@
目录- 一、计算高性能的概念
- 二、PPC方案 [懒加载]
- 三、prefork方案 [预先加载进程方案]
- 四、TPC方案
- 五、prethread方案
- 六、线程池方案
- 七、线程池--轮询方案
- 八、多路复用-Reactor [推荐]
- 九、多路复用-Reactor-多线程[推荐]
- 十、多路复用-多Reactor-多线程[推荐]
- 十一、Proactor--异步IO [推荐]
- 十二、集群方案
- 十三、总结
一、计算高性能的概念
- 概念
- 计算高性能指的是系统中的接口高性能;如图:
- 计算高性能指的是系统中的接口高性能;如图:
二、PPC方案 [懒加载]
- 概念
-
PPC方案也称为进程建立连接方案;如图:
- 以查询商品为场景
- 当客户端发起请求到服务端,父进程接收客户端发过来的请求,再将请求转给子进程进行处理业务逻辑[读数据,写数据],处理完成后再返回客户端。
- 子进程工作流程
1、 创建子进程
2、使用子进程处理业务处理[数据查询,数据写入]
3、 关闭子进程
- 以查询商品为场景
-
- 缺陷
- 太消耗时间,性能低。 [比如客户端发来100个请求,创建子进程需要时间,子进程CPU切换需要消耗时间]
三、prefork方案 [预先加载进程方案]
- 概念
-
prefork方案称之为预先加载进程方案,如图:
当客户端发来到服务端,父进程接收到请求,再将请求转给预先加载好的子进程,进行业务处理[数据的读取,数据的添加]。
-
- 缺陷
- 子进程CPU切换,太消耗时间的问题不能解决。
- 预先创建子进程,太消耗内存资源。
- 创建子进程是有限的。
四、TPC方案
- 概念
-
TCP方案称为进程与线程的方案;如图:
当客户端发送请求到服务端,服务端系统[主进程]接收到请求并创建一个子线程来处理业务逻辑[数据读取,数据添加]。
-
- 缺陷
- 创建子线程与线程CPU切换,消耗时间[性能低]
- 存在资源竞争的问题[方案:lock 互斥锁]
- 子线程与子进程的区别
- 子线程是共享主进程的资源。
- 子进程不共享主进程,复制主进程的资源。
五、prethread方案
- 概念
-
prethread方案可以称为预先加载线程的方案;如图:
当客户端发送请求到服务端,服务端系统[主进程]接收到请求转给预先创建好的子线程来处理业务逻辑[数据读取,数据添加]。
-
- 缺点
- 预先创建子线程,消耗内存资源。
六、线程池方案
- 概念
-
线程池是将预先创建好的线程放在线程池中;如图:
当客户端发送请求到服务端,服务端系统[主进程]接收到请求到线程池中取一个线程来处理业务逻辑 [数据读取,数据添加]。
-
- 场景
- 如果当前的业务处理不耗时,可以使用:进程+多线程+线程的方案
- 当前主进程与子线程之间的关系
- 假如当客户端发起10个请求,主进程会开启10个子线程,当第一个子线程在读取数据时,其他的9个线程处于等待的状态,直到第一个子线程读取数据成功后,主进程将数据返回到客户端,在处理其他的9个子线程,其他的9个子线程和第一个线程的处理方式是一样的,一个一个的返回后在处理其他的子线程。
- 缺陷
- 如果业务处理非常耗时,性能下降很快。
七、线程池--轮询方案
-
概念
- 当客户端发送请求到服务端,服务端系统[主进程]接收到请求,主线程使用for循环轮询的方式循环线程池中的子线程,看哪个子线程是空闲的状态就给哪个请求,并一个一个的返回给客户端;如图:
- 当客户端发送请求到服务端,服务端系统[主进程]接收到请求,主线程使用for循环轮询的方式循环线程池中的子线程,看哪个子线程是空闲的状态就给哪个请求,并一个一个的返回给客户端;如图:
-
缺陷
- 如果并发量大,线程数量大,导致轮询时间过长,消耗CPU的资源,性能下降。
八、多路复用-Reactor [推荐]
-
概念
- 多路复用就是复用一个进程处理请求;如图:
- 多路复用就是复用一个进程处理请求;如图:
-
核心思想
- 调度,依靠事件处理
当系统[微服务]启动之后,Reactor框架中的select监听客户端的请求,当客户端发起查询商品请求后,Reactor框架中的select会判断是建立连接还是进行业务处理,如果第一次进来收到是连接请求,Reactor回将该请求给dispach,dispach转给Accept,Accept并创立连接,同时并创建Handler类处理业务逻辑;当客户端第二次发起请求,Reactor框架中的select发现已经建立连接,Reactor回将该请求给dispach,dispach直接转给Handler类处理业务逻辑。
- 调度,依靠事件处理
-
优点
- 节约线程资源。
- 解决for循环消耗CPU资源的问题。[redis就是使用的这种方案]
-
缺陷
- 如果当前请求业务处理耗时,其他的请求需要进行等待[阻塞],会出现性能瓶颈。
九、多路复用-Reactor-多线程[推荐]
- 概念
-
多路复用+多线程其实就是一个主进程加多个线程的处理方案;如图:
当系统[微服务]启动之后,Reactor框架中的select监听客户端的请求,当客户端发起查询商品请求后,Reactor框架中的select会判断是建立连接还是进行业务处理,如果第一次进来收到是连接请求,Reactor回将该请求给dispach,dispach转给Accept,Accept并创立连接,同时并创建Handler类根据事件类型在主进程里面开启一个新的线程处理业务逻辑;当客户端发起查询订单请求后,Reactor框架中的select会判断是建立连接还是进行业务处理,如果第一次进来收到是连接请求,Reactor回将该请求给dispach,dispach转给Accept,Accept并创立连接,同时并创建Handler类根据事件类型在主进程里面开启一个新的线程处理业务逻辑;
谁先完成业务处理,谁就先返回给客户端。
-
- 场景
- 数据量大的场景
- 数据量小的场景
- 缺陷
- 瞬时高并发时,因为要创建更多的连接和事件,造成性能下降。
十、多路复用-多Reactor-多线程[推荐]
-
当客户端发起请求,主进程Reactor框架的select监听客户端的请求,Reactor会将该请求给dispach,dispach转给Accept,Accept并创立连接后,再将请求交给子进程,子进程会创建一个线程处理业务逻辑;[主进程与子进程相互隔离,主进程负责建立连接,子进程创建线程,线程负责处理业务逻辑。python与go语言符合这种方案,既可以多进程又可以多线程;C#与java是单进程多线程方案;nginx也是用的多进程的方案] 如图:
-
缺陷
- 线程之间的切换耗时
- 线程创建太多,太消耗内存资源
十一、Proactor--异步IO [推荐]
-
概念
- 当客户端发送请求到服务端的用户进程,首先通过Proactor initiator初始化,将请求注册给内核进程中asynchroncus operation processor,同时创建Handler事件处理类,创建成功后注册到asynchroncus operation
processor,再将请求创建一个Proactor;内核进程接收注册的请求后,然后执行IO操作【到数据库查询数据等业务逻辑】,处理成后通知processor,进行回调返回客户端。如图:
- 当客户端发送请求到服务端的用户进程,首先通过Proactor initiator初始化,将请求注册给内核进程中asynchroncus operation processor,同时创建Handler事件处理类,创建成功后注册到asynchroncus operation
-
实现场景
- windows IOCP
- Linux epoll(借助Reactor)
十二、集群方案
1 使用Nginx部署系统集群,如图:
2 使用nginx集群部署系统集群,如图:
3 使用F5部署nginx集群,如图:
F5处理并发能力差不多在100万左右。
-
缺陷
- F5设备太贵,小型公司一般不会去用,大型公司会用。
4 使用DNS服务器部署F5集群,如图:
- F5设备太贵,小型公司一般不会去用,大型公司会用。
-
当客户端发起请求到dns服务器,使用负载均衡算法获取到相应的IP地址,再根据地址到相应的F5设备,F5再用负载均衡算法到相应的nginx服务器,nginx再用负载均衡算法到相应的服务处理业务逻辑。
-
缺陷
- F5这种设备太过于贵重,最起码两台F5设备起,一台正常使用,另一台设备当做备机使用。
十三、总结
- 方案场景选择
- 如果数据量小,选择单Reactor。例如:Redis [8]
- 如果数据量有大,有小,选择Reactor多线程方案。例如:NET,java[9]
- 如果数据量有大,有小,并有瞬间并发,选择多进程方案。例如:Netty,Dotnetty [10]
- 如果数据量有大,有小,并有瞬间并发,而且资源消耗大,选择异步IO。例如:IOCP,epoll ,nginx,Dotnetty [11]
- 以某商城分布式系统为例,看哪些模块使用F5设备
- 商品模块[独立的服务(系统)]:可用可不用,分情况来定,[实例隔离]。
- 订单模块[独立的服务(系统)]:
- 支付模块[独立的服务(系统)]:
- 前提
- 数据访问量 决定集群数量
- 数据大小 决定选择通信模型
- 访问的数据量大 [12中的第四个方案]以上的三个模块可根据访问的数据量来定
- 访问的数据量小 [12中的第二个方案]以上的三个模块可根据访问的数据量来定
- 前提
-
- 用户模块[独立的服务(系统)]: [12中的第二个方案]