乐优商城第三天(springcloud下)

现在是第三天之前的晚上。第三天到来之前,先来一手预习。哈哈哈,预习以下,上课应该会轻松一点。。。。。

第二天,我们学习了注册中心Eureka,接下来我们还要学习四个核心组件。

Eureka详解

  • eureka的高可用

为了Eureka的高可用,我们一般会有多台Eureka,他们是听过互相注册的方式知道彼此的存在的

server:
  port: 10086 # 端口
spring:
  application:
    name: eureka-server # 应用名称,会在Eureka中显示
eureka:
  client:
    service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
      defaultZone: http://127.0.0.1:10087/eureka
    registry-fetch-interval-seconds: 10 #消费者每10秒拉取服务缓存到本地,生产环境不用改

Eureka对于失效不是立即剔除的,而是通过每隔60s的轮询,就是每60秒剔除一次。

那么,这个时候,客户端注册服务的时候就要注册多个Eureka

eureka:
  client:
    service-url: # EurekaServer地址
      defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka

总结:实现eureka高可用的方式就是多个eureka互相注册,客户端注册所有的eureka。

  • 服务提供者和eureka的续约

服务和eureka是通过续约的方式进行的,服务每隔30s向eureka发送一个心跳(数据包),证明自己还活着。由于网络波动的原因,可能有时候没有接受到心跳,eureka不会立即剔除服务,而是再给服务几次机会,如果90s内服务还没有消息,那么eureka会认为服务已死,但是eureka不会立即剔除服务,因为eureka的剔除机制是轮询,每隔60秒剔除一次死掉的服务。

instance:
  lease-expiration-duration-in-seconds: 10 # 10秒即过期
  lease-renewal-interval-in-seconds: 5 # 5秒一次心跳

  • 消费者拉取eureka的服务

消费者每隔30s拉取一次服务

eureka:
  client:
    registry-fetch-interval-seconds: 10

  • eureka的剔除机制

每隔60s剔除一次(默认)

server:
    enable-self-preservation: false # 关闭自我保护模式(缺省为打开)
    eviction-interval-timer-in-ms: 10000 # 扫描失效服务的间隔时间

总结:各司其职,服务隔一段时间就续约,消费者隔一段时间就更新服务,eureka隔一段时间就剔除坏掉的服务。

  • eureka的自我保护
有时候因为网络波动,会出现大量的没有续约的情况,这个时候,如果大量剔除服务,会产生灾难。eureka的解决办法是,他会统计最近15分钟续约失败的服务的比例,如果这个值超过85%,eureka会认为现在是网络波动,他并不会剔除服务,而是会把他们保护起来。
  • robbin 负载均衡
  • Hystix 熔断器
  • Feign 服务消费者
  • zuul 门神

一.robbin 负载均衡

首先回顾以下昨天的注册中心,我们客户端发送请求,会到注册中心拉取服务者,是一个集合,如果要实现负载均衡,我们可以自己编码,实现轮询或者随机,知识我们自己的方式。

而我们知道每一个服务提供者和消费者都是一个客户端,都需要引入Eureka的依赖,而Eureka给我们提供了负载均衡的算法,不需要我们自己提供,我们只需要在restTemplate上添加一个注解即可。

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

这样就可以实现负载均衡,默认算法是轮询算法,我们可以在配置文件中修改算法。

有了负载均衡后,我们就不用自己写负载均衡算法了,下面是之前的写法

List< ServiceInstance> instances = discoveryClient. getInstances( "USER-SERVICE");
ServiceInstance serviceInstance = instances. get( 0);
String url = "http://"+ serviceInstance. getHost()+ ":"+ serviceInstance. getPort()+ "/hello/user/" + id;

现在,我们的写法是这样的,负载均衡的底层回去eureka中去拉取服务

String url = "http://user-service/hello/user/" + id;
User user = restTemplate.getForObject(url, User.class);

下面的算法是随机的算法,默认是轮询,下面这种写法是随机算法

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡

  • 重试机制

Eureka的服务治理强调了CAP原则中的AP,即可用性和可靠性。它与Zookeeper这一类强调CP(一致性,可靠性)的服务治理框架最大的区别在于:Eureka为了实现更高的服务可用性,牺牲了一定的一致性,极端情况下它宁愿接收故障实例也不愿丢掉健康实例,正如我们上面所说的自我保护机制。

    因为Eureke的特性,如果一个服务出现故障,不会立即将他剔除,这样,我们访问的时候,就有可能出现访问不到的情况,这样就会出现错误页面,这时候,有一个新的机制,重试机制,保证了我们在访问不到的时候,可以跳转到另一台机器上。

重试机制是在负载均衡的基础上实现的,因为只有负载均衡后,我们才会不确定会访问到哪一台机器,这样,我们访问的机器有时候就是坏掉的,我们需要一个重试机制,把我们定向到其他机器上。

    因此Spring Cloud 整合了Spring Retry 来增强RestTemplate的重试能力,所以,我们需要先引入依赖

<dependency>
   <groupId>org.springframework.retry</groupId>
   <artifactId>spring-retry</artifactId>
</dependency>

依赖的版本springcloud已经帮助我们管理好了。

接下来我们要在配置文件中告诉我们的robbin需要怎么去重试

首先开启重试功能

spring:
  application:
    name: consumer
  cloud:
    loadbalancer:
      retry:
        enabled: true # 开启Spring Cloud的重试功能
配置重试功能的具体信息

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡
    ConnectTimeout: 250 # Ribbon的连接超时时间
    ReadTimeout: 1000 # Ribbon的数据读取超时时间
    OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
    MaxAutoRetries: 1 # 对当前实例的重试次数

二.Hystix

熔断器会设置一个超时时间,默认是1s,如果超时,会熔断,返回一个友好的页面

首先,导入依赖

<!--引入hystix熔断器依赖-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

第二步,添加注解

@EnableHystrix
@EnableFeignClients
public class CouldCustomerApplication {

第三步,在具体的方法上启用熔断,并且写一个熔断后的方法

@HystrixCommand(fallbackMethod = "queryUserFullBack")
public User queryUserById(Long id) {

第四步,在配置文件中配置熔断实现的具体细节,设置熔断生效的时间

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000

完成这四步,就可以实现熔断了。我们一般将熔断的时间设置的比重试的时间大一点,先重试,再熔断。

三.fegin 伪装

fegion就像通用mapper一样,他的出现就是为了省略代码,通过动态代理。

这是直接用负载均衡和熔断的功能

@HystrixCommand(fallbackMethod = "queryUserFullBack")
public User queryUserById(Long id) {
    //记录时间
    Long start = System.currentTimeMillis();
    String url = "http://user-service/hello/user/" + id;
    User user = restTemplate.getForObject(url, User.class);
    //将响应的json解析成对象
    Long end = System.currentTimeMillis();
    logger.info("查询一共消耗时间{"+(end-start)+"}ms");
    return user;
}

我们的feign直接继承了Hystix和robbin,怎么使用 feign呢?

第一步,引入依赖

<!--引入feign依赖-->
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

第二步,开启feign客户端一,feign继承了robbin,不用再写restTemplate了

@EnableFeignClients
public class CouldCustomerApplication {

第三步,编写一个接口,里面包含服务名等信息

@FeignClient(value = "user-service",path = "hello/user",fallback= UserFeignClientFallback.class )
public interface UserFeignClient  {
    @GetMapping("{id}")
    User queryUserById(@PathVariable("id") Long id);
}

第四步,在service层直接使用fegin,fegin中自带了ribbun负载均衡

@Autowired
    private UserFeignClient userFeignClient;

第五步,熔断的使用,在接口中先定义一个熔断的方法,写一个类继承这个方法,并将方法交给ioc管理

@Component
public class UserFeignClientFallback implements UserFeignClient {
    @Override
    public User queryUserById(Long id) {
        User user = new User();
        user.setId(id);
        user.setName("用户查询出现异常!");
        return user;
    }
}

第六步,配置文件的配置。ribbon可以跟以前一样的配置,但是这里要额外开启Hystix,要不然没法开启,因为没用feign之前是注解的方式开启的

user-service:
  ribbon:
  #  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #负载均衡
    ConnectTimeout: 250 # Ribbon的连接超时时间
    ReadTimeout: 1000 # Ribbon的数据读取超时时间
    OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
    MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
    MaxAutoRetries: 1 # 对当前实例的重试次数

#开启feign的熔断
feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能

另外,feign还有其他额外的功能,对请求进行压缩,减小过程损耗

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
    response:

      enabled: true # 开启响应压缩

还可以对请求的数据类型,还有启动压缩下限的大小进行设置

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型

      min-request-size: 2048 # 设置触发压缩的大小下限


feign还有一个坑爹的地方,就是之前配置日志的方式会不起作用,理由如下:


feign是这样就行配置的

首先,我们要写一个配置类,设定配置的级别

@Configuration
public class FeignConfig {
    @Bean
    Logger.Level feignLoggerLevel(){
        return Logger.Level.FULL;
    }

}

然后,我们开启fegin客户端的地方,设置这个配置

@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class, configuration = FeignConfig.class)
public interface UserFeignClient {
    @GetMapping("/user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}

这样,就可以自定义日志的使用级别了。


四。zuul

守门员,网关

第一步,引入依赖

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

二.在启动程序上用注解开启配置

@EnableZuulProxy
@EnableEurekaClient
public class ZuulDemoApplication {

三,在配置文件中配置eureka

zuul:
  prefix: /api # 配置前缀,标记通过zuul的链接
  routes:
    user-service: /user/** #配置服务,链接中有user的都会被代理到user-service

当然,eureka的默认配置也是少不了的,引入zuul要到eureka中去拉取服务

Eureka
eureka:
  client:
    registry-fetch-interval-seconds: 5 # ��ȡ�����б�����ڣ�5s
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

zuul还有一个重要的功能就是过滤器,实现过滤器要继承zuulFilter,并将过滤器交给ioc管理即可

@Component
public class LoginFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {

filterType是前置过滤的意思,filterOrder是过滤器的等级,一些内置的过滤器等级一般比较高,是-1,-2之类的

shouldFilter代表是否拦截的意思,run方法中写的是具体的拦截方法。

我们在这里写了一个登陆拦截的小demo

RequestContext ctx = RequestContext.getCurrentContext();
// 2) 从上下文中获取request对象
HttpServletRequest req = ctx.getRequest();
// 3) 从请求中获取token
String token = req.getParameter("access-token");
// 4) 判断
if(token == null || "".equals(token.trim())){
    // 没有token,登录校验失败,拦截
    // 返回401状态码。也可以考虑重定向到登录页。
    ctx.setResponseStatusCode(401);
    ctx.setSendZuulResponse(false);
}
// 校验通过,可以考虑把用户信息放入上下文,继续向后执行
return null;

zuul中负载均衡和熔断的配置

zuul:
  retryable: true
ribbon:
  ConnectTimeout: 250 # 连接超时时间(ms)
  ReadTimeout: 2000 # 通信超时时间(ms)
  OkToRetryOnAllOperations: true # 是否对所有操作重试
  MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
  MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
  command:
    execution:
      isolation:
        thread:

          timeoutInMillisecond: 6000 # 熔断超时时长:6000ms



其他:调整每个项目所占内存的大小

-Xms128m -Xmx128m


猜你喜欢

转载自blog.csdn.net/qpc672456416/article/details/80412387