SpringCloud(六)——微服务集群
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringCloud(六)——微服务集群相关的知识,希望对你有一定的参考价值。
参考技术A 为了避免Eureka的单点故障,我们搭建了Eureka集群。要是微服务发生了单点故障怎么办呢?
那么就要搭建微服务集群了。
我们再新建一个服务提供者,之前有了一个8001的提供者,我们用同样的方式创建一个8002端口的提供者,可以参考我之前写的:
https://www.jianshu.com/p/e1b08eeb1d1e
8001工程里面的类和配置文件在8002里都要有一份,只不过我们要将端口改成8002。
因为之前只有一个服务提供者,我们也就无需区分请求发到了哪个服务。现在我们有两个服务提供者了,所以我们要区分一下发到了哪个服务,需要再controller里改一下。
添加端口号的属性,并且作为数据返回。
改造号了之后我们要先分别单独发送一下8001和8002的服务看看是否可以返回,确保微服务没问题。
服务提供者没问题了接下来改造消费者。
消费者里面需要改的有两处controller和config
在消费者的controller里,我们通过restTemplate来和提供者进行通讯,之前的写法是写死了一个url来供restTemplate发送,因为提供者是集群模式了,所以我们就不能写死发往8001的url了。
我们现在要使用服务名来发送服务。
这里的服务名就是注册到Eureka的服务名。
所以我们要在controller里面使用服务名做url。
因为我们使用了服务名,就不能直接解析成ip地址+端口号的形式了,需要我们在restTemplat上面添加@LoadBalanced注解,这个注解同时可以开启我们默认的负载均衡策略。
先看一下我们启动的工程:
Eureka集群和Payment提供者集群都已经搭建好了。并且注册中心中也有实例信息。
那么我们多发送几个请求看看结果。
我们可以看到发送到消费者的服务被依次分发到8001和8002的两个服务上了。
说明我们的负载均衡也生效了!
微服务架构整理-(六SpringCloud实战之Ribbon)
SpringCloud实战之Ribbon
负责均衡介绍
负载均衡分为 硬件负载均衡和软件负载均衡。常用见的如下:
硬件负载均衡: F5 ,深信服, Array 等;
软件负载均衡: Nginx,LVS,HAProxy,Ribbon 等;
它们的原理是维护一个可用的服务列表,通过心跳机制来剔除不可用节点,从而保证可用列表的有效性。当请求经过负载均衡设备(软件)时,设备会按照设定的算法从可用的列表中选择一个服务进行转发。
Ribbon概念
Ribbon是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算
法, 是 一 个基于 HTTP 和 TCP 的客户端负载均衡工具,这里可以理解成服务消费者端的负载均衡工具。
SpringCloud对Ribbon进行了二次封闭,可以让开发人员通过RestTemplate(在注入时,直接在上方加入注解 @LoadBalanced 即可)的实例调用接口时,可以自动进行服务选择。
其主要特点包括:
- 负责均衡算法多样,且支持定制化
- 小巧,使用方便,无需独立部署,直接在代码里使用即可
- 不同于服务端负载均衡,Ribbon的可用服务列表直接从注册中心中读取
Ribbon中的负载均衡算法
Ribbon中提供了一系列的负载均衡算法,这些算法封装了相应的java类,使用时只需注入到Spring容器中即可。
算法 | 作用 |
---|---|
RandomRule | 随机选择一个 Server |
RoundRobinRule | 轮询选择 |
RetryRule | 先按照RoundRobinRule 策略选择,如果选择到的服务不能访问,则在指定时间内进行重试,选择其他可用的服务 |
BestAvailableRule | 先过滤掉由于多次访问故障的服务,然后选择一个并发量最小的服务 |
ResponseTimeWeightedRule/WeightedResponseTimeRule | 根据响应时间分配一个 Weight(权重),响应时间越长,Weight 越小,被选中的可能性越低 |
AvailabilityFilteringRule | 先过滤掉由于多次访问故障的服务,以及并发连接数超过阈值的服务,然后对剩下的服务按照轮询策略进行访问 |
ZoneAvoidanceRule | 综合判断服务节点所在区域的性能和服务节点的 可用性,来 决定选择哪个服务 |
Ribbon使用
因为SpringCloud对Ribbon进行了二次封闭,所以使用起来很方便。这里在上一篇博客的基础上将Ribbon加进来,所以只给出改动的代码。
添加一个服务提供者
之前只有一个服务提供者,为了能够使用负载均衡,至少需要两个服务提供者。所以这里将之前的product_service 复制一份,稍加修改就可以了。涉及以下几个方面:
端口号与服务名
在application.yml中修改端口号,服务名保持不动,服务消费者根据服务名获取服务提供者的集合,然后在集合中选择(由Ribbon完成)一个服务提供者。
server:
# port: 9001 #端口
port: 9003 #端口
spring:
favicon:
enabled: false
application:
name: service-product #服务名称,与之前保持一样
工程添加到父工程里面
在父工程pom.xml中添加新的module
<modules>
<module>product_service</module>
<!--添加product_service_2 module -->
<module>product_service_2</module>
<module>order_service</module>
<module>eureka_service</module>
<module>eureka_service_1</module>
</modules>
工程id
product_service_2的pom.xml中修改artifactId
<artifactId>product_service_2</artifactId>
添加Ribbon
在消费者服务(service-order)的配置类中通过添加 @LoadBalanced 方式引进Ribbon, 负载均衡算法通过bean的方式注入,如果不注入算法,默认使用轮询算法。
@Configuration
public class Config
//引入Ribbon,此标签引入后,当服务启动的时候会自动读取注册中心的服务提供者
@LoadBalanced
@Bean
public RestTemplate getRestTemplate()
return new RestTemplate();
//注入负责均衡算法,这里只列了两种,大家可以根据自己的需求自行添加
@Bean
public IRule getIRule()
// return new RandomRule();
return new BestAvailableRule();
区别服务提供者
因为两个服务提供者返回的内容都一样,所以这里为了区分是由哪个服务者返回的内容,在返回值上稍加修改,真正的生产环境不需要这样。
product_service
在name后面加上1
@GetMapping(value = "/id")
public Product findById(@PathVariable Long id)
Product product = productService.findById(id);
product.setName(product.getName() + "1");
return product;
product_service_2
在name后面加上2
@GetMapping(value = "/id")
public Product findById(@PathVariable Long id)
Product product = productService.findById(id);
product.setName(product.getName() + "2");
return product;
访问服务提供者
order_service controller中不能再使用服务提供者的实例,需要将其改成服务名,因为这里会有多个实例,每个实例拥有自己的端口,如果用实例的话,这里拼服务的地址的时候,又需要写个算法来判断使用哪个端口,所以直接使用服务名就可以,具体用哪个服务,交给Ribbon来处理。
/**
* @author :浦江之猿
* @date :Created in 2022/05/19 21:48
*/
@RestController
@RequestMapping("/order")
public class OrderController
@Autowired
RestTemplate restTemplate;
@Autowired
DiscoveryClient discoveryClient;
@GetMapping(value = "/buy/id")
public Product findById(@PathVariable Long id)
// 获取元数据
/* List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
ServiceInstance instance = instances.get(0);
restTemplate.getForObject("http://"+instance.getHost()+":"+instance.getPort()+"/product/"+id,Product.class); */
Product product = null;
//直接将服务名拼接到地址中
product = restTemplate.getForObject("http://service-product/product/" + id, Product.class);
return product;
运行结果
注册中心
访问http://localhost:9006/,可以看到service-product启了两个
访问订单
看一下使用轮询算法的结果,http://localhost:9002/order/buy/1 返回值会在下面两条中来回切换。
//product_service 返回的结果
"id":1,"name":"apple1","price":8000.00
//product_service_2返回的结果
"id":1,"name":"apple2","price":8000.00
总结
关于Ribbon的使用基本就介绍完了,因为SpringCloud对其进行了二次封装,所以使用其来非常方便。最后,希望本文能帮助大家,祝大家在IT之路上少走弯路,一路绿灯不堵车,测试一性通过,bug秒解!
源码下载
以上是关于SpringCloud(六)——微服务集群的主要内容,如果未能解决你的问题,请参考以下文章
springCloud搭建微服务集群+Zuul服务器端负载均衡
SpringCloud微服务电商系统在Kubernetes集群中上线详细教程
Jenkins—— Jenkins+Docker+SpringCloud微服务持续集成项目优化和集群
云原生微服务SpringCloud-eureka(server)集群搭建