更详细的阐述:https://www.yuque.com/jixiangkuaile/kk8w4w/tka8zh#VocfX

服务注册中心一般原理

分布式微服务架构中,服务注册中心用于存储服务提供者地址信息、服务发布相关的属性信息,消费者通过主动查询和被动通知的方式获取服务提供者的地址信息,而不再需要通过硬编码方式得到提供者的地址信。消费者只需要知道当前系统发布了那些服务,不需要知道服务具体存在于什么位置,这就是透明化路由。
image.png
1)服务提供者启动
2)服务提供者将相关服务信息主动注册到注册中心
3)服务消费者获取服务注册信息
pull模式:服务消费者可以主动拉取可用的服务提供者清单
push模式:服务消费者订阅服务(当服务提供者有变化时,注册中心也会主动推送更新后的服务清单给消费者
4)服务消费者直接调用服务提供者
5)注册中心也需要完成服务提供者的健康监控,当发现服务提供者失效时需要及时剔除;

主流服务中心对比

Zookeeper 存储+监听通知

Eureka 服务注册与发现组件

Consul 分布式高可用的服务 发布和注册服务软件

Nacos 注册中心 + 配置中心的组合

服务注册中心组件Eureka

image.png

Eureka 交互流程及原理

image.png

Eureka 包含两个组件:Eureka Server 和 Eureka Client,Eureka Client是一个Java客户端,用于简化与Eureka Server的交互;Eureka Server提供服务发现的能力,各个微服务启动时,会通过Eureka Client向Eureka Server 进行注册自己的信息(例如网络信息),Eureka Server会存储该服务的信息;
1)图中us-east-1c、us-east-1d,us-east-1e代表不同的区也就是不同的机房
2)图中每一个Eureka Server都是一个集群。
3)图中Application Service作为服务提供者,向Eureka Server中注册服务,Eureka Server接受到注册事件会在集群和分区中进行数据同步,ApplicationClient作为消费端(服务消费者)可以从Eureka Server中获取到服务注册信息,进行服务调用。
4)微服务启动后,会周期性地向Eureka Server发送心跳(默认周期为30秒)以续约自己的信息
5)Eureka Server在一定时间内没有接收到某个微服务节点的心跳,EurekaServer将会注销该微服务节点(默认90秒)
6)每个Eureka Server同时也是Eureka Client,多个Eureka Server之间通过复制的方式完成服务注册列表的同步
7)Eureka Client会缓存Eureka Server中的信息。即使所有的Eureka Server节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者

注:Eureka通过心跳检测、健康检查和客户端缓存等机制,提高系统的灵活性、可伸缩性和可用性

搭建单例Eureka Server服务注册中心

1、创建一个子项目 lagou-cloud-eureka-server-8761

2、在父的pom中添加Spring Cloud 依赖

  1. <dependencyManagement>
  2. <dependencies>
  3. <!--spring cloud依赖管理,引入了Spring Cloud的版本-->
  4. <dependency>
  5. <groupId>org.springframework.cloud</groupId>
  6. <artifactId>spring-cloud-dependencies</artifactId>
  7. <version>Greenwich.RELEASE</version>
  8. <type>pom</type>
  9. <scope>import</scope>
  10. </dependency>
  11. </dependencies>
  12. </dependencyManagement>

3、子项目8761的pom.xml中引入Eureka server依赖

  1. <!--Eureka server依赖-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
  5. </dependency>

4、在父的pom.xml中引入jaxb

  1. <!--因为Jdk9之后默认没有加载jaxb该模块,EurekaServer使用到,
  2. 所以需要手动导入,否则EurekaServer服务无法启动-->
  3. <!--eureka server 需要引入Jaxb,开始-->
  4. <dependency>
  5. <groupId>com.sun.xml.bind</groupId>
  6. <artifactId>jaxb-core</artifactId>
  7. <version>2.2.11</version>
  8. </dependency>
  9. <dependency>
  10. <groupId>javax.xml.bind</groupId>
  11. <artifactId>jaxb-api</artifactId>
  12. </dependency>
  13. <dependency>
  14. <groupId>com.sun.xml.bind</groupId>
  15. <artifactId>jaxb-impl</artifactId>
  16. <version>2.2.11</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.glassfish.jaxb</groupId>
  20. <artifactId>jaxb-runtime</artifactId>
  21. <version>2.2.10-b140310.1920</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>javax.activation</groupId>
  25. <artifactId>activation</artifactId>
  26. <version>1.1.1</version>
  27. </dependency>
  28. <!--引入Jaxb,结束-->

5、配置 application.yml

  1. #eureka server服务端口
  2. server:
  3. port: 8761
  4. spring:
  5. application:
  6. name: lagou-cloud-eureka-server # 应用名称,应用名称会在Eureka中作为服务名称
  7. # eureka 客户端配置(和Server交互),Eureka Server 其实也是一个Client
  8. eureka:
  9. instance:
  10. hostname: LagouCloudEurekaServerA # 当前eureka实例的主机名
  11. client:
  12. service-url:
  13. # 配置客户端所交互的Eureka Server的地址
  14. #(Eureka Server集群中每一个Server其实相对于其它Server来说都是Client)
  15. # 集群模式下,defaultZone应该指向其它Eureka Server,如果有更多其它Server实例,逗号拼接即可
  16. defaultZone: http://LagouCloudEurekaServerB:8762/eureka
  17. register-with-eureka: false # 单例是false,集群模式下改成true
  18. fetch-registry: false # 集群模式下可以改成true
  19. ##单例模式下自己就是服务不需要从Eureka Server获取服务信息,默认为true,置为false
  20. ##集群模式下,就需要改为true,从集群上获取信息
  21. dashboard:
  22. enabled: true

6、 声明当前项目为EurekaServer服务

  1. SpringBoot启动类上面,使用@EnableEurekaServer声明当前项目为EurekaServer服务
  2. @SpringBootApplication
  3. // 声明本项目是一个Eureka服务
  4. @EnableEurekaServer
  5. public class LagouEurekaServerApp8761 {
  6. public static void main(String[] args) {
  7. SpringApplication.run(LagouEurekaServerApp8761.class,args);
  8. }
  9. 。。。。。。。

7、完整的父项目中的pom.xml添加的配置

  1. <!--父工程打包方式为pom-->
  2. <packaging>pom</packaging>
  3. <!--spring boot 父启动器依赖-->
  4. <parent>
  5. <groupId>org.springframework.boot</groupId>
  6. <artifactId>spring-boot-starter-parent</artifactId>
  7. <version>2.1.6.RELEASE</version>
  8. </parent>
  9. <dependencyManagement>
  10. <dependencies>
  11. <!--spring cloud依赖管理,引入了Spring Cloud的版本-->
  12. <dependency>
  13. <groupId>org.springframework.cloud</groupId>
  14. <artifactId>spring-cloud-dependencies</artifactId>
  15. <version>Greenwich.RELEASE</version>
  16. <type>pom</type>
  17. <scope>import</scope>
  18. </dependency>
  19. </dependencies>
  20. </dependencyManagement>
  21. <dependencies>
  22. <!--web依赖-->
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-web</artifactId>
  26. </dependency>
  27. <!--日志依赖-->
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-logging</artifactId>
  31. </dependency>
  32. <!--测试依赖-->
  33. <dependency>
  34. <groupId>org.springframework.boot</groupId>
  35. <artifactId>spring-boot-starter-test</artifactId>
  36. <scope>test</scope>
  37. </dependency>
  38. <!--lombok工具-->
  39. <dependency>
  40. <groupId>org.projectlombok</groupId>
  41. <artifactId>lombok</artifactId>
  42. <version>1.18.4</version>
  43. <scope>provided</scope>
  44. </dependency>
  45. <!-- Actuator可以帮助你监控和管理Spring Boot应用-->
  46. <dependency>
  47. <groupId>org.springframework.boot</groupId>
  48. <artifactId>spring-boot-starter-actuator</artifactId>
  49. </dependency>
  50. <!--热部署-->
  51. <dependency>
  52. <groupId>org.springframework.boot</groupId>
  53. <artifactId>spring-boot-devtools</artifactId>
  54. <optional>true</optional>
  55. </dependency>
  56. <!--因为Jdk9之后默认没有加载jaxb该模块,EurekaServer使用到,所以需要手动导入,
  57. 否则EurekaServer服务无法启动-->
  58. <!--eureka server 需要引入Jaxb,开始-->
  59. <dependency>
  60. <groupId>com.sun.xml.bind</groupId>
  61. <artifactId>jaxb-core</artifactId>
  62. <version>2.2.11</version>
  63. </dependency>
  64. <dependency>
  65. <groupId>javax.xml.bind</groupId>
  66. <artifactId>jaxb-api</artifactId>
  67. </dependency>
  68. <dependency>
  69. <groupId>com.sun.xml.bind</groupId>
  70. <artifactId>jaxb-impl</artifactId>
  71. <version>2.2.11</version>
  72. </dependency>
  73. <dependency>
  74. <groupId>org.glassfish.jaxb</groupId>
  75. <artifactId>jaxb-runtime</artifactId>
  76. <version>2.2.10-b140310.1920</version>
  77. </dependency>
  78. <dependency>
  79. <groupId>javax.activation</groupId>
  80. <artifactId>activation</artifactId>
  81. <version>1.1.1</version>
  82. </dependency>
  83. <!--引入Jaxb,结束-->
  84. </dependencies>
  85. <build>
  86. <plugins>
  87. <!--编译插件-->
  88. <plugin>
  89. <groupId>org.apache.maven.plugins</groupId>
  90. <artifactId>maven-compiler-plugin</artifactId>
  91. <configuration>
  92. <source>11</source>
  93. <target>11</target>
  94. <encoding>utf-8</encoding>
  95. </configuration>
  96. </plugin>
  97. <!--打包插件-->
  98. <plugin>
  99. <groupId>org.springframework.boot</groupId>
  100. <artifactId>spring-boot-maven-plugin</artifactId>
  101. </plugin>
  102. </plugins>
  103. </build>

搭建Eureka Server HA高可用集群注册中心

image.png

1、修改本机host属性

  1. 127.0.0.1 LagouCloudEurekaServerA
  2. 127.0.0.1 LagouCloudEurekaServerB

2、修改 lagou-cloud-eureka-server 工程中的yml配置文件

  1. 赋值一份***server-8761的版本,改为****-8762
  2. #eureka server服务端口
  3. server:
  4. port: 8762
  5. spring:
  6. application:
  7. name: lagou-cloud-eureka-server # 应用名称,应用名称会在Eureka中作为服务名称
  8. # eureka 客户端配置(和Server交互),Eureka Server 其实也是一个Client
  9. eureka:
  10. instance:
  11. hostname: LagouCloudEurekaServerB # 当前eureka实例的主机名
  12. client:
  13. service-url: # 配置客户端所交互的Eureka Server的地址
  14. #把另外的实例LagouCloudEurekaServerA作为了集群中的镜像节点
  15. defaultZone: http://LagouCloudEurekaServerA:8761/eureka
  16. register-with-eureka: true
  17. fetch-registry: true
  18. -----------------------------------------------------
  19. -----------------------------------------------------
  20. 原来的8761的配置只需要修改为true即可(就可以在集群模式下注册服务)
  21. register-with-eureka: true
  22. fetch-registry: true

image.png

3、启动eureka-server

微服务提供者注册到Eureka Server集群

子项目的名称是lagou-service-resume-8080
注册简历微服务(简历服务部署两个实例,分别占用8080、8081端⼝)

1、创建commons 模块用于添加实体类,并引入当前子项目中

2、父工程中引入spring-cloud-commons依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-commons</artifactId>
  4. </dependency>

3、在当前子项目中引入eureka client的相关坐标

  1. <!--eureka client 客户端依赖引入-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5. </dependency>

4、配置application.yml文件

在application.yml 中添加Eureka Server高可用集群的地址及相关配置

  1. server:
  2. port: 8080
  3. #注册到Eureka服务中心
  4. eureka:
  5. client:
  6. service-url:
  7. # 注册到集群,就把多个Eurekaserver地址使用逗号连接起来即可;注册到单实例(非集群模式),那就写一个就ok
  8. defaultZone: http://LagouCloudEurekaServerA:8761/eureka,http://LagouCloudEurekaServerB:8762/eureka
  9. instance:
  10. prefer-ip-address: true #服务实例中显示ip,而不是显示主机名(兼容老的eureka版本)
  11. # 实例名称: 192.168.1.103:lagou-service-resume:8080,我们可以自定义它
  12. instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
  13. # 自定义Eureka元数据
  14. metadata-map:
  15. cluster: cl1
  16. region: rn1
  17. spring:
  18. application:
  19. name: lagou-service-resume #服务提供者的名称,会出现在eureka注册中心的

经验:自定义实例显示格式,加上版本号,便于多版本管理

5、启动类添加注解

EnableDiscoveryClient的通用性更加强

  1. @SpringBootApplication
  2. @EntityScan("com.lagou.edu.pojo")
  3. //@EnableEurekaClient // 开启Eureka Client(Eureka独有)
  4. @EnableDiscoveryClient // 开启注册中心客户端 (通用型注解,比如注册到Eureka、Nacos等)
  5. // 说明:从SpringCloud的Edgware版本开始,不加注解也ok,但是建议大家加上
  6. public class LagouResumeApplication8080 {
  7. public static void main(String[] args) {
  8. SpringApplication.run(LagouResumeApplication8080.class,args);
  9. }
  10. }

微服务消费者注册到Eureka Server集群

子项目的名称是lagou-service-autodeliver-8090

1、父工程中引入spring-cloud-commons依赖

  1. <dependency>
  2. <groupId>org.springframework.cloud</groupId>
  3. <artifactId>spring-cloud-commons</artifactId>
  4. </dependency>

2、当前项目的pom.xml中引入eureka client 客户端

  1. <!--eureka client 客户端依赖引入-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  5. </dependency>

3、 配置application.yml文件

在application.yml 中添加Eureka Server高可用集群的地址及相关配置

  1. server:
  2. port: 8090
  3. #注册到Eureka服务中心
  4. eureka:
  5. client:
  6. service-url:
  7. # 注册到集群,就把多个Eurekaserver地址使用逗号连接起来即可;注册到单实例(非集群模式),那就写一个就ok
  8. defaultZone: http://LagouCloudEurekaServerA:8761/eureka,http://LagouCloudEurekaServerB:8762/eureka
  9. instance:
  10. prefer-ip-address: true #服务实例中显示ip,而不是显示主机名(兼容老的eureka版本)
  11. # 实例名称: 192.168.1.103:lagou-service-resume:8080,我们可以自定义它
  12. instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
  13. spring:
  14. application:
  15. name: lagou-service-autodeliver #服务消费者的名称,会出现在eureka注册中心的

4、启动类添加注解

@EnableDiscoveryClient和@EnableEurekaClient⼆者的功能是一样的。但 是如果选用的是eureka服务器,那么就推荐@EnableEurekaClient,如果是其 他的注册中心,那么推荐使用@EnableDiscoveryClient,考虑到通用性,后期 我们可以使用@EnableDiscoveryClient

  1. @SpringBootApplication
  2. @EnableDiscoveryClient // 开启服务发现
  3. public class AutodeliverApplication8090 {
  4. public static void main(String[] args) {
  5. SpringApplication.run(AutodeliverApplication8090.class,args);
  6. }

5、服务消费者调用服务提供者(通过Eureka)

  1. @RestController
  2. @RequestMapping("/autodeliver")
  3. public class AutodeliverController {
  4. @Autowired
  5. private RestTemplate restTemplate;
  6. @Autowired
  7. private DiscoveryClient discoveryClient;
  8. /**
  9. * 服务注册到Eureka之后的改造
  10. * @param userId
  11. * @return
  12. */
  13. @GetMapping("/checkState/{userId}")
  14. public Integer findResumeOpenState(@PathVariable Long userId) {
  15. // TODO 从Eureka Server中获取我们关注的那个服务的实例信息以及接口信息
  16. // 1、从 Eureka Server中获取lagou-service-resume服务的实例信息(使用客户端对象做这件事)
  17. List<ServiceInstance> instances = discoveryClient.getInstances("lagou-service-resume");
  18. // 2、如果有多个实例,选择一个使用(负载均衡的过程)
  19. ServiceInstance serviceInstance = instances.get(0);
  20. // 3、从元数据信息获取host port 拼接请求地址
  21. String host = serviceInstance.getHost();
  22. int port = serviceInstance.getPort();
  23. String url = "http://" + host + ":" + port + "/resume/openstate/" + userId;
  24. System.out.println("===============>>>从EurekaServer集群获取服务实例拼接的url:" + url);
  25. // 4、消费者之间调用服务提供者
  26. // 调用远程服务—> 简历微服务接口 RestTemplate -> JdbcTempate
  27. // httpclient封装好多内容进行远程调用
  28. Integer forObject = restTemplate.getForObject(url, Integer.class);
  29. return forObject;
  30. }