-
读写隔离
-
动静隔离
-
爬虫隔离
-
等等
线程隔离
网络上很多帖子,大多是从框架开始聊的,这儿说人话其实就是对线程进行治理,把核心业务线程与非核心业务线程隔开,不同的业务需要的线程数量不同,可以设置不同的线程池,来举一些框架中应用的例子,例如Netty中的主从多线程、Tomcat请求隔离、Dubbo线程模型。
Netty主从程模型
主线程负责认证,连接,成功之后交由从线程负责连接的读写操作,大致如下代码:
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup);
主线程是一个单线程,从线程是一个默认为cpu*2个数的线程池,可以在我们的业务handler中做一个简单测试:
public void channelRead(ChannelHandlerContext ctx, Object msg) {
System.out.println(“thread name=” + Thread.currentThread().getName() + " server receive msg=" + msg);
}
服务端在读取数据的时候打印一下当前的线程:
thread name=nioEventLoopGroup-3-1 server receive msg=“…”
可以发现这里使用的线程其实和处理io线程是同一个;
Dubbo线程隔离模型
Dubbo的底层通信框架其实使用的就是Netty,但是Dubbo并没有直接使用Netty的io线程来处理业务,可以简单在生产者端输出当前线程名称:
thread name=DubboServerHandler-192.168.1.115:20880-thread-2,…
可以发现业务逻辑使用并不是nioEventLoopGroup线程,这是因为Dubbo有自己的线程模型,可以看看官网提供的模型图:
由图可以知道,Dubbo服务端接收到请求后,通过调度器(Dispatcher)分发到不同的线程池,也简单做一些关于调度器(Dispatcher)总结:
Dispatcher调度器可以配置消息的处理线程:
-
all
所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。 -
direct
所有消息都不派发到线程池,全部在 IO 线程上直接执行。 -
message
只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在 IO 线程上执行。 -
execution
只有请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在 IO 线程上执行。 -
connection
在 IO 线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
通过看源码可以知道,Dubbo默认使用的线程池是FixedThreadPool ,线程数默认为200 ;
Tomcat请求线程隔离
Tomcat是Servelet的具体实现,在Tomcat请求支持四种请求处理方式分别为:BIO、AIO、NIO、APR
BIO模式:阻塞式I/O操作,表示Tomcat使用的是传统Java。I/O操作(即Java.io包及其子包)。Tomcat7以下版本默认情况下是以bio模式运行的,由于每个请求都要创建一个线程来处理,线程开销较大,不能处理高并发的场景,在几种模式中性能也最低。
NIO模式:同步非阻塞I/O操作,是一个基于缓冲区、并能提供非阻塞I/O操作的API,它拥有比传统I/O操作具有更好的并发性能。
在Tomcat7版本之后,Tomcat把连接介入和业务处理拆分成两个线程池来处理,即:
可以使用独立的线程池来维护servlet的创建。连接器connector能介入的请求肯定比业务复杂的servlet处理的个数要多,在中间,Tomcat加入了队列,来等待servlet线程池空闲。这两步是Tomcat内核完成的,在一阶段无法区分具体业务或资源,所以只能在连接介入,servlet初始化完成后我们根据自己的业务线去划分独立的连接池。
这样做,独立的业务或资源中如果出现崩溃,不会影响其他的业务线程,从而达到资源隔离和服务降级的效果。
在使用了servlet3之后,系统线程隔离变得更灵活了。可以划分核心业务队列和非核心业务队列:
线程隔离小总结
-
资源一旦出现问题,虽然是隔离状态,想要让资源重新可用,很难做到不重启jvm。
-
线程池内部线程如果出现OOM、FullGC、cpu耗尽等问题也是无法控制的
-
线程隔离,只能保证在分配线程这个资源上进行隔离,并不能保证整体稳定性
进程隔离
进程隔离这种思想其实并不陌生,Linux操作系统中,利用文件管理系统将各个进程的虚拟内存与实际的物理内存映射起来,这样做的好处是避免不同的进程之间相互影响,而在分布式系统中,线程隔离不能完全隔离故障避免雪崩,例如某个线程组耗尽内存导致OOM,那么其他线程组势必也会受影响,所以进程隔离的思想是,CPU、内存等等这些资源也通过不同的虚拟机来做隔离。
具体操作是,将业务逻辑进行拆分成多个子系统(拆分原则可以参考:Redis集群拆分原则之AKF),实现物理隔离,当某一个子系统出现问题,不会影响到其他子系统。
集群隔离
如果系统中某个业务模块包含像抢购、秒杀、存储I/O密集度高、网络I/o高、计算I/O高这类需求的时候,很容易在并发量高的时候因为这种功能把整个模块占有的资源全部耗尽,导致响应编码甚至节点不可用。
像上图的的拆分之后,如果某一天购物人数瞬间暴增,电商交易功能模块可能受影响,损坏后导致电商模块其他的浏览查询也无法使用,因此就要建立集群进行隔离,具体来说就是继续拆分模块,将功能微服务化。
解决方案
-
独立拆分模块
-
微服务化
可以使用hystrix在微服务中隔离分布式服务故障。他可以通过线程和信号量进行隔离。
线程池隔离与信号量隔离对比
这儿同上面的线程隔离,不多赘述,简单叙述一下hystrix的两种隔离方式的区别:
| 隔离方式 | 是否支持超时 | 是否支持熔断 | 隔离原理 | 是否是异步调用 | 资源消耗 |
| :-- | :-- | :-- | :-- | :-- | :-- |
| 线程池隔离 | 支持,可直接返回 | 支持,当线程池到达maxSize后,再请求会触发fallback接口进行熔断 | 每个服务单独用线程池 | 可以是异步,也可以是同步。看调用的方法 | 大,大量线程的上下文切换,容易造成机器负载高 |
| 信号量隔离 | 不支持,如果阻塞,只能通过调用协议(如:socket超时才能返回) | 支持,当信号量达到maxConcurrentRequests后。再请求会触发fallback | 通过信号量的计数器 | 同步调用,不支持异步 | 小,只是个计数器 |
信号量隔离
说人话就是,很多线程涌过来,要去获得信号量,获得了才能继续执行,否则先进入队列等待或者直接fallback回调
最重要的是,信号量的调用是同步的,也就是说,每次调用都得阻塞调用方的线程,直到结果返回。这样就导致了无法对访问做超时(只能依靠调用协议超时,无法主动释放)
官网对信号量隔离的描述建议
- Generally the only time you should use semaphore isolation for
HystrixCommand
s is when the call is so high volume (hundreds per second, per instance) that the overhead of separate threads is too high; this typically only applies to non-network calls.
理解下两点:
-
隔离的细粒度太高,数百个实例需要隔离,此时用线程池做隔离开销过大
-
通常这种都是非网络调用的情况下
机房隔离
机房隔离主要目的有两个,一方面是将不同区域的用户数据隔离到不同的地区,例如湖北的数据放在湖北的服务器,浙江的放在浙江服务器,等等,这样能解决数据容量大,计算密集,i/o(网络)密集度高的问题,相当于将流量分在了各个区域。
另一方面,机房隔离也是为了保证安全性,所有数据都放在一个地方,如果发生自然灾害或者爆炸等灾害时,数据将全都丢失,所以把服务建立整体副本(计算服务、数据存储),在多机房内做异地多活或冷备份、是微服务数据异构的放大版本。
如果机房层面出现问题的时候,可以通过智能dns、httpdns、负载均衡等技术快速切换,让区域用户尽量不收影响。
数据读写隔离
通过主从模式,将mysql、redis等数据存储服务集群化,读写分离,那么在写入数据不可用的时候,也可以通过重试机制 临时通过其他节点读取到数据。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
3)]
[外链图片转存中…(img-XCFicc17-1715207597884)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!