赞
踩
目录
Eureka 是 Netflix OSS 套件中关于服务注册和发现的解决方案,Spring Cloud 对 Eureka 进行了集成,大量公司的微服务系统使用 Eureka 作为注册中心
Eureka 主要分为两个部分:
1)Eureka Server:作为注册中心 Server 端,向服务应用程序提供服务注册、发现、健康检查等能力
2)Eureka Client:服务提供者,服务启动时,会向 Eureka Service 注册自己的信息(IP、端口、服务信息等),Eureka Service 会存储这些信息
步骤:
1)搭建 Eureka Service
2)将order-service,product-service 都注册到 Eureka
3)order-service 远程调用时,从Eureka中获取 product-service 的服务列表,然后进行交互
Eureka Service 是一个独立的微服务
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- server:
- port: 10010
- spring:
- application:
- name: eureka-server
- eureka:
- instance:
- hostname: localhost
- client:
- fetch-registry: false # 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,不需要同步其他的Eureka Server节点的数据,这里设置为false
- register-with-eureka: false # 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.
- service-url:
- # 设置与Eureka Server的地址,查询服务和注册服务都需要依赖这个地址
- defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
给该项⽬编写⼀个启动类,并在启动类上添加 @EnableEurekaServer 注解,开启eureka注册中心
服务
- @EnableEurekaServer
- @SpringBootApplication
- public class EurekaServerApplication {
- public static void main(String[] args) {
- SpringApplication.run(EurekaServerApplication.class,args);
- }
- }
访问注册中心:http://127.0.0.1:10010/
将 product-service 注册到 eureka-server 中
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- spring:
- application:
- name: product-service
- eureka:
- client:
- service-url:
- defaultZone: http://127.0.0.1:10010/eureka/
刷新注册中心: http://127.0.0.1:10010/
此时 product-service 已经注册到了 eureka 上了
服务注册和服务发现都封装在 eureka-client 依赖中,所以服务发现时也是引入 eureka-client 依赖
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- spring:
- application:
- name: order-service
- eureka:
- client:
- service-url:
- defaultZone: http://127.0.0.1:10010/eureka/
- @Service
- public class OrderService {
-
- @Autowired
- private OrderMapper orderMapper;
-
- @Autowired
- private RestTemplate restTemplate;
-
- @Autowired
- private DiscoveryClient discoveryClient;
-
- public OrderInfo selectOrderById(Integer orderId) {
- OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
- //从 Eureka 中获取服务列表
- List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
- String uri = instances.get(0).getUri().toString();
- String url = uri + "/product/" + orderInfo.getProductId();
- ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
- orderInfo.setProductInfo(productInfo);
- return orderInfo;
- }
- }
此时 order-service 已经注册到 eureka 上了
远程调用也成功了
Eureka 和 Zookeeper 都是用于服务注册和发现的工具,区别如下:
1)Eureka 是 Netflix 开源的项目,而 Zookeeper 是 Apache 开源的项目
2)Eureka 基于 AP 原则,保证高可用,Zookeeper 基于 CP 原则,保证数据一致性
3)Eureka 每个节点都是均等的,Zookeeper 的节点区分 Leader 和 Follower 或 Observer,如果Zookeeper 的 Leader 发生故障时,需要重新选举,选举过程中集群可能会有短暂时间的不可用
- List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
- String uri = instances.get(0).getUri().toString();
上述代码中根据应用名获取了服务示例列表,如果一个服务应对多个实例,流量适合分配的
在启动 2 个 product-service 实例,选择要启动的服务
在弹出的框中,选择 Modify options -> Add VM options
添加 VM options : -Dserver.port=9091
此时,product-service 下有 3 个实例
访问接口,通过日志,可以发现,请求多次访问,都是同一台机器,我们的预期是启动多个实例,是希望可以分担其他机器的负荷
解决方案:
取余,请求计数器 % 实例数
- @Slf4j
- @Service
- public class OrderService {
-
- @Autowired
- private OrderMapper orderMapper;
-
- @Autowired
- private RestTemplate restTemplate;
-
- @Autowired
- private DiscoveryClient discoveryClient;
-
- //计数器
- private static AtomicInteger count = new AtomicInteger(1);
-
- private static List<ServiceInstance> instances;
- @PostConstruct
- public void init() {
- instances = discoveryClient.getInstances("product-service");
- }
-
- public OrderInfo selectOrderById(Integer orderId) {
- OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
- //服务可能有多个,轮询获取实例
- int index = count.getAndIncrement() % instances.size();
- String uri = instances.get(index).getUri().toString();
- String url = uri + "/product/" + orderInfo.getProductId();
- log.info("调用的url:" + url);
- ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
- orderInfo.setProductInfo(productInfo);
- return orderInfo;
- }
- }
通过日志可以看到,请求被均衡的分配在了不同的实例上
负载均衡(Load Balance),是高并发、高可用系统必不可少的关键组件,当服务流量增大时,通常采用增加机器的方式进行扩容,负载均衡就是用来在多个机器或者其他资源中,按照一定的规则合理分配负载
服务端负载均衡
在服务端进行负载均衡算法,⽐较有名的服务端负载均衡器是 Nginx,请求先到达 Nginx 负载均衡器,然后通过负载均衡算法,在多个服务器之间选择一个进行访问
客户端负载均衡
在客户端进行负载均衡的算法匹配,把负载均衡的功能以库的方式继承到客户端,而不再是由一台指定的负载均衡设备几种提供
⽐如 Spring Cloud 的 Ribbon,请求发送到客户端,客户端从注册中心(例如 Eureka)获取服务列表,在发送请求与前通过负载均衡算法选择一个服务器,然后访问
1)给 RestTemplate 这个Bean添加 @LoadBalanced 注解就可以
- @Configuration
- public class BeanConfig {
-
- @Bean
- @LoadBalanced
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
- }
2)修改 IP 端口号为服务名称
- public OrderInfo selectOrderById(Integer orderId) {
- OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
- String url = "http://product-service/product/" + orderInfo.getProductId();
- log.info("调用的url:" + url);
- ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
- orderInfo.setProductInfo(productInfo);
- return orderInfo;
- }
Spring Cloud LoadBalancer 仅支持两种负载均衡策略:轮询策略和随机策略
1)轮询:轮询策略是指服务器轮流处理用户请求,这是一种实现最简单,最常用的策略
2)随机:随机选择一个后端服务器来处理新的请求
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。