负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。
单独导入
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
<version>2.2.1.RELEASEversion>
dependency>
整合依赖spring-cloud-starter-netflix-eureka-client里面也包含了ribbon的依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
<version>2.2.1.RELEASEversion>
dependency>
public class HcodeRule extends AbstractLoadBalancerRule {
//每个服务,访问5次,然后循环所有服务
private AtomicInteger total = new AtomicInteger(0); //服务被调用的次数
private AtomicInteger currentIndex = new AtomicInteger(0); //当前被调用服务的下标
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
return null;
}
Server server = null;
while (server == null) {
if (Thread.interrupted()) {
return null;
}
//获得活着的服务
List<Server> upList = lb.getReachableServers();
//获得全部服务
List<Server> allList = lb.getAllServers();
int serverCount = allList.size();
if (serverCount == 0) {
return null;
}
// //生成区间随机数
// int index = chooseRandomInt(serverCount);
// server = upList.get(index); //从或者的服务中随机获取一个
/*============================================*/
if(total.get()<5){
server = upList.get(currentIndex.get());
getAndIncrement(total);
}else{
total.set(0);
getAndIncrement(currentIndex);
if(currentIndex.get()>=upList.size()){
currentIndex.set(0);
}
server = upList.get(currentIndex.get());
getAndIncrement(total);
}
/*==============================================*/
if (server == null) {
Thread.yield();
continue;
}
if (server.isAlive()) {
return (server);
}
// Shouldn't actually happen.. but must be transient or a bug.
server = null;
Thread.yield();
}
return server;
}
//自旋锁防止高并发情况数据不一致性
private final int getAndIncrement(AtomicInteger atomicInteger){
int current;
int next;
do {
current = atomicInteger.get();
next = current >= 2147483647 ? 0 : current + 1;
}while (!atomicInteger.compareAndSet(current,next)); //第一个参数是期望值,第二个参数是修改值是
return next;
}
protected int chooseRandomInt(int serverCount) {
return ThreadLocalRandom.current().nextInt(serverCount);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
// TODO Auto-generated method stub
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
}
再将该策略类注入IOC容器,当然如果不想写自定义策略类,那就使用原有的IRule的实现类,将其注入IOC容器即可.下面两种二选一
@Configuration
public class MyRule {
@Bean //使用自定义的
public IRule HcodeRule(){
return new HcodeRule();
}
//============================================================
//AvailabilityFilteringRule : 先过滤掉出现故障的服务器,对剩下的服务进行轮询
//RoundRobinRule 轮询 默认设置
//RandomRule 随机
//WeightedResponseTimeRule 权重
//RetryRule:先按照轮询获取,若获取服务失败,则在指定时间内进行重试
//随机访问,只要将实现类注入到ICO容器,即可覆盖
@Bean //使用原有的实现类
public IRule myRule(){
return new RandomRule();
}
}
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候就能去加载我们自定义的负载均衡Ribbon类,name为微服务提供者注册到注册中心的服务名
@RibbonClient(name="SPRINGCLOUD-PROVIDER-DEPT",configuration = MyRule.class)
public class DeptConsumer_80 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumer_80.class,args);
}
}
单独导入依赖 org.springframework.cloud:spring-cloud-starter-hystrix:2.2.1.RELEASE
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
<version>2.2.1.RELEASEversion>
dependency>
使用eureka整合客户端pom就不用再导入单独的hystrix
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
@RestController
@DefaultProperties(defaultFallback = "Global_FallbackMethod") //没有配置专属熔断器方法,就走全局熔断器
public class TestController {
@HystrixCommand //没加特定方法,走全局
@PostMapping("/global")
public String test1(){
return "(●'◡'●)全局熔断器方法未触发";
}
//全局响应Fallback方法 服务降级触发熔断
public Object Global_FallbackMethod(){
return "┭┮﹏┭┮全局熔断器方法触发了,呜呜呜!";
}
//断路器
@HystrixCommand( fallbackMethod = "CircuitBreaker_fallback" , commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),// 是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),// 请求次数
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //时间窗口期,失败后经过多久尝试恢复
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60") //失败率到达多少后跳闸
})
@GetMapping("/local")
public String test2(){
return "(●'◡'●)特定断路器方法未触发~";
}
public String CircuitBreaker_fallback(){ //参数可以跟原接口方法参数一致
return "┭┮﹏┭┮特定限制方法熔断器触发了,呜呜呜~";
}
}
@EnableCircuitBreaker //添加对服务熔断的支持
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
然后配置yml,让feign支持hystrix
feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
然后再服务层接口加上注解。
@FeignClient(value = "hystrix-test-provider",fallback = DeptFallbackService.class) //服务名,备用的响应类
@Component
public interface testService {
@GetMapping("/global")
public String test1();
}
兜底用的备用响应类
@Component // 服务降级
public class DeptFallbackService implements testService{
public String test1() {
return "┭┮﹏┭┮该服务被降级了,目前无法使用";
}
}
最后,主启动类添加@EnableHystrix
@EnableHystrix
老样子,hystrix也是停止更新了,所以换新的才是王道~况且阿里巴巴的sentinel就是继承hystrix,两者挺像的。
下载好jar包sentinel-dashboard-1.7.0.jar后,直接命令行运行即可~
注意:该boot服务默认为8080端口号。启动后,访问http://localhost:8080,账号密码都是sentinel。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
server:
port: 8666
spring:
application:
name: cloudalibaba-sentinel-service
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos注册中心的地址
sentinel:
transport:
dashboard: localhost:8080 # sentinel的地址
port: 8719 #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
# 暴露监控
management:
endpoints:
web:
exposure:
include: '*'
@EnableDiscoveryClient
@SpringBootApplication
@RestController
@SentinelResource(fallbackClass = "Global_FallbackMethod")
public class TestController {
@SentinelResource(value = "test",blockHandlerClass = CustomerBlockHandle.class,blockHandler ="deal_test")
@GetMapping("/test")
public String test(@RequestParam(value = "p") String p){
return "(●'◡'●)没有被限流";
}
// public String test(String p,BlockException blockException){
// return "-------------deal list ┭┮﹏┭┮";
// }
//全局响应Fallback方法 服务降级触发熔断
public Object Global_FallbackMethod(){
return "┭┮﹏┭┮全局熔断器方法触发了,呜呜呜!";
}
}
统一处理限流的备用方法类
public class CustomerBlockHandle {
public static String deal_test(String p, BlockException blockException){
return "┭┮﹏┭┮被限流了";
}
}
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-sentinelartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
server:
port: 80
spring:
application:
name: nacos-test-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
service-url:
nacos-user-service: http://cloudalibaba-sentinel-service
#对Feign的支持
feign:
sentinel:
enabled: true
@FeignClient(value = "cloudalibaba-sentinel-service",fallback = DeptFallbackService.class)
@Component
public interface TestService {
@GetMapping("/test")
public String test();
}
@Component // 服务降级
public class DeptFallbackService implements DeptService {
public String test() {
return "┭┮﹏┭┮服务被降级了,不能使用~";
}
}
@Autowired
private TestService testService ;
@GetMapping(value = "/consumer/test")
public String test(){
return testService.test();
}
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients
public class test80
{
public static void main(String[] args) {
SpringApplication.run(test80.class, args);
}
}