xmtrock
发布于 2021-07-15 / 345 阅读
0

Eureka

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>
server.port=9000
#配置eurekaserver
eureka.instance.hostname=localhost
#是否将自己注册到注册中心
eureka.client.register-with-eureka=true
#是否从eureka中获取注册信息
eureka.client.fetch-registry=false
#配置暴露给Eureka Client的请求地址
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
@EnableEurekaServer

然后能正常访问http://localhost:9000/就说明没问题

简单producter、consumer

spring:
  application:
    name: eureka-server
server:
  port: 9000 #端口
#配置eureka server
eureka:
  client:
    register-with-eureka: false #是否将自己注册到注册中心
    fetch-registry: true #是否从eureka中获取注册信息
    service-url: #配置暴露给Eureka Client的请求地址
      defaultZone: http://localhost:9000/eureka/
  server:
    enable-self-preservation: false #关闭自我保护
    eviction-interval-timer-in-ms: 4000 #剔除服务间隔
server:
  port: 9001 #端口
spring:
  application:
    name: service-product #服务名称
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456
  jpa:
    database: MySQL
    show-sql: true
    open-in-view: true
#配置Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/ #多个eurekaserver之间用,隔开
  instance:
    prefer-ip-address: true #使用ip地址注册
server:
  port: 9002 #端口
spring:
  application:
    name: service-order #服务名称
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/shop?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8
    username: root
    password: 123456
  jpa:
    database: MySQL
    show-sql: true
    open-in-view: true
#配置Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册

provider、consumer可以不需要配置启动类
20210715040745354

简单例子

@Bean
public RestTemplate restTemplate() { return new RestTemplate(); }
@RestController
@RequestMapping("/order")
public class OrderController {

    //注入restTemplate对象
    @Resource
    private RestTemplate restTemplate;

    /**
     * 注入DiscoveryClient : springcloud提供的获取原数组的工具类 调用方法获取服务的元数据信息
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * 参数:商品id
     *  通过订单系统,调用商品服务根据id查询商品信息
     *      1.需要配置商品对象
     *      2.需要调用商品服务
     *  使用java中的urlconnection,httpclient,okhttp
     */
   @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        //调用discoveryClient方法
        //已调用服务名称获取所有的元数据
        List<ServiceInstance> instances = discoveryClient.getInstances("service-product");
        //获取唯一的一个元数据
        ServiceInstance instance = instances.get(0);
        //根据元数据中的主机地址和端口号拼接请求微服务的URL
        Product product = null;
        //如何调用商品服务?
        product = restTemplate.getForObject("http://" + instance.getHost() + ":" + instance.getPort() + "/product/1", Product.class);
        return product;
    }
}

上面是生产者,下面的消费者:

@RestController
@RequestMapping("/product")
public class ProductController {

   @Autowired
   private ProductService productService;

   @Value("${server.port}")
   private String port;

   @Value("${spring.cloud.client.ip-address}") //spring cloud 自动的获取当前应用的ip地址
   private String ip;

   @RequestMapping(value = "/{id}",method = RequestMethod.GET)
   public Product findById(@PathVariable Long id) {
      Product product = productService.findById(id);
      product.setProductName("访问的服务地址:"+ip + ":" + port);
      return product;
   }

   @RequestMapping(value = "",method = RequestMethod.POST)
   public String save(@RequestBody Product product) {
      productService.save(product);
      return "保存成功";
   }
}

order在9002,product在9001
20210715042318807

高可用

集群相互注册,复制值configuration,一个port9000zone8000,另一port8000zone9000

eureka:
  client:
    register-with-eureka: true #是否将自己注册到注册中心
    fetch-registry: true #是否从eureka中获取注册信息
    service-url: #配置暴露给Eureka Client的请求地址
      defaultZone: http://localhost:8000/eureka/
  server:
    enable-self-preservation: false #关闭自我保护
    eviction-interval-timer-in-ms: 4000 #剔除服务间隔

20210715095856419
20210715100448093
微服务注册到多个集群上。避免其中一个down掉后另一个无法得知服务状态

#配置Eureka
eureka:
  client:
    service-url: #多个eurekaserver之间用,隔开
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册
    #    instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id
    #lease-renewal-interval-in-seconds: 5 #向注册中心中注册服务id
    # lease-expiration-duration-in-seconds: 10 #续约到期的时间

优化、用ip注册:

#配置Eureka
eureka:
  client:
    service-url: #多个eurekaserver之间用,隔开
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id

优化:心跳间隔,续约到期时间
(如果Eureka在10秒内检测不到我,那么就说明我挂了,所以我每5秒就向Eureka发送一次心跳)

#配置Eureka
eureka:
  client:
    service-url: #多个eurekaserver之间用,隔开
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册
    instance-id: ${spring.cloud.client.ip-address}:${server.port} #向注册中心中注册服务id
    lease-expiration-duration-in-seconds: 10 #续约到期的时间
    lease-renewal-interval-in-seconds: 5 #向注册中心中注册服务id

优化:关闭自我保护,剔除服务间隔

#配置eureka server
eureka:
  client:
    register-with-eureka: false #是否将自己注册到注册中心
    fetch-registry: false #是否从eureka中获取注册信息
    service-url: #配置暴露给Eureka Client的请求地址
      defaultZone: http://localhost:9000/eureka/
  server:
    enable-self-preservation: false #关闭自我保护
    eviction-interval-timer-in-ms: 4000 #剔除服务间隔

Springboot自动装载

@Data
public class User {
   private String username;
   private Integer age;
}
public class UserConfiguration {
   @Bean
   public User getUser() {
      User user = new User();
      user.setAge(23);
      user.setUsername("腼腆Hold");
      return user;
   }
}
public class UserImportSelector implements ImportSelector {
   //@Configuration
   public String[] selectImports(AnnotationMetadata annotationMetadata) {
      //获取配置类的名称
      return new String[]{UserConfiguration.class.getName()};
   }
}
@Retention(RetentionPolicy.RUNTIME) //什么时候运行
@Documented //这个注解应该被 javadoc工具记录
@Target(ElementType.TYPE) //配置到什么地方
@Import(UserImportSelector.class) //自动加载selector
public @interface EnableUserBean {
}

然后测试

@EnableUserBean
public class TestApplication {
   /**
    *   --> EnableUserBean --> UserImportSelector --> UserConfiguration --> User
    * @param args
    */
   public static void main(String[] args) {
      //获取spring容器
      AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestApplication.class);
      User bean = ac.getBean(User.class);
      System.out.println(bean);
   }
}

ImportSelector接口是Spring导入外部配置的核心接口,在SpringBoot的自动化配置和@EnableXXX中气到决定性作用。(P25自动配置原理)
20210715142734251

Ribbon

负载均衡器,有助于控制HTTP和TCP客户端行为。一般Eureka都是配合Ribbon使用的
服务调用:在创建RestTemplate时,声明@LoadBalanced,使用restTemplate时就不需要再拼接微服务的URL了,以请求的服务名来代替(注意不要自定义instance-id)

#配置eureka server
eureka:
  client:
    register-with-eureka: false #是否将自己注册到注册中心
    fetch-registry: false #是否从eureka中获取注册信息
    service-url: #配置暴露给Eureka Client的请求地址
      defaultZone: http://localhost:9000/eureka/
  server:
    enable-self-preservation: false #关闭自我保护
    eviction-interval-timer-in-ms: 4000 #剔除服务间隔
#配置Eureka
eureka:
  client:
    service-url: #多个eurekaserver之间用,隔开
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册
    lease-expiration-duration-in-seconds: 10 #续约到期的时间
    lease-renewal-interval-in-seconds: 5 #向注册中心中注册服务id
#配置Eureka
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9000/eureka/,http://localhost:8000/eureka/
  instance:
    prefer-ip-address: true #使用ip地址注册

使用consumer:

@LoadBalanced
@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}
//注入restTemplate对象
@Resource
private RestTemplate restTemplate;

/**
 * 基于ribbon的形式调用远程微服务
 * 1.使用@LoadBalanced声明RestTemplate
 * 2.使用服务名称替换ip地址
 */
@RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
    Product product = null;
    product = restTemplate.getForObject("http://service-product/product/1", Product.class);
    return product;
}

使用producer:

@RestController
@RequestMapping("/product")
public class ProductController {
    @Autowired
    private ProductService productService;
    @Value("${server.port}")
    private String port;
    @Value("${spring.cloud.client.ip-address}") //spring cloud 自动的获取当前应用的ip地址
    private String ip;

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        Product product = productService.findById(id);
        product.setProductDesc("访问的服务地址:" + ip + ":" + port);
        return product;
    }
}

负载均衡:把一个典型的客户端负载均衡器,Ribbon会获取服务的所有地址,根据内部的负载均衡算法,获取本次请求的有效地址。
单机测试:只需复制configuration,改端口模拟运行两个producer,那么Eureka就会显示有两个同名的服务。
只要consumer配置了@LoadBalanced,默认可无需多做配置,它自动完成负载。(默认是轮循方式的)
如何修改负载策略?

#修改ribbon的负载均衡策略,服务名 - ribbon - NFLoadBalancerRuleClassName: 策略
service-product:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

com.netflix.loadbalancer.RoundRobinRule :以轮询的方式进行负载均衡。
com.netflix.loadbalancer.RandomRule :随机策略
com.netflix.loadbalancer.RetryRule :重试策略。
com.netflix.loadbalancer.WeightedResponseTimeRule :权重策略。会计算每个服务的权重,越高的被调用的可能性越大。
com.netflix.loadbalancer.BestAvailableRule :最佳策略。遍历所有的服务实例,过滤掉故障实例,并返回请求数最小的实例返回。
com.netflix.loadbalancer.AvailabilityFilteringRule :可用过滤策略。过滤掉故障和请求数超过阈值的服务实例,再从剩下的实力中轮询调用。

请求重试:实现访问失败的话重试一次,若不成功则切换其他同service的服务

#修改ribbon的负载均衡策略   服务名 -  ribbon - NFLoadBalancerRuleClassName : 策略
service-product:
  ribbon:
    #NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    ConnectTimeout: 250 # Ribbon的连接超时时间
    ReadTimeout: 1000 # Ribbon的数据读取超时时间
    OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
    MaxAutoRetries: 1 # 对当前实例的重试次数
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>