Eureka源码探索(一)-客户端服务端的启动和负载均衡
程序员文章站
2022-04-28 15:46:01
1. Eureka源码探索(一) 客户端服务端的启动和负载均衡 1.1. 服务端 1.1.1. 找起始点 1. 目前唯一知道的,就是启动Eureka服务需要添加注解 ,但是暂时找不到它被使用的地方 2. 看日志,明显有打印discovery client,服务端同时也用作客户端,因为它可以相互注册, ......
1. eureka源码探索(一)-客户端服务端的启动和负载均衡
1.1. 服务端
1.1.1. 找起始点
- 目前唯一知道的,就是启动eureka服务需要添加注解
@enableeurekaserver
,但是暂时找不到它被使用的地方 - 看日志,明显有打印discovery client,服务端同时也用作客户端,因为它可以相互注册,以下是自动配置类
- 知道了客户端有自动配置类,可以想象服务端也应该有,找到相应的包,发现果然有
1.1.2. 服务初始化
- 启动初始化
- 接下来是个发布订阅方法,发布对象继承了spring的
applicationevent
,可以看出肯定会有订阅者接收该配置,配置内容就是我们application.properties里配置的属性,不配则是默认属性
1.1.3. @enableeurekaserver
起作用的原理
- 进入该注解,可以看到注解中还有个注解
@import
它的作用就是将之后的类对象所对应的实例,实例化并加入spring容器管理
@target(elementtype.type) @retention(retentionpolicy.runtime) @documented @import(eurekaservermarkerconfiguration.class) public @interface enableeurekaserver { }
- 进入
eurekaservermarkerconfiguration
类,可以看到如下,该类的作用仅仅用来标记下,为启动类判断是否需要启动eurekaserver
@configuration public class eurekaservermarkerconfiguration { @bean public marker eurekaservermarkerbean() { return new marker(); } class marker { } }
- 它具体被使用的地方如下,用一个
@conditionalonbean
表示,若存在该类bean,则启动配置生效
1.2. 客户端
1.2.1. 调用解析过程
- resttemplate调用
resttemplate.getforentity("http://eureka-server", string.class);
- 在不断深入后,最终处理的是一个拦截器
- 拦截器进的实际处理类是
loadbalancerinterceptor
- 但里面实际的负载均衡调用
loadbalancer
又是ribbonloadbalancerclient
- 这就真真的进了ribbon的负载均衡调用了,至于这个
ribbonloadbalancerclient
怎么注入进来的,这也简单,这里有两层关系,该loadbalancerinterceptor
如何实例化的,和ribbonloadbalancerclient
如何实例化并注入的,可以看如下图
- 好了,不扯开去了,继续解析服务名,实际上,接下来就是
ribbonloadbalancerclient
的实现了
- 继续深入
- 轮询核心算法
1.3. 模拟负载均衡调用
1.3.1. 代码直接上
@springbootapplication @enablediscoveryclient @restcontroller @slf4j public class eurekaclientapplication { public static void main(string[] args) { springapplication.run(eurekaclientapplication.class, args); } @autowired private resttemplate resttemplate; @autowired private discoveryclient discoveryclient; /** * 使用ribbon的负载均衡 * @return */ @getmapping("/") public responseentity<string> gettime(){ return resttemplate.getforentity("http://eureka-server", string.class); } /** * 模拟轮询负载的调用 * @return */ @getmapping("/discovery") public responseentity<string> discovery(){ list<serviceinstance> instances = discoveryclient.getinstances("eureka-server"); int i = incrementandgetmodule(instances.size()); return resttemplate.getforentity(((eurekadiscoveryclient.eurekaserviceinstance) instances.get(i)).getinstanceinfo().gethomepageurl(), string.class); } private atomicinteger nextindex = new atomicinteger(); private int incrementandgetmodule(int module) { for (; ; ) { int current = nextindex.get(); int next = (current + 1) % module; if (nextindex.compareandset(current,next) && current < module) { return current; } } } /** * 加上@loadbalanced该注解使用的ribbon的负载均衡算法 */ @bean @loadbalanced public resttemplate resttemplate(){ return new resttemplate(); } }
- 这里用了ribbon的负载均衡轮询算法和直接调用
discoveryclient
实现最简单的模拟轮询算法 - 注意,测试discovery的时候可以需要把
@loadbalanced
注掉
上一篇: Python虚拟环境
下一篇: 分布式架构原理解析,Java开发必修课