一、搭建服务提供者集群

  • 项目层级

 

 

  •  创建一个新module(cloud-provider-payment9001)

    这个module只修改端口号,其余内容和8001一样

server:
  # 端口
  port: 9001
spring:
  #要配置集群、名字必须相同
  application:
    name: cloud-payment-service
  #安全认证
  security:
    user:
      name: root
      password: root
  #数据源基本配置
  datasource:
    url: jdbc:mysql://localhost:3306/test_springcloud
    username: root
    password: 678678
    #druid
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
eureka:
  client:
    # 表示将自己注册进Eureka Server默认为true
    register-with-eureka: true
    # 是否从Eureka Server抓去已有的注册信息,默认是true
    fetch-registry: true
    # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
    service-url:
      defaultZone: http://${spring.security.user.name}:${spring.security.user.password}@eureka1.com:8887/eureka,http://${spring.security.user.name}:${spring.security.user.password}@eureka2.com:8888/eureka,http://${spring.security.user.name}:${spring.security.user.password}@eureka3.com:8889/eureka
mybatis:
  mapper-locations: classpath:mapping/*.xml
#开启优雅停服
#(必须通过POST请求向Eureka Client发起一个shutdown请求。请求路径为:http://ip:port/shutdown。可以通过任意技术实现,如:HTTPClient,AJAX等。)
management:
  endpoint:
    shutdown:
      enabled: true

 

  • 重启服务。调用消费者就会负载均衡了

 1 package com.sdkj.config;
 2 
 3 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 4 import org.springframework.context.annotation.Bean;
 5 import org.springframework.context.annotation.Configuration;
 6 import org.springframework.web.client.RestTemplate;
 7 
 8 /**
 9  * @Author wangshuo
10  * @Date 2022/5/19, 19:49
11  * Please add a comment
12  */
13 @Configuration
14 public class AppConfig {
15 
16     /**
17      * 注入restTemplate,请用请求rest接口
18      * @return
19      */
20     @Bean
21     // 标注此注解后,RestTemplate就具有了客户端负载均衡能力
22     // 负载均衡技术依赖于的是Ribbon组件~
23     // RestTemplate都塞入一个loadBalancerInterceptor 让其具备有负载均衡的能力
24     @LoadBalanced
25     public RestTemplate restTemplate(){
26         return new RestTemplate();
27     }
28 }

二、服务发现

  • App

 1 package com.sdkj;
 2 
 3 import org.mybatis.spring.annotation.MapperScan;
 4 import org.springframework.boot.SpringApplication;
 5 import org.springframework.boot.autoconfigure.SpringBootApplication;
 6 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 7 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 8 
 9 /**
10  * @Author wangshuo
11  * @Date 2022/5/18, 16:37
12  * Please add a comment
13  */
14 @SpringBootApplication(scanBasePackages = {"com.sdkj"})
15 @EnableEurekaClient
16 //启用服务发现
17 @EnableDiscoveryClient
18 @MapperScan("com.sdkj.dao")//扫描dao添加Mapper
19 public class App {
20 
21     public static void main(String[] args) {
22         SpringApplication.run(App.class);
23     }
24 }
  • PaymentController

 1 package com.sdkj.controller;
 2 
 3 import com.sdkj.dataobject.PaymentDO;
 4 import com.sdkj.error.BusinessException;
 5 import com.sdkj.error.EnumBusinessError;
 6 import com.sdkj.response.CommonReturnType;
 7 import com.sdkj.service.PaymentService;
 8 import lombok.extern.slf4j.Slf4j;
 9 import org.apache.commons.lang.StringUtils;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.cloud.client.ServiceInstance;
12 import org.springframework.cloud.client.discovery.DiscoveryClient;
13 import org.springframework.stereotype.Controller;
14 import org.springframework.web.bind.annotation.CrossOrigin;
15 import org.springframework.web.bind.annotation.RequestMapping;
16 import org.springframework.web.bind.annotation.ResponseBody;
17 
18 /**
19  * @Author wangshuo
20  * @Date 2022/5/19, 9:08
21  * Please add a comment
22  */
23 @Controller
24 @RequestMapping(value = "/payment")
25 @CrossOrigin(origins = {"*"}, allowCredentials = "true")
26 @Slf4j
27 public class PaymentController extends BaseController {
28 
29     @Autowired
30     PaymentService paymentService;
31     //注入服务发现
32     @Autowired
33     DiscoveryClient discoveryClient;
34 
35     @RequestMapping(value = "/findById")
36     @ResponseBody
37     public CommonReturnType findById(Long id) throws BusinessException {
38 
39         if (StringUtils.isEmpty(id.toString()))
40             throw new BusinessException(EnumBusinessError.REGISTER_OTP_ERROR);//参数不合法
41         PaymentDO payment = paymentService.getPaymentById(id);
42         return CommonReturnType.create(payment);
43     }
44 
45     @RequestMapping(value = "/getDiscovery")
46     @ResponseBody
47     public Object getDiscovery(){
48 
49         //获取服务列表
50         for (String service : discoveryClient.getServices()) {
51             log.info("发现service:" + service);
52         }
53         //获取服务实例集合
54         for (ServiceInstance instance : discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE")) {
55             log.info("发现服务CLOUD-PAYMENT-SERVICE:" +
56                     " serviceId = " +instance.getServiceId() +
57                     " host = " + instance.getHost() +
58                     " port = " + instance.getPort() +
59                     " uri = " + instance.getUri());
60         }
61         return this.discoveryClient;
62     }
63 }

 

三、自带负载均衡规则说明

策略名 策略声明 策略描述 实现说明
BestAvailableRule public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule 选择一个最小的并发请求的server 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
AvailabilityFilteringRule public class AvailabilityFilteringRule extends PredicateBasedRule 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
WeightedResponseTimeRule public class WeightedResponseTimeRule extends RoundRobinRule 根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择server。
RetryRule public class RetryRule extends AbstractLoadBalancerRule 对选定的负载均衡策略机上重试机制。 在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server
RoundRobinRule public class RoundRobinRule extends AbstractLoadBalancerRule roundRobin方式轮询选择server 轮询index,选择index对应位置的server
RandomRule public class RandomRule extends AbstractLoadBalancerRule 随机选择一个server 在index上随机,选择index对应位置的server
ZoneAvoidanceRule public class ZoneAvoidanceRule extends PredicateBasedRule 复合判断server所在区域的性能和server的可用性选择server 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。