美文网首页
【Spring-Cloud】使用教程 基础篇 Eureka Ri

【Spring-Cloud】使用教程 基础篇 Eureka Ri

作者: 植富宝 | 来源:发表于2019-02-27 19:37 被阅读0次

    ==1. Eureka-Server==

    1.1 新建eureka-server项目,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    

    1.2 修改application.yml

    1.2.1 单例

    server:
      port: 8761
    
    eureka:
      instance:
        hostname: localhost
      client:
        registerWithEureka: false
        fetchRegistry: false
        serviceUrl:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    

    1.2.2 多例

    ---
    spring:
      profiles: peer1
    eureka:
      instance:
        hostname: peer1
      client:
        serviceUrl:
          defaultZone: http://peer2/eureka/
    
    ---
    spring:
      profiles: peer2
    eureka:
      instance:
        hostname: peer2
      client:
        serviceUrl:
          defaultZone: http://peer1/eureka/
    

    1.3 添加注解

    @EnableEurekaServer
    

    ==2. Eureka-Client==

    2.1 对应的服务中,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    

    2.2 修改application.yml

    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    

    2.3 添加注解

    @EnableEurekaClient
    

    ==3. Ribbon==

    3.1 对应的服务中,添加pom依赖

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

    3.2 修改application.yml

    beebee-archives-thrift-consumer: # 服务提供者的名称
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡策略
    

    3.3 启动类

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    

    3.4 添加工具类 EurekaUtil

    @Configuration
    public class EurekaUtil {
        @Autowired
        private  RestTemplate restTemplate;
        @Autowired
        private  LoadBalancerClient loadBalancerClient;
        /**
         * 远程调用
         * @param server 调用的服务器
         * @param method 调用的方法
         * @param p 方法的参数
         */
        public <P> String remoteInvoke(String server, String method, P p) {
            ServiceInstance serviceInstance = loadBalancerClient.choose(server);
            return restTemplate.postForObject("http://" + serviceInstance.getServiceId() + method, p, String.class);
        }
    }
    

    3.5 Controller调用

    @PostMapping("/getList")
    public String getList(ArchivesListParam param) {
        return eurekaUtil.remoteInvoke(Server.BEEBEE_ARCHIVES_THRIFT_PROVIDER_CLIENT, Method.ARCHIVES_GET_LIST, param);
    }
    

    ==4. Feign==

    4.1 对应的服务中,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

    4.2 启动类添加注解

    @EnableFeignClients
    

    4.3 在service.impl下,添加 interface

    @FeignClient(name = "product-service")
    public interface ProductClient {
        @GetMapping("/api/v1/product/find")
        String findById(@RequestParam("id") int id);
    }
    

    4.4 在OrderServiceImpl下使用

    @Autowired
    private ProductClient productClient;
    
    String resp = productClient.findById(productId);
    

    ==5. Hystrix==

    5.1 对应的服务中,添加pom依赖

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

    5.2 启动类添加注解

    @EnableCircuitBreaker
    

    5.3 OrderController使用

    @Autowired
    private StringRedisTemplate redisTemplate;
    
    @RequestMapping("save")
    @HystrixCommand(fallbackMethod = "saveOrderFail")
    public Object save(int userId, int productId, HttpServletRequest request) {
        Map<String, Object> data = new HashMap<>();
        data.put("code", 0);
        data.put("data", orderService.save(userId, productId));
        return data;
    }
    
    private Object saveOrderFail(int userId, int productId, HttpServletRequest request) {
        String saveOrderKey = "save-order";
        String saveValue = redisTemplate.opsForValue().get(saveOrderKey);
        String ip = request.getRemoteAddr();
    
        new Thread(() -> {
            if (StringUtils.isBlank(saveValue)) {
                // TODO 调用短信接口 ip服务器宕机,请尽快处理
                redisTemplate.opsForValue().set(saveOrderKey, "save-order-fail", 30, TimeUnit.SECONDS);
            } else {
                // TODO 30s内不再重发
            }
        }).start();
    
        Map<String, Object> msg = new HashMap<>();
        msg.put("code", -1);
        msg.put("msg", "抢购人数太多,您被寄出来了");
        return msg;
    }
    

    ==6. Feign 结合 Hystrix==

    6.1 开启Feign支持Hystrix

    feign:
      hystrix:
        enabled: true
    

    6.2 在fallback包下创建ProductClientFallback

    @Component
    public class ProductClientFallback implements ProductClient {
        @Override
        public String findById(int id) {
            System.out.println("异常处理:记录日志、发送短信或邮件");
            return null;
        }
    }
    

    6.3 在注解@FeignClient添加fallback类

    @FeignClient(name = "product-service", fallback = ProductClientFallback.class)
    public interface ProductClient {
        @GetMapping("/api/v1/product/find")
        String findById(@RequestParam("id") int id);
    }
    

    ==7. 断路器Dashboard监控仪表盘==

    7.1 对应的服务中,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    

    7.2 启动类添加注解

    @EnableHystrixDashboard
    

    7.3 修改application.yml

    management:
      endpoints:
        web:
          exposure:
            include: "*"
    

    7.4 访问入口

    http://localhost:8781/hystrix
    http://localhost:8781/actuator/hystrix.stream
    

    7.5 断路器图示

    断路器close状态

    graph LR
    consumer-->断路器
    断路器-->provider
    

    断路器半开状态

    graph LR
    consumer-.->断路器
    断路器-->provider
    

    断路器open状态

    graph LR
    consumer-.X.->断路器
    断路器-->provider
    

    ==8. Zuul==

    8.1 新建beebee-zuul项目,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
    

    8.2 启动类添加注解

    @EnableZuulProxy
    

    8.3 访问

    之前:http://localhost:8781/api/v1/order/save?userId=1&productId=1
    现在:http://localhost:9000/order-service/api/v1/order/save?userId=1&productId=1
    访问规则:http://ip:port/service-id/*
    注意:order-service 注意大小写,需要和application.yml配置的一样
    

    8.4 自定义路由

    server:
      port: 9000
    spring:
      application:
        name: beebee-api
    zuul:
      routes:
        order-service: /beebee-api/order/**  # 自定义服务名称
        product-service: /beebee-api/product/**  # 此名称不要与上面冲突,否则会覆盖上面的
      ignored-services: product-service  # 忽略一个,忽略商品服务,不能通过 http://localhost:9000/product-service/... 访问
      ignored-patterns: /*-service/**  # 忽略多个,只能通过 http://localhost:9000/beebee-api/... 访问   
            
    访问方式:http://localhost:9000/beebee-api/api/v1/order/save?userId=1&productId=1
    

    8.5 Http请求头过滤问题

    @ConfigurationProperties("zuul")
    public class ZuulProperties {
        // 默认以下三个敏感信息不传递到下游服务器
        private Set<String> sensitiveHeaders = new LinkedHashSet<>(Arrays.asList("Cookie", "Set-Cookie", "Authorization"));
    }
    
    # 将此属性置为空
    zuul:
      sensitive-headers:
    

    8.6 zuul流程

    过滤器order值越小,越优先执行
    

    [图片上传失败...(image-be497b-1551267407598)]

    8.7 自定义zuul过滤器

    在filter包下添加LoginFilter
    
    @Component
    public class LoginFilter extends ZuulFilter {
    
        /**
         * 过滤器类型,前置过滤器
         * @return
         */
        @Override
        public String filterType() {
            return PRE_TYPE;
        }
    
        /**
         * 过滤器执行顺序,越小越先执行
         * @return
         */
        @Override
        public int filterOrder() {
            return 4;
        }
    
        /**
         * 过滤器是否生效
         * @return
         */
        @Override
        public boolean shouldFilter() {
            RequestContext context = RequestContext.getCurrentContext();
            HttpServletRequest request = context.getRequest();
    
            // 或者ACL方式
            if ("/beebee-api/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
                return true;
            }
            return false;
        }
    
        /**
         * 业务逻辑
         * @return
         * @throws ZuulException
         */
        @Override
        public Object run() throws ZuulException {
            RequestContext context = RequestContext.getCurrentContext();
            HttpServletRequest request = context.getRequest();
            String token = request.getHeader("token");
            token = StringUtils.isEmpty(token) ? request.getParameter("token") : token;
    
            // 登录校验,实际使用改为JWT
            if (StringUtils.isBlank(token)) {
                context.setSendZuulResponse(false);
                context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            }
            return null;
        }
    }
    
    

    8.8 订单服务限流

    在filter包下创建OrderRateLimitFilter类
    
    @Component
    public class OrderRateLimitFilter extends ZuulFilter {
    
        // Guava:每秒产生1000个令牌,即每秒最多1000个请求
        private static final RateLimiter RATE_LIMITER = RateLimiter.create(1000);
    
        @Override
        public String filterType() {
            return PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return -4;
        }
    
        @Override
        public boolean shouldFilter() {
            RequestContext context = RequestContext.getCurrentContext();
            HttpServletRequest request = context.getRequest();
    
            // 只对订单接口限流
            if ("/beebee-api/order/api/v1/order/save".equalsIgnoreCase(request.getRequestURI())) {
                return true;
            }
            return false;
        }
    
        @Override
        public Object run() throws ZuulException {
            RequestContext context = RequestContext.getCurrentContext();
            if (!RATE_LIMITER.tryAcquire()) {
                context.setSendZuulResponse(false);
                context.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());
            }
            return null;
        }
    }
    

    ==9. Sleuth==

    9.1 对应的项目中,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-sleuth</artifactId>
    </dependency>
    

    9.2 XxxServiceImpl中使用

    private final Logger logger = LoggerFactory.getLogger(getClass());
    logger.info("order -- service");
    
    2019-01-16 17:45:51.507  INFO [order-service,4fdff23615ab2226,d8818e5c8e6e5ba5,false] 8446 --- [derController-2] c.z.o.service.impl.OrderServiceImpl : order -- service
    
    第一个值:order-service,spring.application.name的值
    第二个值:4fdff23615ab2226,叫TraceID,用来标识一条请求链路,一条请求链路中包含一个TraceID,多个SpanID
    第三个值:d8818e5c8e6e5ba5,叫SpanID,基本的工作单元,获取元数据,如发送一个http
    第四个值:false,是否要将该信息输出到zipkin服务中来收集和展示。
    

    ==10. Zipkin==

    10.1 web使用 Zipkin

    docker run -d -p 9411:9411 openzipkin/zipkin 
    访问:http://localhost:9411/zipkin/    
    

    10.2 对应的服务中,添加pom依赖

    这个依赖包含了 spring-cloud-starter-sleuth、spring-cloud-sleuth-zipkin
    相应的服务都要添加以下依赖
    
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    

    10.3 修改application.yml

    spring:
      application:
        name: order-service
      zipkin:
        base-url: http://localhost:9411
      sleuth:
        sampler:
          probability: 1 # 采样百分比:开发环境=1即100%,生成环境用默认的=0.1即10%
    

    ==11. Config==

    11.1 新建config-server项目,添加pom依赖

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    

    11.2 启动类添加注解

    @EnableConfigServer
    

    11.3 修改application.yml

    spring:
      application:
        name: config-server
    server:
      port: 9100
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/ 
    

    11.4 码云建立config-cloud项目

    https://gitee.com/zhangyimai/config-cloud.git
    

    11.5 修改application.yml

    spring:
      cloud:
        config:
          server:
            git:
              uri: https://gitee.com/zhangyimai/config-cloud 
              username:
              password: 
              timeout: 5
    

    11.6 在码云config-cloud项目上,新建product-service.yml文件

    11.7 访问方式

    http://localhost:9100/product-service.yml
    /{name}-{profiles}.properties
    /{name}-{profiles}.yml
    /{name}-{profiles}.json
    /{label}/{name}-{profiles}.yml
    name:服务器名称
    profile:环境名称,开发、测试、生产
    lable:仓库分支、默认master分支
    

    11.8 config-client使用,product-service添加pom依赖

    <!--配置中心客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-client</artifactId>
    </dependency>
    

    11.9 修改application.yml为bootstrap.yml

    # 服务名称
    spring:
      application:
        name: product-service
      # 指定从哪个配置中心读取
      cloud:
        config:
          discovery:
            service-id: CONFIG-SERVER # 服务ID
            enabled: true
          label: dev # dev分支,建议用label区分配置文件的环境
          profile: dev # 配置文件后缀,不建议用profile区分配置文件的环境
    # 注册中心
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
          
    此配置文件读取的路径:http://localhost:9100/dev/product-service-dev.yml
    

    ==12. Bus==

    12.1 Docker安装启动RabbitMQ

    docker pull rabbitmq:management
    docker run -d --name="myrabbitmq" -p 5671:5671 -p 15672:15672 rabbitmq:management
    访问:http://localhost:15672
    用户名密码:guest
    

    12.2 config-client添加pom依赖

    <!--配置中心结合消息队列-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    

    12.3 添加RabbitMQ等配置

    在码云config-cloud项目中,对应的配置文件添加如下配置
    
    # RabbitMQ连接信息
    spring:
      rabbitmq:
        host: localhost
        port: 5672
        username: guest
        password: guest
    #暴露全部的监控信息
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    

    12.4 需要刷新配置的类上添加注解

    如需动态刷新,需要配置以下注解
    @RefreshScope
    

    12.5 动态刷新配置

    post方式请求:http://localhost:8773/actuator/bus-refresh
    8773是当前项目的端口,如果是多个节点,其他节点也会刷新
    注意:动态刷新配置,在开发和测试环境使用,尽量少在生产环境使用
    

    ==13. 微服务改造为配置中心总结==

    13.1 码云上创建cloud-config项目,并添加对应配置文件

    微服务添加以下配置
    
    # RabbitMQ连接信息
    spring:
      rabbitmq:
        host: localhost
        port: 5672
        username: guest
        password: guest
    #暴露全部的监控信息
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    

    13.2 微服务添加pom依赖

    <!--配置中心客户端-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-client</artifactId>
    </dependency>
    <!--配置中心结合消息队列-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    

    13.3 application.yml --> bootstrap.yml

    # 服务名称
    spring:
      application:
        name: product-service
      # 指定从哪个配置中心读取
      cloud:
        config:
          discovery:
            service-id: CONFIG-SERVER # 服务ID
            enabled: true
          label: dev # dev分支
          profile: dev # 配置文件后缀
    # 注册中心
    eureka:
      client:
        serviceUrl:
          defaultZone: http://localhost:8761/eureka/
    

    13.4 各个项目启动顺序

    1. 注册中心
    2. 配置中心
    3. 各个服务:商品服务、订单服务...
    4. 启动网关
    

    相关文章

      网友评论

          本文标题:【Spring-Cloud】使用教程 基础篇 Eureka Ri

          本文链接:https://www.haomeiwen.com/subject/gthquqtx.html