简栈

拥抱AI,持续成长

Eureka 工作原理

Eureka 作为 Spring Cloud 体系中最核心、默认的注册中心组件,研究它的运行机制,有助于我们在工作中更好地使用它。

Eureka 核心概念

回到上节的服务注册调用示意图,服务提供者和服务的消费者,本质上也是 Eureka Client 角色。整体上可以分为两个主体:Eureka ServerEureka Client
http://static.cyblogs.com/20190703102014756.png

Eureka Server:注册中心服务端

注册中心服务端主要对外提供了三个功能:

服务注册
服务提供者启动时,会通过 Eureka ClientEureka Server 注册信息,Eureka Server 会存储该服务的信息,Eureka Server 内部有二层缓存机制来维护整个注册表

提供注册表
服务消费者在调用服务时,如果 Eureka Client 没有缓存注册表的话,会从 Eureka Server 获取最新的注册表

同步状态
Eureka Client 通过注册、心跳机制和 Eureka Server 同步当前客户端的状态。

Eureka Client:注册中心客户端
Eureka Client 是一个 Java 客户端,用于简化与 Eureka Server 的交互。Eureka Client 会拉取、更新和缓存 Eureka Server 中的信息。因此当所有的 Eureka Server 节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者,但是当服务有更改的时候会出现信息不一致。

阅读全文 »

深度阅读的能力

我敢保证,看完这个回答之前,就有很多人会划走。

这绝逼不是因为我这个回答写的太无趣,或者他们不同意我的某些观点,而是因为——他们看什么东西都是这样。

他们根本不能沉浸式的阅读什么东西,一般超过几百字的内容就很少看了,除非是小黄文和超能力爽文。他们做的最多的是浮皮潦草的刷刷抖音、看看段子,稍微有点复杂的电影都看不下去,更何况那些晦涩枯燥的工具书了。

我不能说知乎用户就比抖音用户牛逼,但是经过我这些年的学习和生活,我发现能够全神贯注的阅读长篇文字,本身就是很强的一种能力,它能够轻而易举的影响到我们的学习效果和工作效果,它关乎到我们的注意力、记忆力、逻辑思维能力和理解能力。

你信也好,你不信也罢,越看书就会越聪明,一直看爽文、肥皂剧、抖音就会变得不善思考。

自我认知能力

不要觉得这个能力很菜,真没几个人有。

不服你可以冷静下来想想,你真的了解你自己么?你真的知道你自己在这个社会中处于怎样的一个阶层和水平么?如果你觉得你都了解,那我再问你一句,你的这些认知,都来源于哪里?

其实你对自己的评价往往都来源于他人对你的反馈,所以人其实是很容易被环境和他人的评价所左右的,不要觉得你不可能进入传销,当你周围的环境和人全都变了,你得到的反馈就完全乱了,你自己就会失去对自己的认知。

阅读全文 »

http 是无状态的,一次请求结束,连接断开,下次服务器再收到请求,它就不知道这个请求是哪个用户发过来的。当然它知道是哪个客户端地址发过来的,但是对于我们的应用来说,我们是靠用户来管理,而不是靠客户端。所以对我们的应用而言,它是需要有状态管理的,以便服务端能够准确的知道 http 请求是哪个用户发起的,从而判断他是否有权限继续这个请求。这个过程就是常说的会话管理。它也可以简单理解为一个用户从登录到退出应用的一段期间。本文总结了 3 种常见的实现 web 应用会话管理的方式:

1)基于 serversession 的管理方式

2)cookie-base 的管理方式

3)token-base 的管理方式

这些内容可以帮助加深对 web 中用户登录机制的理解,对实际项目开发也有参考价值,欢迎阅读与指正。

1. 基于 server 端 session 的管理

在早期 web 应用中,通常使用服务端 session 来管理用户的会话。快速了解服务端 session:

  1. 服务端 session 是用户第一次访问应用时,服务器就会创建的对象,代表用户的一次会话过程,可以用来存放数据。服务器为每一个 session 都分配一个唯一的 sessionid,以保证每个用户都有一个不同的 session 对象。

2)服务器在创建完 session 后,会把 sessionid 通过 cookie 返回给用户所在的浏览器,这样当用户第二次及以后向服务器发送请求的时候,就会通过 cookiesessionid 传回给服务器,以便服务器能够根据 sessionid 找到与该用户对应的 session 对象。

3)session 通常有失效时间的设定,比如 2 个小时。当失效时间到,服务器会销毁之前的 session,并创建新的 session 返回给用户。但是只要用户在失效时间内,有发送新的请求给服务器,通常服务器都会把他对应的 session 的失效时间根据当前的请求时间再延长 2 个小时。

阅读全文 »

前言

循环依赖:就是N个类循环(嵌套)引用。 通俗的讲就是N个Bean互相引用对方,最终形成闭环。用一副经典的图示可以表示成这样(A、B、C都代表对象,虚线代表引用关系):

http://static.cyblogs.com/mxuio3xfqc.png

注意:其实可以N=1,也就是极限情况的循环依赖:自己依赖自己

另需注意:这里指的循环引用不是方法之间的循环调用,而是对象的相互依赖关系。(方法之间循环调用若有出口也是能够正常work的)

可以设想一下这个场景:如果在日常开发中我们用new对象的方式,若构造函数之间发生这种循环依赖的话,程序会在运行时一直循环调用最终导致内存溢出,示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Main {

public static void main(String[] args) throws Exception {
System.out.println(new A());
}

}

class A {
public A() {
new B();
}
}

class B {
public B() {
new A();
}
}

运行报错:

1
Exception in thread "main" java.lang.StackOverflowError

这是一个典型的循环依赖问题。本文说一下Spring是如果巧妙的解决平时我们会遇到的三大循环依赖问题的~

Spring Bean的循环依赖

阅读全文 »

JDK.1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:

  • 强引用(Strong Reference)
  • 软引用(Soft Reference)
  • 弱引用(Weak Reference)
  • 虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。不同的引用在垃圾回收中体现也是不一样~

M

我们先创建一个M对象,后面为了方便的感受GC的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.cyblogs.java.learning.C001_ReferenceType;

/**
* Created with java-learning-demo
*
* @description:
* @author: chenyuan
* @date: 2020/6/16
* @time: 9:30 PM
*/
public class M {

@Override
public void finalize() {
System.out.println("finalize");
}

}

finalize函数是对象在gc的时候,一定会调用该方法。我们重写一下该方法并且打印一行日志。

强引用

只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也会直接抛出OutOfMemoryError,不会去回收。如果想中断强引用与对象之间的联系,可以显示的将强引用赋值为null,这样一来,JVM就可以适时的回收对象了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.cyblogs.java.learning.C001_ReferenceType;

import java.io.IOException;

/**
* Created with java-learning-demo
*
* @description: 正常引用/强引用
* @author: chenyuan
* @date: 2020/6/16
* @time: 9:31 PM
*/
public class C001_01_NormalReference {

public static void main(String[] args) throws IOException {
M m = new M();
// 将对象复制为空
m = null;
// 手动触发GC
System.gc();
// 因为不是触发gc就一定会立马gc,所以让线程阻塞一下
System.in.read();
}
}

控制台日志输出:

阅读全文 »

俗话说,站在巨人的肩膀上看世界,一般学习的时候也是先总览一下整体,然后逐个部分个个击破,最后形成思路,了解具体细节,Tomcat的结构很复杂,但是 Tomcat 非常的模块化,找到了 Tomcat最核心的模块,问题才可以游刃而解,了解了Tomcat的整体架构对以后深入了解Tomcat来说至关重要!

一、Tomcat顶层架构

先上一张Tomcat的顶层结构图(图A),如下:

http://static.cyblogs.com/5j8j72c1yz.jpg

Tomcat中最顶层的容器是Server,代表着整个服务器,从上图中可以看出,一个Server可以包含至少一个Service,用于具体提供服务。

Service主要包含两个部分:ConnectorContainer。从上图中可以看出 Tomcat 的心脏就是这两个组件,他们的作用如下:

1、Connector用于处理连接相关的事情,并提供SocketRequestResponse相关的转化;

2、Container用于封装和管理Servlet,以及具体处理Request请求;

一个Tomcat中只有一个Server,一个Server可以包含多个Service,一个Service只有一个Container,但是可以有多个Connectors,这是因为一个服务可以有多个连接,如同时提供HttpHttps链接,也可以提供向相同协议不同端口的连接,示意图如下(EngineHostContext下边会说到):

img

阅读全文 »

什么是布隆过滤器

本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”

相比于传统的 ListSetMap 等数据结构,它更高效、占用空间更少,但是缺点是其返回的结果是概率性的,而不是确切的。

实现原理

HashMap 的问题

讲述布隆过滤器的原理之前,我们先思考一下,通常你判断某个元素是否存在用的是什么?应该蛮多人回答 HashMap 吧,确实可以将值映射到 HashMapKey,然后可以在 O(1) 的时间复杂度内返回结果,效率奇高。但是 HashMap 的实现也有缺点,例如存储容量占比高,考虑到负载因子的存在,通常空间是不能被用满的,而一旦你的值很多例如上亿的时候,那 HashMap 占据的内存大小就变得很可观了。

还比如说你的数据集存储在远程服务器上,本地服务接受输入,而数据集非常大不可能一次性读进内存构建 HashMap 的时候,也会存在问题。

布隆过滤器数据结构

布隆过滤器是一个 bit 向量或者说 bit 数组,长这样:

http://static.cyblogs.com/QQ20200618-210117@2x.jpg

阅读全文 »

当你看到这个标题的时候,以为我是一个标题党?(其实也是…)

但是你真的不能小瞧这个单例模式,不信的话,你可以继续往下看。

小白些单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Created with vernon-test
*
* @description: 设计模式-单例模式
* @author: chenyuan
* @date: 2020/6/7
* @time: 9:25 PM
*/
public class Singleton {

private static Singleton instance = null;

private Singleton() {
}

public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
System.out.println("我开始new对象了~");
}
return instance;
}
}

这种单例估计是我们第一眼就能想到的,咋一眼看没问题,因为我们的大脑一眼反应我们的程序都是单线程的。实际上我们系统在初始化的时候就有可能存在多线程的情况。我们模拟并发写一个小程序来验证下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Created with vernon-test
*
* @description: 测试类
* @author: chenyuan
* @date: 2020/6/7
* @time: 9:27 PM
*/
public class TestCase {

public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Singleton instance = Singleton.getInstance();
System.out.println(instance);
}
});
thread.start();
}
}
}

看一眼运行的结果:

1
2
3
4
5
6
7
8
9
10
11
12
我开始new对象了~
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@a963d08
我开始new对象了~
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a
com.vernon.test.designpattern.singleton.Singleton@773d663a

很明显,new了2次对象,看打印的对象地址也是不对的。

那我们如何去改进呢?– 加锁

阅读全文 »

为什么用分布式锁?在讨论这个问题之前,我们先来看一个业务场景。

为什么用分布式锁?

系统 A 是一个电商系统,目前是一台机器部署,系统中有一个用户下订单的接口,但是用户下订单之前一定要去检查一下库存,确保库存足够了才会给用户下单。

由于系统有一定的并发,所以会预先将商品的库存保存在 Redis 中,用户下单的时候会更新 Redis 的库存。

此时系统架构如下:

img

但是这样一来会产生一个问题:假如某个时刻,Redis 里面的某个商品库存为 1。

此时两个请求同时到来,其中一个请求执行到上图的第 3 步,更新数据库的库存为 0,但是第 4 步还没有执行。

而另外一个请求执行到了第 2 步,发现库存还是 1,就继续执行第 3 步。这样的结果,是导致卖出了 2 个商品,然而其实库存只有 1 个。

很明显不对啊!这就是典型的库存超卖问题。此时,我们很容易想到解决方案:用锁把 2、3、4 步锁住,让他们执行完之后,另一个线程才能进来执行第 2 步。

阅读全文 »

增量同步

rsync [args] SRC [DEST]
情形:同时维护着两份不同的data_center,但以old_data_center为标准。因为权限的缘故没有开启rsync自动同步,只是每隔一段时间手动同步一下。SRCDEST都是采用mount形式,如果每一次都完整地copy,耗时很长,这时候就想到采用增量同步的方法,因为两份data_center同时由不同人维护,所以内容略有不同,data_center同步的时候不光要完全同步old_data_center的所有内容,而且要删除自身多余的内容,保持完全一致。

http://static.cyblogs.com/1559267-20190509170938551-832776092.png

1
2
3
rsync -a 
--delete
--progress /old_vip_data_center/test_envs/trainer/resource /vip_data_center/test_envs/trainer/resource/

–delete: 删除DEST端存在但是SRC端不存在的文件,如果不使用此参数,则DEST端会同步SRC端的文件,但DEST端已有的文件不受影响。

快速删除大量文件

  1. 先建一个空目录,随便位置

    1
    mkdir /local/empty_dir
  2. 用rsync删除目标目录

    1
    rsync --delete-before -avH --progress /local/empty_dir/ /local/trainer_test/

trainer_test清空之后可以再用rm -rf trainer_test删除

注意不要忘了文件夹最后的/

rsync提供了一些跟删除相关的参数

阅读全文 »
0%