SpringCloud-Eureka底层源码分析

*设计思想:

*执行流程:

Registry 名词 登记处、挂号处

Registration 名词 登记、注册、挂号

EurekaServiceRegistry 这个类顾名思义就是服务注册的地方,登记处,这个类实现了ServiceRegistry<EurekaRegistration>接口,其中的泛型EurekaRegistration顾名思义就是一次eureka注册,也是一个名词对象。EurekaServiceRegistry负责将EurekaRegistration注册到注册中心

1. 客户端服务注册流程

1.1 启动时注册

容器在实例化CloudEurekaClient时,父类的构造函数会执行第一次注册,不做配置的话默认是不会进行注册的。

1
2
3
4
5
6
7
8
9
10
11
12
// DiscoveryClient 
// registration.enabled=true(默认是true) && shouldEnforceRegistrationAtInit=true(默认是false)时,会进行一次注册
if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
try {
if (!register() ) {
throw new IllegalStateException("Registration error at startup. Invalid server response.");
}
} catch (Throwable th) {
logger.error("Registration error at startup: {}", th.getMessage());
throw new IllegalStateException(th);
}
}

查看更多

kafka-消息的存储

一个topic的多个partition在物理磁盘上的保存路径,路径保存在 /tmp/kafka-logs/topic_partition,包 含日志文件、索引文件和时间索引文件

kafka是通过分段的方式将Log分为多个LogSegment,LogSegment是一个逻辑上的概念,一个 LogSegment对应磁盘上的一个日志文件和一个索引文件,其中日志文件是用来记录消息的。索引文件是用来保存消息的索引。那么这个LogSegment是什么呢?

LogSegment

假设kafka以partition为最小存储单位,那么我们可以想象当kafka producer不断发送消息,必然会引起partition文件的无线扩张,这样对于消息文件的维护以及被消费的消息的清理带来非常大的挑战,所以kafka以segment为单位又把partition进行细分。每个partition相当于一个巨型文件被平均分配到多个大小相等的segment数据文件中(每个segment文件中的消息不一定相等),这种特性方便已经被消费的消息的清理,提高磁盘的利用率。

log.segment.bytes=107370 (设置分段大小),默认是1gb,我们把这个值调小以后,可以看到日志分段的效果

抽取其中3个分段来进行分析

查看更多

kafka-提交offset存储

每个topic可以划分多个分区partition,同一个topic下的不同分区存储的消息是不重复的。在每个消息被分配给一个分区时,会生成一个偏移量offset,它是消息在分区中的唯一编号。kafka通过offset来保证消息在分区内的顺序,分区之间不能保证消息的顺序性。

消费者可以通过以下配置来开启自动提交:

1
2
3
4
props.put(ConsumerConfig.GROUP_ID_CONFIG, "group_2");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); // 开启自动提交
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000"); //自动提交时间间隔
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest"); //消费者启动时从哪里开始消费

对于消费者来说,每次消费一个消息并且提交以后,kafka会保存当前消费到的最后的一个offset,那么offset保存在哪里?

在kafka中提供了一个名为__consumer_offsets-*的topic,默认有50个分区。消费者消费数据并提交之后,offset将存储到该topic的某个分区中。

查看更多

SpringCloud-Ribbon实现源码分析

客户端的负载均衡解决的问题:从配置文件或注册中心获取需要调用的服务列表,使用指定的算法选择一个服务实例,发送调用请求。

流程总结:

  • RestTemplate.getObject方法开始流程,执行到doExcute()方法中,该方法创建一个Http请求发送请求
  • 创建http请求是一个InterceptingClientHttpRequest对象,表示这是一个正在被拦截的客户端http请求,ribbon负载均衡就是基于拦截器实现的
  • InterceptingClientHttpRequest有方法excute(),此方法对请求执行拦截处理,最后发送出去。
查看更多

kafka-副本机制

kafka虽然可以对topic进行分片,但是对于partition来说,它还是单点的,当partition所在的broker宕机了,那么这部分消息就无法被消费。所以kafka为了提高partition的可靠性,提供了副本replica的概念,通过副本机制来实现冗余备份。

每个分区可以有多个副本,并且在副本集合中会存在一个learder副本,所有的读写请求都是由leader来处理。其余的副本称为follower副本,follower会主动从leader同步消息日志。一般情况下,同一个分区的多个副本会被均匀的分配到集群的不同broker上,当leader所在的broker出现故障,可以重新选举新的leader副本继续向外提供服务。

通过下面的命令创建一个带副本的topic

1
sh kafka-topic.sh --create --zookeeper 192.168.2.112:9092 --replication-factor 3 --partition 3 --topic test_topic

如何知道各个分区中对应的leader是谁呢?

在zookeeper服务器上,通过如下命令去获取对应分区的信息,比如下面这个是获取Topic第1个分区的状态信息。

查看更多