电商系统中的线程隔离技术

JAVA herman 296浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

别被标题迷糊了,隔离技术不光在电商系统中使用,而是大量的在各分布式系统中存在。今天我们就一起来聊一个最简单的线程隔离技术。

线程隔离技术,也称是线程池隔离技术。最著名的使用者算 Hystrix 了。Hystrix 提供了两种隔离策略,分布式:线程隔离和信号量隔离。Hystrix 默认的隔离技术就是线程池隔离,因为隔离技术有一个除网络超时以外的额外保护层。

  • THREAD(线程隔离):使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中线程数量的限制。
  • SEMAPHORE(信号量隔离):使用该方式,HystrixCommand将会在调用线程上执行,开销相对较小,并发请求受信号量的个数的限制。

之所以,信号量隔离 SEMAPHORE 不是 Hystrix 的首选(默认隔离)的原因是,信号量隔离一般仅适用于非网络调用的隔离。比如,操作内存等。而对于跨网络的,调用负载非常高的(例如每个实例每秒调用数百次)才需要使用信号量隔离,因为这种场景下使用 THREAD 开销会比较高。

所谓的线程隔离主要有线程池隔离,在实际使用时我们会把请求分类,然后交给不同的线程池处理,当一种业务的请求处理发生问题时,不会将故障扩散到其他线程池,从而保证其他服务可用。

打个比方,在我们的电商系统中,假设现在有 3 个业务调用分别是查询订单、查询商品、查询用户,且这三个业务请求都是依赖第三方服务-订单服务、商品服务、用户服务。三个服务都需要跨网络请求调用,可以是 RPC 调用,也可以是 Rest 的 HTTP 调用。当查询订单服务出现故障时,假如线程阻塞了,这个时候后续有大量的查询订单请求过来,那么容器中的线程数量则会持续增加直致 CPU 资源耗尽到 100%,整个服务对外不可用,集群环境下就是雪崩。

线程隔离

如果这个故障进行隔离,那么最终回导致当前业务提供的服务也不可以使用。

故障蔓延

如果通过线程隔离,那么就可以避免这种情况。通过设置线程池大小来控制并发访问量,当线程饱和的时候可以拒绝服务,防止依赖问题扩散。

故障隔离

对于电商系统来说,如果不做隔离,对于整个系统来说简直就是灾难。故障一秒,损失的就是钱啊。

对于 Hystrix 来说,用它来做服务隔离,是在简单不过了。看下面的代码:

package com.xttblog.hystrix.threadpool;
import com.netflix.hystrix.*;
import org.junit.Test;
import java.util.List;
import java.util.concurrent.Future;
public class GetOrderCommand extends HystrixCommand<List> {
    OrderService orderService;
    public GetOrderCommand(String name){
        super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ThreadPoolXttblogGroup"))
            .andCommandKey(HystrixCommandKey.Factory.asKey("testCommandKey"))
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(name))
            .andCommandPropertiesDefaults(
                HystrixCommandProperties.Setter()
                    .withExecutionTimeoutInMilliseconds(5000)
            )
            .andThreadPoolPropertiesDefaults(
                HystrixThreadPoolProperties.Setter()
                    .withMaxQueueSize(10)   //配置队列大小
                    .withCoreSize(2)    // 配置线程池里的线程数
            )
        );
    }
    @Override
    protected List run() throws Exception {
        return orderService.getOrderList();
    }
    public static class UnitTest {
        @Test
        public void testGetOrder(){
            //new GetOrderCommand("xttblog-order").execute();
            Future<List> future =new GetOrderCommand("xttblog-order").queue();
        }

    }
}

线程隔离的优点:

  • 一个服务可以给予一个线程池,这个服务的异常不会影响其他的依赖。
  • 使用线程可以完全隔离第三方代码,请求线程可以快速放回。
  • 当一个失败的服务再次变成可用时,线程池将清理,并立即恢复可用,而不是一个长时间的恢复。
  • 可以完全模拟异步调用,方便异步编程。
  • 使用线程池,可以有效的进行实时监控、统计和封装。

线程隔离的缺点:

  • 使用线程池的缺点主要是增加了计算的开销。每一个依赖调用都会涉及到队列,调度,上下文切换,而这些操作都有可能在不同的线程中执行。

尽管有了线程隔离,但是并不意味着我们的代码可以随便写。必要的规范,超时机制还是要有的。

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » 电商系统中的线程隔离技术