Ribbon,Feign,Hystrix,Hystrix-Dashboard,Zuul

Ribbon

依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

客户端负载均衡工具。

常见的负载均衡软件:Nginx,Lvs

分类:

  • 集中式Load Balance。在服务消费方和提供方使用都市Lb实时。Nginx。有lb实时负责把请求转发至服务提供方
  • 进程式LB。将LB集中到消费方,消费方从注册中心获取有哪些地址可用,再从地址中选出一个合适的服务器。例:Ribbon

Ribbon默认轮询

自定义均衡策略:

主义:自定义负载均衡配置类不能喝启动类放在一个包下

  • 启动类添加注解

    //name:自定义均衡的服务提供者,configure:自定义负载均衡类
    @RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT", configuration = MyRule.class)
    
  • 自定义均衡策略类

    package com.moral.myrule;
    
    
    import com.netflix.client.config.IClientConfig;
    import com.netflix.loadbalancer.AbstractLoadBalancerRule;
    import com.netflix.loadbalancer.ILoadBalancer;
    import com.netflix.loadbalancer.Server;
    
    import java.util.List;
    import java.util.concurrent.ThreadLocalRandom;
    
    //自定义负载均衡策略,每个服务使用5次
    public class MyRandomRule extends AbstractLoadBalancerRule {
        public MyRandomRule() {
        }
    
        private int total = 0;//如果=5指向下一个节点
    
        private int currentIndex = 0;
    
        public Server choose(ILoadBalancer lb, Object key) {
            if (lb == null) {
                return null;
            } else {
                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 = this.chooseRandomInt(serverCount);
                    server = (Server)upList.get(index);*/
                    if (total < 5) {
                        server = upList.get(currentIndex);
                        total++;
                    } else {
                        total = 0;
                        currentIndex++;
                        if (currentIndex > upList.size()) {
                            currentIndex = 0;
                        }
                        upList=lb.getReachableServers();
                        server = upList.get(currentIndex);
                    }
    
    
    
                    if (server == null) {
                        Thread.yield();
                    } else {
                        if (server.isAlive()) {
                            return server;
                        }
    
                        server = null;
                        Thread.yield();
                    }
                }
    
                return server;
            }
        }
    
        protected int chooseRandomInt(int serverCount) {
            return ThreadLocalRandom.current().nextInt(serverCount);
        }
    
        public Server choose(Object key) {
            return this.choose(this.getLoadBalancer(), key);
        }
    
        public void initWithNiwsConfig(IClientConfig clientConfig) {
        }
    }
    
  • 配置bean

    @Configuration
    public class MyRule {
    
        @Bean
        public IRule myRule11(){
            return new MyRandomRule();
        }
    }
    

Fign集成了ribbon

ribbon通过服务名字调用,feign通过接口+注解调用

注意:接口上的路径必须和服务提供者提供的路径一样

依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>
接口
@Component
//value:服务名字 多个服务提供最用同一个spring.application.name
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();
}

Feign

Feign替代了restTemplate访问

访问时路径不必和服务提供者和接口路径一样

访问路径:localhost:80/consumer/dept/list

@RestController
@RequestMapping("/consumer/dept")
public class DeptController {

    @Autowired
    private DeptClientService deptClientService =null;

    @RequestMapping("add")
    public boolean addDept(Dept dept) {
        return deptClientService.addDept(dept);
    }

    @RequestMapping("get/{id}")
    public Dept queryById(@PathVariable("id") Long id) {
        return deptClientService.queryById(id);
    }

    @RequestMapping("list")
    public List<Dept> queryAll() {
        return deptClientService.queryAll();
    }
}

Hystrix 熔断

服务熔断

在服务提供方做

依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

yml配置:

server:
  port: 8001

#mybatis配置
mybatis:
  type-aliases-package: com.moral.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

#spring配置
spring:
  application:
    name: springcloud-provider-dept

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    url: jdbc:mysql://localhost:3306/db01?seUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver

#Eureka配置,服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
  instance:
    instance-id: springcloud-provider-hystrix-dept8001 #修改eureka上默认描述信息
    prefer-ip-address: true #true,可以显示服务的ip

#eureka上本服务信息
info:
  app.name: springcloud-provider-dept8001
  company.name: com.moral

启动类

@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker//添加熔断支持
public class HystrixDeptProvider_8001 {

    public static void main(String[] args) {
        SpringApplication.run(HystrixDeptProvider_8001.class, args);
    }
}

controller

@RestController
@RequestMapping("/dept")
public class DeptController {

    @Autowired
    private DeptService deptService;

    @GetMapping("get/{id}")
    @HystrixCommand(fallbackMethod = "hystrixQueryById")//失败时调用的方法
    public Dept queryById(@PathVariable("id") Long id) {
        Dept dept = deptService.queryById(id);
        if (dept == null) {
            throw new RuntimeException("id=>" + id + ",不存在该用户");
        }
        return dept;
    }

    //备选方法
    public Dept hystrixQueryById(@PathVariable("id") Long id) {
        return new Dept().setDeptno(id).setDname("id=>" + id + ",不存在该用户@Hystrix").setDb_source("no database of mysql");
    }
}
服务降级

在服务消费端,客户端做

api:

@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public boolean addDept(Dept dept) {
                return false;
            }

            @Override
            public Dept queryById(Long id) {
                return new Dept().setDeptno(id)
                        .setDname("id=>" +id+"没有对应的信息,客户端提供了降级的信息,这个服务现在已被关闭")
                        .setDb_source("no database");
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }
        };
    }
}
@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT", fallbackFactory = DeptClientServiceFallbackFactory.class)
public interface DeptClientService {

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept);

    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id);

    @GetMapping("/dept/list")
    public List<Dept> queryAll();
}

服务消费端配置;

# 开启降级
feign:
  hystrix:
    enabled: true

启动eureka集群,启动普通服务提供者,启动feigin服务消费者,此时浏览器访问正常,关闭服务提供者时再访问,不会出现异常,会返回DeptClientServiceFallbackFactory中自定义的失败返回信息

服务熔断和服务降级对比
  • 熔断:服务端,某个服务超市或异常,引起熔断,保险丝
  • 降级:客户端,从整体网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再被调用
    • 此时客户端可以准备一个FallbackFactory,返回一个默认值(缺省值),整体服务水平下降,但是,好歹能用,比直接挂掉强

Hystrix Dashboard

dashboard项目
  • 创建dashboard子项目,配置port

  • 启动类:

    @SpringBootApplication
    @EnableHystrixDashboard//开启监控页面
    public class DeptConsumerDashboard_9001 {
        public static void main(String[] args) {
            SpringApplication.run(DeptConsumerDashboard_9001.class, args);
        }
    }
    
服务提供方provider

服务提供方需添加依赖

<!--eureka完善监控信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker//添加熔断支持
public class HystrixDeptProvider_8001 {

    public static void main(String[] args) {
        SpringApplication.run(HystrixDeptProvider_8001.class, args);
    }

    //固定代码
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}
监控流程
  1. http://localhost:9001/hystrix 监控页面

  2. http://localhost:8001/actuator/hystrix.stream查看流信息,需访问接口才能看到动态数据

  3. 监控页面填写http://localhost:8001/actuator/hystrix.stream,进入监控具体页面

4.访问接口http://localhost/consumer/dept/get/7,就能看到页面刷新

5.访问不存在的id,就会触发配置好的熔断降级,上图失败/异常数就会增加1,错误百分比也会增加

Zuul网关

新建zuul子模块,也需要注册到eureka

修改本地hosts文件,添加映射127.0.0.1 www.moral.com

依赖:

<!--zuul-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-zuul -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

yml配置

server:
  port: 9527

eureka:
  client:
    service-url:
      defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
  instance:
    instance-id: zuul9527.com
    prefer-ip-address: true

info:
  app.name: springcloud
  company.name: moral

spring:
  application:
    name: springcloud-zuul

启动类

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication_9527 {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class, args);
    }
}

启动eureka集群,启动服务提供者,启动zuul

访问:http://www.moral.com:9527/springcloud-provider-dept/dept/get/1就可以访问

此时添加yml配置

zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept
    mydept.path: /mydept/** # http://www.moral.com:9527/mydept/dept/get/1也可访问
  #ignored-services: springcloud-provider-dept #不让通过http://www.moral.com:9527/springcloud-provider-dept/dept/get/1访问
  ignored-services: '*' #忽略所有通过服务名访问的请求
  prefix: /jpy #配置统一访问前缀 

就可以通过:http://www.moral.com:9527/mydept/dept/get/1访问,添加ignoreed-services后可以禁止通过服务名访问

posted @   jpy  阅读(2)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示