会做一个静态化页面,直接返回给用户,不涉及业务,所以返回时间特别快,如图所示。
这坏处在于只是使用一些小型的网站,几百几千到几万的商品数据。如果一些大型网站,商品数量几亿数量级,那么将这些数据全都静态化,肯定是不现实的。
一般会有一个缓存服务,进行部分数据的主动更新,然后再进行渲染。那么这个架构的核心就是缓存服务,接收到消息之后,如何保证其会获取到底层的数据。如果依赖的底层服务失败、拒绝、超时怎么办,可能会导致商品页面显示不出来数据,该如何保证这个架构的高可用性。
如果我们的服务是接收处理所有的请求,那么如果大量的请求同时涌入的话,就很可能会造成资源耗尽而导致系统崩溃,如果用线程池来进行流量的一个管控,如果请求达到了线程池的上线,就直接拒绝请求或者进行fallback的服务降级,那么就相当于拦截了多出来的请求,不至于让我们的系统过载,出现故障。而且线程池可以对线程进行管控,检测请求是否超时之类的错误。
线程池隔离技术适用于99%的资源隔离和限流场景。
信号量隔离限流信号量就相当于一个关卡,每接到一个请求就记录一下,如果请求量达到上线,就直接让其请求fallback降级服务。那么这样也可以做到一个资源隔离和限流的功能。与线程池最大的区别就是,线程池是用自己的线程去进行依赖访问,而信号量是作为一个关卡将用户的请求线程进行放行或者拒绝。所以也不能对请求进行监控,检测请求是否超时之类的错误。
信号量隔离使用于内部资源隔离和限流的场景,因为不需要进行超时之类的统计,不涉及任何的网络请求,只是避免内部复杂的低效率代码hang主大量线程。
比如一些地理位置我们可能放在纯内存中,那么就可以使用信号量进行资源隔离和限流,优点在于不用自己管理线程池,并且性能还高一些。
Hrstrix的Command线程池通过设置线程组和线程名称来实现线程池和信号量的隔离。
command group 是一个非常重要的概念,默认情况下就是通过command group来定义一个线程池,还会通过这个command group来聚合一些监控和报警信息,只要是通过同一个command group的请求都会到同一个线程池中。如果没有手动定义hrstrixThreadpool线程池的名称,那么会默认使用command group来作为hrstrix线程池的名称
command key代表了一个依赖接口;command group代表了一类依赖服务
coreSize,线程池的大小,默认为10,通过HystrixThreadPoolProperties.Setter().withCoreSize(Integer vlaue) 来设置。
-
创建command,构建一个HrstrixCommand或者HrstrixObservableCommand对象,HrstrixCommand主要用于仅仅会返回一个结果的调用,HrstrixObservableCommand用于会返回多个结果的调用。
-
调用Command执行方法,execute()、queue()、observe()、toObservable()。
execute():只适用于HrstrixCommand,同步调用,调用后block等待返回结果。
queue():只适用于HrstrixCommand,异步调用,调用后通过Future获取结果。
observe():订阅一个Observable对象,获取结果
toObservable():延迟调用,调用后不会返回,订阅Observable对象后才会返回。 -
检查是否开启缓存,如果有缓存那么直接返回数据
-
是否开启断路器,如果开启证明依赖不可用,直接调用fallback服务降级
-
检查线程队列是否满了,满的话调用fallback服务降级
-
执行Command
-
短路健康检查,统计服务失败、超时次数,判断是否需要开启短路器
-
如果调用了fallback,那么执行降级服务,返回结果
通过过滤器Filter来实现,每次接受请求的时候都会建立一个上下文内容request context并且设置生命周期,那么每次通过Command调用依赖的时候都会检测请求值是否已经存在,如果存在则直接返回 request cache中的数据,不需要多次请求依赖服务。
fallback降级机制Hrstrix调用各种外部依赖的时候,出现了异常情况报错的话,就自定义一个默认值或者内存的返回值。