这次救火讨论的是流控,流控可以很简单,也可以非常复杂,特别是动态流控。我们有一个产品在T国某个运营商遇到了麻烦,这个运营商的母公司是欧洲的运营商,而欧洲的运营商对于产品验收的苛刻是出了名的,而这次给我们带来麻烦的就是流控。

这个产品的大致功能就是把订阅的短消息或者彩信内容发送到户手机上,就类似于在几年前火了一段时间的手机报。这个产品的流控有些复杂:

1、首先这套系统部署是集群,假设集群有6台主机,这6台主机的每秒下发的消息量不能超过一个值,假设为10000,为什么有这个要求,是因为下游执行发送消息的短消息网关或彩信网关有流控,你发的快了,下游系统会拒绝你,所以这个总的TPS不能超。

2、这些消息的来源都是来自于某个SP或者CP,每个CP或者SP在签约平台的时候,它有一个最大每秒发送量,发送量分为彩信、短信以及WAP Push渠道。

3、除了上面的限制以外,CP和SP又分了优先级,如果低先级和高优先级的时候在一起发送的,一定要先等到高优先级的先发送完成。

还有一些规则要求,时间比较久了,我记不是特别清楚了。

这套系统在国内和国外不少地方都上线了,不能说质量多好,也没有太大的问题,我接手这个产品大概几个月的时候在这个局点遇到了问题,客户投诉他们通过线上实际的监控发现2个严重的问题,如果不解决,他们会******:

1,这套系统在高峰期间实际下发的每秒流量没有达到当时他们购买的流量,比如他们购买为10000条/秒,但是他们实际监测发现高峰的时候,可能只有9000条/秒.

2,系统的流控不稳定,当时合同签署的流控上下波动不能大于正负10%。举个例子,假设他们有一个最大的SP,在上午10点到11点独占发送消息,他们设定按200条/秒发送,这时没有任何其它的SP抢占通道,那么消息发送速率应该是在180~220条/秒,但是实际发送的速率会在这个区间之外。

当时我接手这个产品几个月时间,对系统的大致实现有了解,但是细节并不是清楚,负责这个产品的小组长找到我求助,不懂也要硬着头皮上。一开始以为是个小问题,这个产品的开发骨干试了几种方案过了一周,发现都很难达到客户的要求,这时客户和项目经理失去了耐心,开始把问题往高层领导汇报,一旦高层领导知道,后果可想而知。我当时带着这个产品的小组长以及开发骨干开始做这个问题的攻关,前后总共投入了3周左右的时间(有一半的时间基本上是都是在通宵)。

经过几天走读代码以及实际测试验证,我发现原来的流控实现方案存在严重的缺陷,原来的方案是存储过程实现上面的流控的流量的分配动作,这个存储过程每1秒运行一次,每次运行的时候它会把当前需要下发的任务根据总流控、CP以及SP等计算一遍,然后把需要下发的数据加载到Oracle的分区表中,把要发送的速率插入到任务表中,然后集群是每个任务下发的线程从任务表中读到任务,然后再从分区表中加载上任务要发送的数据,再周而复始的存储过程不断计算分配任务、集群每个节点加载任务数据发送数据。

这个产品的最初的开发在2004~2005年左右,最初的设计人员找不到了,但是我猜想为什么用数据库来解决,是因为如何控制每秒发送的消息在集群下并不好实现,而数据库存放集中式数据是最简单的实现方式。这种方案对于大部分运营商对流控的准确性要求没有那么高时,其实并不是太大的问题,只要系统的负载不是过重,消息能基本准确的发送就可以了。

回到客户发现的2个问题,可以大致感性的分析原因:

1、因为任务的分配是每秒重新计算一次,计算完成以后,下发线程要再从分区表中加载数据,这都需要时间,即数据不是立即下发,会导致之前分配的速率执行时间被拉长了,所以很难达到总容量

2、流控的不准确性:单个线程发送的流控算法优化问题,我会在后面再讨论这个问题

针对第一个问题,我们最后设计了一个流控中心的应用,抛弃了原来通过数据库进行任务的分配的逻辑,其它所有发送消息的应用通过Netty连接到流控中心,当前任务以什么速率发送完全以流控中心的指标为准,而流控中心它的计算逻辑全在内存中实现。流控中心和消息发送应用之间双向通信,当下发的速率要调整的时候,流控中心可以把速率主动的下发给消息中心。当时因为时间紧,我们并没有用专门的机器来部署流控中心,而是把所有的发送消息的主机在启动的时候把自己的IP地址写到数据库的一张表中,然后在这张表中最先插入数据的那台机器就兼容来流控,顺便发送消息。因为流控并不是很耗性能,所以即使发送消息对性能影响不大。如果负责流控的机器挂了的话,再由心跳机制把那台挂了的机器删除掉,这时其它发送消息的节点再重新连接到新的负责流控的主机上。

看到这,大家可能觉得这招很土,其实当时我想过用JGroup来做集群的管理,但是如果你在生产环境用过JGroup的话,就会发现这玩意太复杂了,我当时在很多项目都被坑过。那时也没有见过其它什么更好的集群通信的开源组件了,加上项目时间紧,我们按更加稳妥的方案实现。

而针对第二个问题,难度相对要小一些。原来的方案采用了一个定时器,这个定时器每秒运行一次,每次运行的时候把一个Semaphore置成需要发送的TPS,每个发送线程在发送之前accquire,如果能取到就发送,取不到就阻塞,然后再下一个1秒的时候再把这个信号量Release到发送的TPS。这么实现会导致发送的在1秒内不平均,比如说:我要一秒发送30条消息,有可能在1/3秒的时候就把消息都发完了,然后在剩下的2/3秒什么也没发,这样如果在下游采样统计TPS的周期不是按1秒来计算,而是按1/6计算的时候,明显发送速率就不稳定。

改进以后的流控算法是参考了一个兄弟产品的方案,称之为滑动窗口流控算法,因为画图比较花时间,我简单描述一下。这个算法将1秒分成10个小窗口,还是以上面每秒发送30条为例,在第一个小窗口时,我需要发送3条消息,到第2个小窗口时我只需要累计发送2*3=6条消息,到第3个小窗口时,我只需要累计发送3*3=9条消息,这个算法的好处是发送的消息速率更加平滑,将下游发送的速率的波动给抹平掉。这个算法还有一个好处,不像上面一个算法要有定时器不断的清零,而只需要很简单的获取当前系统时间-系统启动时间,就可以算出来当前处在哪个发送窗口,系统的开销不仅小而且更准确。

经过上面的2个优化以后,达到了预期的目标,后面这个产品的基线版本的流控算法又重新进行了设计,后面的随笔再说后来怎么优化的。1年以后的基线版本优化以后,这个产品的小组长离开了公司,这个产品的开发骨干去了海外常驻,也没有了联系。但是写到这,就想到3个人像个落魄鬼一样在公司不分昼夜的讨论方案、改代码、测试…

转载于:https://www.cnblogs.com/cc011/p/5858091.html

救火队员的那些事(4)-关于流控相关推荐

  1. 从源码分析 MySQL Group Replication 的流控机制

    Group Replication 是一种 Shared-Nothing 的架构,每个节点都会保留一份数据. 虽然支持多点写入,但实际上系统的吞吐量是由处理能力最弱的那个节点决定的. 如果各个节点的处 ...

  2. linux内核TCP 滑动窗口,TCP滑动窗口和流控

    TCP的滑动窗口是一个很重要的概念,也是很晦涩的一个知识点.下面就大概介绍下TCP滑动窗口为什么出现?它是怎么工作的的? 什么是TCP窗口 首先,要理解,client和server各自协议栈都有自己的 ...

  3. 【协议识别】流控及上网行为管理产品比较

    WAN加速产品: 外国厂商:RiverBed.F5 .思科WAAS.juniper广域网加速平台.思杰广域网加速平台 国内厂商:华夏创新 评比:外国厂商中只有前两者是非常著名的专注于广域网加速的厂商, ...

  4. RS232的硬件流控

    DCD :载波检测.主要用于Modem通知计算机其处于在线状态,即Modem检测到拨号音, 处于在线状态.  RXD:此引脚用于接收外部设备送来的数据:在你使用Modem时,你会发现RXD指示灯在闪烁 ...

  5. RS232的硬件流控:DCD DSR DTR RTS CTS

    DCD :载波检测.主要用于Modem通知计算机其处于在线状态,即Modem检测到拨号音, 处于在线状态.  RXD:此引脚用于接收外部设备送来的数据:在你使用Modem时,你会发现RXD指示灯在闪烁 ...

  6. 关于VMware ESX4.1上架设 海蜘蛛+Panabit流控 的虚拟整合

    早在玩软路由.流控那时就有这个想法,将其用虚拟机整合起用,让本来所需要的几台设备才能做到的工作变成一台搞定!起码节省设备的同时也可以节省空间(幸好两样都暂时不是问题~哈哈). 前言结束-因为最近比较懒 ...

  7. 串口流控--软件流控与硬件流控

    在串行通讯处理中,常常看到rts/cts和xon /xoff这两个选项,这就是两个流控制的选项,目前流控制主要应用于调制解调器的数据通讯中.流控制在串行通讯中有何作用,在编制串行通讯程序怎样应用呢?下 ...

  8. 如何形象地描述 RxJava 中的背压和流控机制?

    之前我在知乎上受邀回答过一个关于RxJava背压(Backpressure)机制的问题,今天我把它整理出来,希望对更多的人能有帮助. RxJava的官方文档中对于背压(Backpressure)机制比 ...

  9. 串口的硬件流控和软件流控

    为什么需要流控?   当两台设备进行串口通信,假如他们对数据的处理速度不同.如果接收端数据缓冲区已满,则此时继续发送来的数据就会丢失.使用流控机制时,当接收端数据处理能力饱和时,就发出"不再 ...

最新文章

  1. oracle11g自带优化吗,windows下Oracle11g的优化教程
  2. 简单的JSP登录程序
  3. docker 核心概念整理
  4. 查询进程并杀死该进程
  5. 地图上实现高效率绘制海量点的原理
  6. DevStack安装问题,git clone noVNC.git失败
  7. python之路day4_python之路day4
  8. Python一行代码给儿子制作九九乘法表
  9. 程序员回家过个年,真心不要容易
  10. MySQL导入sql文件的三种方法
  11. php获取qq头像地址,使用PHP语言通过邮箱获取全球公认的Gravatar头像地址
  12. 在VSCode中使用CUDA
  13. 网络表情NLP(一)︱颜文字表情实体识别、属性检测、新颜发现
  14. 每天1分钟 经济学小知识
  15. db2的节点编目和数据库编目
  16. java语言如何将小写字母转化为大写_java中如何把大写字母转换成小写字母,小写字母转换成大写字母...
  17. python下载动作电影_Python爬虫实战之取电影天堂,,新手练手项目
  18. 书评与摘抄《经济学原理》
  19. SAP FICO 会计凭证打印开发说明书(包括开发源代码、测试样例及FS)
  20. 知识点------js判断早上好,上午好,下午好,傍晚好,晚上好

热门文章

  1. 拯救者Y7000系列 笔记本键盘点击 只响但是没有反应的问题
  2. Java数组|数组的声明创建和使用
  3. 几何基础 叉乘与反对称矩阵
  4. 二维码“仙人”——教你制作二维码,读取二维码
  5. python打开网页获取网页内容方法总结
  6. 羧酸-COOH功能化修饰红色荧光聚苯乙烯AIE微球的产品组成和保存条件
  7. 2023年你最值得了解的信息技术-AI篇(二)
  8. 身份云为什么? 浅谈身份认证与FIDO
  9. 【达内课程】音乐播放器4.0(播放详情页下)
  10. Mac OS SafariBookmarksSyncAgent意外退出解决方法