SpringCloud 相关

注册中心

Eureka

导入依赖
pom.xml

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

配置文件

  • 注册中心默认端口:8761
server:
  port: 8761  # 默认端口

eureka:
  instance:
    hostname: localhost # Eureka服务端实例名称
  client:
    registerWithEureka: false # 是否向Eureka注册自己(本身就是注册中心)
    fetchRegistry: false # false 表示自己是注册中心
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 注册中心监控页面地址

spring:
  application:
    name: eureka-server

启动类

  • @EnableEurekaServer:表示为一个Eureka服务启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(EurekaServerApplication.class).run(args);
    }
}

服务注册

导入依赖

<dependencies>
        <!-- eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 完善监控信息 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- 表示为一个web服务 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.1.1</version>
        </dependency>

        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
    </dependencies>

配置文件

  • instance-id:实例化id与其他服务重名时,注册中心只能找到最后一次注册
server:
  port: 8001
spring:
  application:
    name: product-data-service
  datasource:
    username: jerel
    password: 4464984
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
# 服务注册到哪里
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ # 注册中心的地址
  instance:
    instance-id: spirngcloud-provider-user # 实例化id
# info信息(注册中心可以获取到)
info:
  app.name: user-service
  company.name: top.xiongyungang
  • 服务状态
  • 服务信息

    启动类
  • @EnableEurekaClient:在服务启动后自动注册到Eureka
@SpringBootApplication
@EnableEurekaClient
public class UserServerApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(UserServerApplication.class).run(args);
    }
}

服务保护机制

即服务宕机不会立刻在注册中心注销该服务,可在配置中关闭这种机制

服务调用

负载均衡(LB)

集中式负载均衡

在服务的消费方和提供方之间使用独立的负载均衡设施(可以是硬件,如F5,也可以是软件,如nginx),由该设施负责吧访问请求通过某中策略转发至服务的提供方

进程式负载均衡

将负载均衡逻辑集成到消费方,消费方从服务注册中心获知那些地址可用,然后自己再从这些地址中选择一个合适的服务器,例如ribbon,ribbon只是一个类库,集成在消费方进程,消费方通过它来获取到服务提供方的地址

Ribbon

  • Ribbon是Netflix下的开源项目,实现了客户端负载均衡
  • 可自定义负载均衡算法

导入依赖

  • netflix依赖中包含Ribbon
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

配置

server:
  port: 8004
spring:
  application:
    name: ribbon-view-service

# Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # 注册中心地址,多个注册中心逗号分隔
  instance:
    instance-id: springcloud--ribbon-view # 实例id

配置类

  • Ribbon默认的负载均衡算法为RandomRule(轮询方式)
@Configuration
public class ConfigBean {
    // 配置负载均衡实现restTemplate
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    // 自定义负载均衡算法
    @Bean
    public IRule myRule() {
        return new MyRandomRule();
        // return new RandomRule();  //默认轮询方式
    }

}

自定义负载均衡

  • 自定义负载均衡,实现IRole接口或继承实现了IRole接口类
  • 自定义类放在子目录中,防止被spring扫描到
    // 实现IRule
    // RandomRule: 随机策略 在while循环内,如果服务地址不为空会不停的循环直到随机出一个可用的服务
    // RoundRobinRule: 轮询策略,但是有个查找次数的限制,也就是说查了10次都是不可用的服务的话就会警告没有可用服务并返回null了,选择的方式是很简单,取余运算
    // RetryRule: 采用了轮询策略(内部直接实例化RoundRobinRule使用)的重试策略来获取可用的服务实例
    // ...
public class MyRandomRule extends AbstractLoadBalancerRule {
    private int cnt = 0;  // 服务执行次数
    private int currIndex = 0; // 当前服务索引

    public MyRandomRule() {
    }

    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;
                }
                
                // 每个服务访问两次
                //////////////////////////
                if (cnt < 2) {
                    cnt++;
                    server = upList.get(currIndex);
                } else {
                    cnt = 1;
                    currIndex++;
                    if (currIndex >= upList.size()) {
                        currIndex = 0;
                    }
                    server = upList.get(currIndex);
                }
                ////////////////////////////

                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

启动类

  • @RibbonClient:启动时加载自定义Ribbon客户端
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "PRODUCT-DATA-SERVICE", configuration = MyRule.class) //启动时加载自定义Ribbon客户端
@Controller
public class RibbonViewApplication {
    @Autowired
    RestTemplate restTemplate; // 提供多种远程调用http服务的方式,简单的restful模板

    @RequestMapping("/users")
    @ResponseBody
    public List<User> listUser() {
        // 通过服务名称来访问服务
        return restTemplate.getForObject("http://PRODUCT-DATA-SERVICE/users", List.class);
    }

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

Feign

与Ribbon的不同

  • Feign基于注解和接口
  • 集成了Ribbon

导入依赖

    <dependencies>
        <!-- eureka 客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- feign方式 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 表示web服务 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

配置

server:
  port: 8003
spring:
  application:
    name: view-service
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

配置Feign

  • @FeignClient:使用服务名称获取服务
// Feign客户端,value:调用服务的注册名称
@FeignClient(value = "PRODUCt-DATA-SERVICE")
@Component
public interface ViewClient {

    @GetMapping("/users")
    public List<User> list();
}

启动类

  • @EnableFeignClients:标记为Feign方式

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients  // Feign方式
@Controller
public class ViewServiceApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(ViewServiceApplication.class).run(args);
    }

    @Autowired
    ViewClient viewClient;

    @RequestMapping("/users")
    @ResponseBody
    public Object listUser() {
        return viewClient.list();
    }
}

路由网关Zuul

功能:提供 代理+路由+过滤功能

导入依赖

    <dependencies>
        <!-- Eureka Client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- web服务 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- zuul -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>

配置

server:
  port: 9527
spring:
  application:
    name: springcloud-zuul

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/ # 注册中心地址
  instance:
    instance-id: zuul # 实例化id
    prefer-ip-address: true # 隐藏真实ip地址
zuul:
  routes:
    myservice1: # 自定义
      serviceId: PRODUCT-DATA-SERVICE #服务实例id,大写
      path: /data/** # 路由地址
    myservice2:
      serviceId: VIEW-SERVICE
      path: /view/**
  ignored-services: "*" # 隐藏真实项目路径,*代表全部
  prefix: /roles #设置公共路由前缀

启动类

  • @EnableZuulProxy:标记为Zuul路由
@SpringBootApplication
@EnableZuulProxy //Zuul路由
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

服务熔断Hystrix

依赖

<dependencies>
        <!-- Hystrix熔断服务支持-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!-- eureka 客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- feign方式 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 表示web服务 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

配置

server:
  port: 8003
spring:
  application:
    name: view-service
feign:
  hystrix:
    enabled: true  # 开启服务熔断
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/ # 注册中心地址
  instance:
    instance-id: springcloud-hystrix-view # 实例化id
    prefer-ip-address: true # 隐藏真实ip地址

对类的熔断

模拟调用服务宕机

  • @FeignClient注解的fallback指定一个实现当前接口的类,在服务调用失败时,调用该类的方法实现
// Feign客户端,value:调用服务的注册名称, fallback 熔断类
@FeignClient(value = "PRODUCt-DATA-SERVICE", fallback = ViewHystrixClient.class)
@Component
public interface ViewClient {

    @GetMapping("/users")
    Object list();
}

熔断类

  • 实现了ViewClient接口,服务调用失败时调用该类方法实现
// 服务熔断后的备选方案
@Component
public class ViewHystrixClient implements ViewClient {

    public Object list(){
        return "server error";
    }
}

启动类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients  // Feign方式
@Controller
public class ViewHystrixServiceApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(ViewHystrixServiceApplication.class).run(args);
    }

    @Autowired
    ViewClient viewClient;

    @RequestMapping("/users")
    @ResponseBody
    public Object listUser() {
        return viewClient.list();
    }
}

对方法的熔断

启动类

  • @EnableCircuitBreaker :对熔断的支持
  • @HystrixCommand(fallbackMethod = "hystrix"):当前方法执行异常时跳转到指定方法实现
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients  // Feign方式
@Controller
@EnableCircuitBreaker // 对熔断的支持
public class ViewHystrixServiceApplication {
    public static void main(String[] args) {
        new SpringApplicationBuilder(ViewHystrixServiceApplication.class).run(args);
    }

    @RequestMapping("/getUser")
    @HystrixCommand(fallbackMethod = "hystrix")
    @ResponseBody
    public Object getuser() {
        int id = 11;
        if (id > 10) {
            // 模拟故障
            throw new RuntimeException("server error");
        }
        // 使用模拟数据
        return new User(id, "testUser", "", "", "", "");
    }

    public Object hystrix() {
        return "server error";
    }
}

posted @ 2020-11-08 00:44  熊云港  阅读(79)  评论(0编辑  收藏  举报