LF模式是个坑,一个小小的失误就可能使你的网络处理瘫痪,Ice就很好地展现了出来,换句话说,Ice中间件或是LF模式就是一个坑,如果你一不小心。

LF模式的官方论文中,论述了此模式用于高性能网络并发模式,使用的是系统的隐式队列,也就是Reactor复用多路IO,(如果是select的话,还是会将事件收集到一个显式队列),每次只有一条线程可以有一次机会成为leader访问这个队列,从队列取出事件后放弃leader,同时唤醒另一线程(如果还有follower线程的话);注意这时的线程既不是leader也不是follower,它就可以处理事件,一般就是同步非阻塞读写,然后处理这个请求(通常来说就是dispatchFromThisThread)。当上面的工作结束就,才会作为follower等待成为leader,如果没有leader的话就会马上成为leader。在这种模式中,称为LF模式有点误导,因为实际上是三种状态,LPF,Leader,Process,Follower,状态机为 L->P->F->L->...。Follower状态的线程阻塞等待着Leader离开Leader状态去Process,从而唤醒可能的Follower状态的线程。被唤醒的Follower线程状态变为Leader,成为线程池中唯一当前有权操作队列的线程,要么阻塞在空队列,要么取出队列一个事件离开Leader状态去Process。线程池线程当Process完事件后才会状态变为Follower,或者阻塞等待Leader的唤醒,或者自动成为Leader。状态机就为 L(block on event queue)->P->F->(block on followers queue)->L ...。在这种模式下的线程池中,最多只有一个线程在Leader状态,并且只有这个Leader线程可以阻塞在IO事件队列,其它线程要么在Process状态处理事件,要么就是在Follower状态等待成为下一个Leader。当没有IO事件的时候,就只有一个线程在Leader状态阻塞在IO事件队列,其它线程都结事了事件的处理,并在Follower状态阻塞等待Leader线程释放信号。

通常用来衬托LF模式的,就是sync/async模式,并且都会举例Manager-Workers线程池。Manager负责将队列的事件指派到空闲Worker线程进行处理。Worker线程被唤醒处理完事件后再次阻塞等待Manager唤醒。当没有事件的时候,Manager阻塞在事件队列,Worker线程阻塞等待Manager线程唤醒。这种线程池有一个固定线程去阻塞在事件队列。并且每次Manager唤醒Worker都要通过堆来传递事件。(Manager从事件队列取出一个事件写入到堆内存,Worker从堆内存读到自己的栈,然后处理栈上的这个事件;而Leader从事件队列将一个事件读到自己的栈,再就唤醒其它Follower,然后处理栈上的这个事件。)当Manager线程不负责Reactor复用多路IO的情况,在空闲时发生了一次IO事件必须跨线程写入Manager线程的事件队列,并唤醒Manager线程,然后Manager线程唤醒Worker线程去处理事件。而LF模式线程池,Leader从系统的多路IO复用分离函数中返回,唤醒一个Follower,然后自己去处理事件。这样一比较就是Manager-Workers线程池进行了两次线程唤醒,而LF模式线程池只有一个线程唤醒(这里必须要公正,Leader是之前就被唤醒经历消耗了一次切换),事件在Manager-Workers线程池需要多次拷贝。

那么为什么LF模式不心就会踩坑,而Ice的设计就让体会这个坑。

问题在于如果LF模式线程池的线程进行Process阻塞等待IO响应,而所有的线程都在Process过程中阻塞等待IO响应,更重要这些被等待的IO应用在这个线程池的Reactor,就会再也没有线程成为Leader去多路IO分离函数中读取IO事件。这时候这个LF线程池就会瘫痪不工作。Ice中间件会让你深深体会这种痛。Ice采用ActiveObject模式进行OBR对象代理请求。控制线程调用proxy请求返回一个future,阻塞等待future。Communicator的clientThreadPool负责Reactor,收到请求的response后就向future发信号,从而唤醒这个response对应的future阻塞住的控制线程。这种情况下使用ORB对象代理请求的线程与网络Reactor线程池独立,负责Reactor的LF线程池不会被其它逻辑影响。但是在LF线程池中进行ORB对象代理请求呢?问题就来了。你的LF线程池随时都可能瘫痪掉,只要你不小心。极端地,LF线程池只有一个线程,这个线程在Process事件时,进行了ORB对象代理请求,阻塞等待future。Good Job!! 这个线程池中唯一的线程就永远不会再有机会成为Leader去取出远端的response的IO事件,去唤醒这个阻塞住线程的future了。这还不容易解决,都说是线程池,那会只有一个线程的呢。我们让这个LF线程池添加到两个线程,第一个线程取出事件唤醒第二个线程,然后自己处理事件时,进行了ORB对象代理请求,阻塞等待future;第二个线程成为Leader阻塞在多路IO分离函数,并在远端response到来时,从分离函数返回,得以唤醒了阻塞第一个线程的future。但是很不幸,第二个线程在等待到response到来之前,收到其它IO事件,而处理这个事件却进行了ORB对象代理请求,阻塞等待future。汗,LF线程池都被阻塞在future,future又等待IO事件。再往下演绎,不论LF线程池有多少线程,只要你的处理逻辑中进行了同步阻塞的ORB对象代理请求,都会使你的Ice网络处理瘫痪,瘫痪的原因是LF线程池瘫痪了。Ice的Server端线程池默认就在当前线程进行请求的dispatch,如果你在实现你的服务的时候必须依赖其它ORB对象代理请求时,你就要小心了,你可能因为这样而阻塞掉所有Communicator的Server端LF线程池,至使网络Reactor瘫痪。如果你使用了bidirection connection来提供callback的饲服,要是你在callback的实现中依赖了其它ORB对象代理请求时,你同样也要小心了,你可能因为这样而阻塞掉所有Communicator的Client端LF线程池,至使网络Reactor瘫痪。Ice为了避免,会默认为每个连接加上一个计时器,让连接自动断开。但是我们还是有应用场合希望连接长九不断开,关闭这种机制,这时就要小心了。再者就是,即使你所有的ORB对象请求代理都用异步方式(ami,amd)进行编程,但是悲剧的是你无法干涉到你依赖的其它人函数没有进行同步阻塞的ORB对象代理请求。

LF模式是个坑,ZeroIce中间件让你体会这个痛的更多相关文章

  1. LF模式解决的问题

    一说起Leader/Followers并发模式,都会与Half-Async/Half-Sync并发模式进行比较,说LF模式更加高性能,成了一个高性能名词标签 符号,相反HA/HS仿佛成了一个低性能的名 ...

  2. Vmware虚拟机配置LVS/NAT模式遇到的坑。

    这两天在研究LVS的负载均衡,先从最简单的LVS/NAT模式开始入手. 最后配置完之后能够相互之间Ping通,并且能够直接访问real服务器提供的web服务,而且防火墙也已经关闭了. 但是通过访问LV ...

  3. asp.net core系列 76 Apollo 快速安装模式下填坑和ASP.NetCore结合使用

    前言:由于公司占时没有运维,出于微服务的需要,Apollo只能先装在windows 阿里云上跑起来,由于环境及网络等问题,在安装过程中遇到很多坑,算是一个个坑填完后,最终实现. 一. java jdk ...

  4. webpack集成vue单文件模式的很多坑(研究了1个星期)

    1.一开始不知道局部安装webpack后,如何调用webpack. 后来看说明文档(webpack中文网)才知道,有个npx可以启动本地安装的webpack. 我估计:全局安装webpack,全局的w ...

  5. nacos集群模式搭建踩坑记录

    首先数据库使用的本地的mysql 1.看日志提示no set datasource,使用虚拟机ping本地后发现无法ping通,原因是本地没有关闭防火墙. 2.看日志提示不允许建立数据库连接,原因是r ...

  6. 重学 Java 设计模式:实战外观模式「基于SpringBoot开发门面模式中间件,统一控制接口白名单场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你感受到的容易,一定有人为你承担不容易 这句话更像是描述生活的,许许多多的磕磕绊绊总 ...

  7. ASP.NET Core路由中间件[2]: 路由模式

    一个Web应用本质上体现为一组终结点的集合.终结点则体现为一个暴露在网络中可供外界采用HTTP协议调用的服务,路由的作用就是建立一个请求URL模式与对应终结点之间的映射关系.借助这个映射关系,客户端可 ...

  8. VSCode git Warning LF will be replaced by CRLF

    本文参考自:http://www.yulongjun.com/linux/20170518-08-lf-cr/ 我们打开Visual Studio Code编辑器,可以看到右下角有这个LF,这是VS ...

  9. java设计模式——原型模式

    一. 定义与类型 定义:指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数 类型:创建型 二.使用场景 类初始化消耗较多资源 new 产生的一个对 ...

随机推荐

  1. 微信小程序 瀑布流布局

    今天做小程序的时候,碰到一个比较常见的需求,就是要瀑布流布局,两列,交错分布,大概如下图 最终要实现的结果就是如左图所示. 不过在微信小程序里面,不能通过JavaScript来直接操作dome,所以一 ...

  2. 【高斯消元】兼 【期望dp】例题

    [总览] 高斯消元基本思想是将方程式的系数和常数化为矩阵,通过将矩阵通过行变换成为阶梯状(三角形),然后从小往上逐一求解. 如:$3X_1 + 2X_2 + 1X_3 = 3$ $           ...

  3. Serv-U FTP版本控制服务器 - 目录规范

    背景 公司要组建一个版本控制服务器,选定了serv-u,初始目的是应用于war级的一些标准组件的版本控制/测试交付/统一对外发布渠道. 项目过程图: 如果不使用版本控制会出现什么问题? War标准组件 ...

  4. 由于用mpu6050模块,所以要用上i2c通信原理。

    i2c通信原理 i2c总线只有两根双向信号线,一根是数据线SDA,一根是时钟线SCL. 每个接到i2c总线上的器件都有唯一的地址,主机与其他器件之间的数据传送可以是由主机发送给其他器件.主机为发送器, ...

  5. 灵玖Nlpir Parser智能挖掘汉语精准分词

    在中文自然语言处理中,词是最小的能够独立活动的有意义的语言成分.汉语是以字为基本书写单位,词语之间没有明显的区分标记,因此进行中文自然语言处理通常是先将汉语文本中的字符串切分成合理的词语序列,然后再在 ...

  6. Redis主从复制(Master/Slave)

    Redis主从复制(Master/Slave) 修改配置文件 拷贝多个redis.conf文件分别配置如下参数: 开启daemonize yes pidfile port logfile dbfile ...

  7. 实例甜点 Unreal Engine 4迷你教程(6)之三个重要基础操作SpawnActor、TArray的Add和Remove

    本小节的教程需要完成前置教程:建议阅读<实例甜点 Unreal Engine 4迷你教程(5)>,因为5里面提到了本节的工程,不过也可以在不看5的前提下直接阅读本教程. 第一步:Empty ...

  8. php中自动加载类_autoload()和spl_autoload_register()实例详解

    一._autoload 自动加载类:当我们实例化一个未定义的类时,就会触此函数.到了php7.1以后版本不支持此函数好像抛弃了 新建一个类文件名字自己随便去:news类在auto.php文件里面去实例 ...

  9. python学习之核心数据类型

    python核心数据类型 对象类型 例子 数字 1234,-345 字符串 'spam' 列表 [1,3,'ds'] 元组 (1,'spam',6) 字典 {'name':'lili','age':1 ...

  10. 社群系统 ThinkSNS+ 中如何利用 Laravel 表单验证来验证用户名的?(我朝独有需求,两个字母占一个汉字。。。)

    ThinkSNS+后端框架使用laravel,每周和 laravel master 保持同步,而后台和 html 5 则采用 vue 开发.语言特性方面,采用 php 7 的严格模式. 言归正传,之所 ...