| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,349 @@ | |||
| 1 | + # 一、 Nacos服务注册源码解析 | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + * * * | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + ## 1.1 源码方式打包 | ||
| 10 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + * * * | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + | ||
| 17 | + 客户端源码中增加打包方式,将源码打入包中 | ||
| 18 | + | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + ```<plugin> <groupId>org.apache.maven.plugins</groupId> maven-source-plugin <version>3.2.1</version> <configuration> true </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> ``` | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + | ||
| 29 | + | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + | ||
| 33 | + 然后打包: | ||
| 34 | + | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + | ||
| 38 | + | ||
| 39 | + | ||
| 40 | + | ||
| 41 | + ```mvn install -DskipTests ``` | ||
| 42 | + | ||
| 43 | + | ||
| 44 | + | ||
| 45 | + | ||
| 46 | + | ||
| 47 | + | ||
| 48 | + | ||
| 49 | + ## 1.2 入口 | ||
| 50 | + | ||
| 51 | + | ||
| 52 | + | ||
| 53 | + * * * | ||
| 54 | + | ||
| 55 | + | ||
| 56 | + | ||
| 57 | + [github.com/alibaba/nac…](https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Falibaba%2Fnacos%2Ftree%2F1.4.1) | ||
| 58 | + | ||
| 59 | + 首先我们会把源码下载下来,我们会通过源码的方式进行启动, 你可以通过debug的方式进行运行来判断他的运行过程。 | ||
| 60 | + | ||
| 61 | + 我们从源码的角度来分析一下:服务启动后他会上报到注册中心: | ||
| 62 | + | ||
| 63 | + NacosNamingService 就是服务注册和发现相关的类,他就是在这里将当前启动的服务调用注册实例的方法,我们看一下这个方法干什么了? | ||
| 64 | + | ||
| 65 | +  | ||
| 66 | + | ||
| 67 | +  | ||
| 68 | + | ||
| 69 | + 他就是拼接了一些参数发送http请求,到达服务注册中心进行发现,请求的就是这个路径: | ||
| 70 | + | ||
| 71 | +  | ||
| 72 | + | ||
| 73 | + 好这就是对应的路径,我们回到官方文档的指南当中 | ||
| 74 | + | ||
| 75 | + [nacos.io/zh-cn/docs/…](https://link.juejin.cn?target=https%3A%2F%2Fnacos.io%2Fzh-cn%2Fdocs%2Fopen-api.html) | ||
| 76 | + | ||
| 77 | +  | ||
| 78 | + | ||
| 79 | + 好,按照我们讲到这里就不用再往里面看了,我们可以点进去看一下, | ||
| 80 | + | ||
| 81 | +  | ||
| 82 | + | ||
| 83 | + 他真正的调用给你是在这里。 | ||
| 84 | + | ||
| 85 | +  | ||
| 86 | + | ||
| 87 | +  | ||
| 88 | + | ||
| 89 | +  | ||
| 90 | + | ||
| 91 | +  | ||
| 92 | + | ||
| 93 | + 在这里进行调用 | ||
| 94 | + | ||
| 95 | +  | ||
| 96 | + | ||
| 97 | + 好哪有同学问你怎么知道断点就达到这里,那我们看一下怎样查看源码的启动的路径,我们看一下我们订单微服务的路径,我们要集成nacos的服务发现功能,我们要引入我们的discovery的包,他是一个starter,前面我们学过springboot我们知道任何starter里面一定有个spring.factories,作为一个入口 | ||
| 98 | + | ||
| 99 | +  | ||
| 100 | + | ||
| 101 | + 这里面动态加载的类很多,NacosServiceRegistryAutoConfiguration 从这名字我们能发现他是一个nacos服务注册的自动配置类, | ||
| 102 | + | ||
| 103 | +  | ||
| 104 | + | ||
| 105 | + 这里面实现了三个类,我们看一下这个类NacosAUtoServiceRegistration | ||
| 106 | + | ||
| 107 | +  | ||
| 108 | + | ||
| 109 | + 自动注册类,我们可以看一下他的集成关系,是一个ApplicationListener spring启动完成后都会发送一个消息,applicaitonListener就是通过监听这个消息然后进行执行的。所以我们知道下一步我们应该怎么看: | ||
| 110 | + | ||
| 111 | +  | ||
| 112 | + | ||
| 113 | + 所以查看他的抽象类。 | ||
| 114 | + | ||
| 115 | +  | ||
| 116 | + | ||
| 117 | + 查看onApplicationEvent方法:这样在服务发送完就会发送这样一个消息,收到这个消息就会调用这个bind方法 | ||
| 118 | + | ||
| 119 | +  | ||
| 120 | + | ||
| 121 | + 这里有个if return 我们就直接跳过,这一定是分支代码,像这样的分支代码我们就不要看,第一 次要看主线,所以我们直接看这里的start方法,如果后面这里没有对应的代码逻辑我们可以进入这个分支来看。 好,像这样start, begin,init,register方法都是很重要的方法,我们一定要进去看 | ||
| 122 | + | ||
| 123 | +  | ||
| 124 | + | ||
| 125 | + 第一个if就不用看,第二个if需要看,因为后面就没有逻辑了你看这个register(),应该就是这个方法,因为你就是查看注册的流程。 | ||
| 126 | + | ||
| 127 | +  | ||
| 128 | + | ||
| 129 | +  | ||
| 130 | + | ||
| 131 | +  | ||
| 132 | + | ||
| 133 | +  | ||
| 134 | + | ||
| 135 | + 这里需要你知道SpringBoot自动装配的基本知识,其次要知道Spring启动发现的 基本知识。 | ||
| 136 | + | ||
| 137 | + ## 1.3 服务注册 | ||
| 138 | + | ||
| 139 | + | ||
| 140 | + | ||
| 141 | + * * * | ||
| 142 | + | ||
| 143 | + | ||
| 144 | + | ||
| 145 | + Nacos高并发支撑异步任务与内存队列剖析 | ||
| 146 | + | ||
| 147 | + 刚才是在服务提供者上面讲的内容,现在我们服务注册中心来看一下 | ||
| 148 | + | ||
| 149 | + 请求的是instance实例:这就是一个springmvc的controller,所有我们可以全文搜索 Controller,我们是instance实例吧,所以我们这里InstanceController | ||
| 150 | + | ||
| 151 | +  | ||
| 152 | + | ||
| 153 | + 那之前我们用的是post请求所以我们查看post方法,这里有delete,update...,他这里是什么风格? restFul | ||
| 154 | + | ||
| 155 | + 我们发现里面没有对应的DefaultGroup,在服务注册和发现的情况下这个group是不经常用的。你用的话只是自己的规范和方便管理的。在服务注册和发现中源码中都没有用。,命名空间,服务名,然后将我们参数转化为实例。这就我们服务模型中的三层模型。 | ||
| 156 | + | ||
| 157 | +  | ||
| 158 | + | ||
| 159 | + 那我们看一下他的注册实例里面做了什么? 这里面我们注意我们是注册instance,我们就围绕着他,进行分析,是不是就来到addInstance了 | ||
| 160 | + | ||
| 161 | +  | ||
| 162 | + | ||
| 163 | + createEmptyService | ||
| 164 | + | ||
| 165 | +  | ||
| 166 | + | ||
| 167 | + 1、获取service 初次获取一定为空,我们可以进去分析一下 | ||
| 168 | + | ||
| 169 | +  | ||
| 170 | + | ||
| 171 | +  | ||
| 172 | + | ||
| 173 | + 这里就是注册表,我们前面说过nacos服务领域模型【可以参考图】,这个map就是对应的注册表 | ||
| 174 | + | ||
| 175 | +  | ||
| 176 | + | ||
| 177 | + 这里面设置服务和初始化 | ||
| 178 | + | ||
| 179 | +  | ||
| 180 | + | ||
| 181 | +  | ||
| 182 | + | ||
| 183 | + 服务初始化:心跳 | ||
| 184 | + | ||
| 185 | +  | ||
| 186 | + | ||
| 187 | + 看这里是个scheduleNamingHealth是一个定时任务,我们只需要看一下task任务就可以 | ||
| 188 | + | ||
| 189 | +  | ||
| 190 | + | ||
| 191 | + task任务我们需要看一下run方法: | ||
| 192 | + | ||
| 193 | + 在这里我们看是获取所有的实例【可以点进去看一下】 | ||
| 194 | + | ||
| 195 | + 当前时间 - 上次心跳时间 间隔超过15秒 则将实例设置为非健康, 当超过30秒没有收到心跳就直接剔除 | ||
| 196 | + | ||
| 197 | +  | ||
| 198 | + | ||
| 199 | +  | ||
| 200 | + | ||
| 201 | + 好,我们回来,这里名字起的特别好,createEmtyService,是创建一个空服务,后面我们的实例,是不是还会注册到里面, | ||
| 202 | + | ||
| 203 | +  | ||
| 204 | + | ||
| 205 | + > 我们可以看一下服务模型,和我们以前说过的一样 | ||
| 206 | + > | ||
| 207 | + > 命名空间 ,cluster 集群概念 | ||
| 208 | + > | ||
| 209 | + >  | ||
| 210 | + > | ||
| 211 | + >  | ||
| 212 | + > | ||
| 213 | + > 集群中对应的实例。 | ||
| 214 | + > | ||
| 215 | + >  | ||
| 216 | + | ||
| 217 | + 我们看一下addinstance | ||
| 218 | + | ||
| 219 | +  | ||
| 220 | + | ||
| 221 | + 构建对应的key: | ||
| 222 | + | ||
| 223 | + | ||
| 224 | + | ||
| 225 | + | ||
| 226 | + | ||
| 227 | + | ||
| 228 | + | ||
| 229 | + ```String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral); ``` | ||
| 230 | + | ||
| 231 | + | ||
| 232 | + | ||
| 233 | + | ||
| 234 | + | ||
| 235 | + | ||
| 236 | + | ||
| 237 | +  | ||
| 238 | + | ||
| 239 | + | ||
| 240 | + | ||
| 241 | + | ||
| 242 | + | ||
| 243 | + | ||
| 244 | + | ||
| 245 | + ```//获取注册实例的IP端口列表 List<Instance> instanceList = addIpAddresses(service, ephemeral, ips); ``` | ||
| 246 | + | ||
| 247 | + | ||
| 248 | + | ||
| 249 | + | ||
| 250 | + | ||
| 251 | + | ||
| 252 | + | ||
| 253 | + 我们进入简单的看一下,我们发现这个add,remove,这里就是新增和移除实例 | ||
| 254 | + | ||
| 255 | +  | ||
| 256 | + | ||
| 257 | + 我们主要出里这写注册进来的ips,那我们就点击ips,高亮来显示看看,然后他会进行循环instance,这里我们可以看到如果他是移除就从map里面移除出去,如果是新增就在instanceMap中新增一下,最后将期返回。 | ||
| 258 | + | ||
| 259 | +  | ||
| 260 | + | ||
| 261 | +  | ||
| 262 | + | ||
| 263 | +  | ||
| 264 | + | ||
| 265 | +  | ||
| 266 | + | ||
| 267 | + 现类,我们可以猜测一下,或者debug进去,当然这个类,我们点击一下,在声明的地方 | ||
| 268 | + | ||
| 269 | +  | ||
| 270 | + | ||
| 271 | + 它指定了名称: | ||
| 272 | + | ||
| 273 | +  | ||
| 274 | + | ||
| 275 | + 好,我们全文搜索看一下: | ||
| 276 | + | ||
| 277 | +  | ||
| 278 | + | ||
| 279 | +  | ||
| 280 | + | ||
| 281 | + 我们知道前面说过ephemeral是true所以选择第一个: 有疑问: | ||
| 282 | + | ||
| 283 | +  | ||
| 284 | + | ||
| 285 | + 我们应该调用EphemeralConsistencyService对应的put方法。但是EphemeralConsistencyService只是一个接口,我们应该调用对应的实现实例。 | ||
| 286 | + | ||
| 287 | +  | ||
| 288 | + | ||
| 289 | +  | ||
| 290 | + | ||
| 291 | + 我们看一下他的onput方法。 | ||
| 292 | + | ||
| 293 | + 现在放到队列中: | ||
| 294 | + | ||
| 295 | +  | ||
| 296 | + | ||
| 297 | + 这里面就是把核心的请求放到blockquene里面,也就是一个阻塞队列中 | ||
| 298 | + | ||
| 299 | +  | ||
| 300 | + | ||
| 301 | +  | ||
| 302 | + | ||
| 303 | + 整个注册的过程就这么简单,一个请求过来,最终将服务注册的请求,放到我们的阻塞队列当中,放到则色队列之后,整个阻塞队列就返回了。那放到阻塞队列之后,哪里有访问这个阻塞队列。 | ||
| 304 | + | ||
| 305 | + 大家注意这个Notifier是一个线程,老师交大家一个技巧:如果遇到一个线程就需要看他的run方法因为run方法才是他 真正执行代码的地方。 | ||
| 306 | + | ||
| 307 | +  | ||
| 308 | + | ||
| 309 | + 在这里进行死循环进行数据处理,不断的处理客户端注册的信息,丢进来就实现后面的异步注册信息, | ||
| 310 | + | ||
| 311 | + 这个线程会一直在转,一直运行,如果他挂了那说明整个服务就挂掉了,好,你看着里面的异常也吃掉了,所以一直会运行,如果没有数据他会阻塞,阻塞会让出cpu | ||
| 312 | + | ||
| 313 | +  | ||
| 314 | + | ||
| 315 | + 注册表结构的分析: | ||
| 316 | + | ||
| 317 | +  | ||
| 318 | + | ||
| 319 | + 首先当他是个change的时候,我们就进入onChange,他是个服务所以我们进入他的service里面去看: | ||
| 320 | + | ||
| 321 | +  | ||
| 322 | + | ||
| 323 | + 这里面就不用看了,先看权重,权重大于多少的时候设置最大值,权重小于多少的时候设置一个最小值。然后就是核心的方法updateIP | ||
| 324 | + | ||
| 325 | +  | ||
| 326 | + | ||
| 327 | + 那这个updateIPs是做什么呢? 做的就是我遍历我所有要注册的实例,然后就放到我们的clusterMap里面 | ||
| 328 | + | ||
| 329 | +  | ||
| 330 | + | ||
| 331 | +  | ||
| 332 | + | ||
| 333 | + 那到这里大家可能就有疑问了,那什么时候启动这个线程,来实时监听我们消息的阻塞队列呢? 教大家如何找一下这个方法,我们现在看着个类叫Notifier,因为他本身就是一个线程,他会丢到一个线程池中进行运行,我们看一下他究竟是在哪里实例化的, | ||
| 334 | + | ||
| 335 | +  | ||
| 336 | + | ||
| 337 | + 我们看到这个方法:这个注解就是当你的spring的一个类进行初始化之后进行调用的,那我们看一下这个init方法到底是做了什么 | ||
| 338 | + | ||
| 339 | +  | ||
| 340 | + | ||
| 341 | +  | ||
| 342 | + | ||
| 343 | + 是一个Scheduled线程池: | ||
| 344 | + | ||
| 345 | +  | ||
| 346 | + | ||
| 347 | + 也就是在对象初始化的时候就进行启动一个线程池,去运行notifier对应的方法。这个run方法就是这样run的。启动后就会实时监听异步队列。这样写的好处,就是将写和处理完全隔离了。通过监听高性能的内存队列,来处理这个事情,他这样的好处,1、提高性能 | ||
| 348 | + | ||
| 349 | +  | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments