智能批处理

我们都有多少次听说“分批处理”会增加延迟? 作为对低延迟系统充满热情的人,这让我感到惊讶。 以我的经验,正确完成批处理不仅可以提高吞吐量,还可以减少平均延迟并保持一致。

那么,批处理如何神奇地减少延迟呢? 这取决于采用什么算法和数据结构。 在分布式环境中,我们常常不得不将消息/事件分批放入网络数据包中以实现更大的吞吐量。 我们还采用类似的技术来缓冲写入存储,以减少IOPS的数量。 该存储可以是块设备支持的文件系统或关系数据库。 大多数IO设备每秒只能处理少量的IO操作,因此最好高效地填充这些操作。 许多批处理方法都涉及等待超时发生,这本质上会增加延迟。 批处理也可以在超时发生之前被填满,从而使延迟更加不可预测。

图1

上面的图1.描绘了通过引入类似队列的结构来暂存要发送的消息/事件,以及通过进行批量处理以写入到设备的线程,来分离对IO设备的访问,从而取消对IO设备的访问。

算法

批处理方法使用Java伪代码中的以下算法:

public final class NetworkBatcherimplements Runnable
{private final NetworkFacade network;private final Queue<Message> queue;private final ByteBuffer buffer;public NetworkBatcher(final NetworkFacade network,final int maxPacketSize,final Queue<Message> queue){this.network = network;buffer = ByteBuffer.allocate(maxPacketSize);this.queue = queue;}public void run(){while (!Thread.currentThread().isInterrupted()){while (null == queue.peek()){employWaitStrategy(); // block, spin, yield, etc.}Message msg;while (null != (msg = queue.poll())){if (msg.size() > buffer.remaining()){sendBuffer();}buffer.put(msg.getBytes());}sendBuffer();}}private void sendBuffer(){buffer.flip();network.send(buffer);buffer.clear();}
}

基本上,等待数据可用,并立即将其发送。 在发送前一条消息或等待新消息时,可能会到达一连串的流量,所有流量都可以批量发送,直到缓冲区的大小,然后发送到基础资源。 这种方法可以使用ConcurrentLinkedQueue ,它提供低延迟并避免锁定。 但是,如果线程的速度超过批处理程序的速度,则不会产生使生产/发布线程停顿的反压力,因为队列不受限制,因此队列可能会失去控制。 我经常不得不包装ConcurrentLinkedQueue来跟踪其大小,从而产生背压。 根据我的经验,此大小跟踪可以使使用此队列的处理成本增加50%。

该算法遵循单一写入器原理 ,在写入网络或存储设备时通常可以使用,因此避免了第三方API库中的锁争用。 通过避免争用,由于对锁的排队效应,我们避免了通常与资源争用相关的J曲线延迟配置文件。 使用此算法,随着负载增加,等待时间保持恒定,直到底层设备的流量饱和为止,从而导致比“ J曲线”更多的“浴缸”配置文件。

让我们举一个处理10个消息的示例,这些消息作为流量突发而到达。 在大多数系统中,流量是突发的,很少在时间上均匀地间隔开。 一种方法将假定不进行批处理,并且线程将直接写入设备API,如上面的图1所示。 另一个将使用无锁数据结构来收集消息以及按照上述算法在循环中消耗消息的单个线程。 对于该示例,我们假设花费100 µs的时间将单个缓冲区作为同步操作写入网络设备并得到确认。 当等待时间很关键时,缓冲区的大小最好小于网络的MTU。 许多网络子系统是异步的,并且支持流水线化,但是我们将做出上述假设以阐明示例。 如果网络操作在REST或Web服务下使用HTTP之类的协议,则此假设与基础实现相匹配。

最佳(µs) 平均值(µs) 最差(µs) 发送的数据包
序列号 100 500 1,000 10
智能批处理 100 150 200 1-2

如果从线程发起数据直接将消息发送到资源(如果资源无竞争),则将实现绝对最低的延迟。 上表显示了发生争用并产生排队效应时发生的情况。采用串行方法时,将必须发送10个单独的数据包,这些数据包通常需要排队等待管理对资源的访问的锁,因此将按顺序进行处理。 上图假定锁定策略在没有可察觉开销的情况下完美工作,而这在实际应用中是不可能的。

对于批处理解决方案,如果并发队列有效,则可能会在第一批中拾取所有10个数据包,从而提供最佳的延迟情况。 在最坏的情况下,在第一批中仅发送一条消息,在下一批中发送其他九条消息。 因此,在最坏的情况下,一条消息的延迟为100 µs,随后的9条消息的延迟为200 µs,因此,最坏情况的平均值为190 µs,这比串行方法要好得多。

当最简单的解决方案由于争用而过于简单时,这是一个很好的例子。 批处理解决方案有助于在突发条件下实现一致的低延迟,并且最适合吞吐量。 它在接收端的整个网络上也具有很好的效果,因为接收器必须处理更少的数据包,因此使两端的通信效率更高。

大多数硬件都会处理缓冲区中的数据(最大固定大小)以提高效率。 对于存储设备,通常为4KB块。 对于网络,这将是MTU,对于以太网,通常为1500字节。 批处理时,最好了解底层硬件,并以理想的缓冲区大小写下批处理,以实现最佳效率。 但是请记住,某些设备需要封装数据,例如,网络数据包的以太网和IP标头,因此缓冲区需要考虑这一点。

线程切换总是会增加等待时间,并且通过数据结构进行交换的成本也会增加。 但是,使用无锁技术可以使用许多非常好的非阻塞结构。 对于Disruptor,这种类型的交换可以在短短的50-100ns内完成,因此对于低延迟或高吞吐量的分布式系统而言,选择智能批处理方法毫无困难。

这项技术可以用于许多问题,而不仅仅是IO。 当发布者突发事件并超过EventProcessor时,Disruptor的核心使用此技术来帮助重新平衡系统。 可以在BatchEventProcessor内部看到该算法。

注意:为了使该算法起作用,排队结构必须比基础资源更好地处理争用。 许多队列实现在管理争用方面非常差。 在得出结论之前,请运用科学和测量。

使用干扰器批量处理

下面的代码显示了使用Disruptor的EventHandler机制运行的相同算法。 以我的经验,这是一种非常有效的技术,可以有效地处理任何IO设备,并在处理负载或突发流量时保持较低的延迟。

public final class NetworkBatchHandlerimplements EventHander<Message>
{private final NetworkFacade network;private final ByteBuffer buffer;public NetworkBatchHandler(final NetworkFacade network,final int maxPacketSize){this.network = network;buffer = ByteBuffer.allocate(maxPacketSize);}public void onEvent(Message msg, long sequence, boolean endOfBatch) throws Exception{if (msg.size() > buffer.remaining()){sendBuffer();}buffer.put(msg.getBytes());if (endOfBatch){sendBuffer();}} private void sendBuffer(){buffer.flip();network.send(buffer);buffer.clear();}    
}

与上述算法中的double循环相比,endOfBatch参数大大简化了批处理。

我简化了示例以说明算法。 显然,需要考虑错误处理和其他边缘条件。

IO与工作处理的分离

还有另一个很好的理由将IO与执行工作处理的线程分开。 将IO移交给另一个线程意味着一个或多个工作线程可以继续处理而不会以一种友好的缓存友好方式进行阻塞。 我发现这对于实现高性能吞吐量至关重要。

如果基础IO设备或资源短暂饱和,则可以将消息排队等待批处理程序线程,以允许工作处理线程继续进行。 然后,批处理线程以最有效的方式将消息馈送到IO设备,从而允许数据结构处理突发数据,如果已完全施加必要的反压力,则可以很好地分离工作流程中的关注点。

结论

所以你有它。 智能批处理可以与适当的数据结构配合使用,以实现一致的低延迟和最大吞吐量。

参考:来自Mechanical慰问博客的JCG合作伙伴 Martin Thompson提供的智能配料 。


翻译自: https://www.javacodegeeks.com/2012/08/smart-batching.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353094.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cogs 76. [NOIP2007] 统计数字

【问题描述】 某次科研调查时得到了n个自然数&#xff0c;每个数均不超过1500000000(1.5*10^9)。已知不相同的数不超过10000个&#xff0c;现在需要统计这些自然数各自出现的次数&#xff0c;并按照自然数从小到大的顺序输出统计结果。 【输入格式】 输入文件pcount.in包…

javaweb之Filter详解

一、概念&#xff1a;Filter也称之为过滤器&#xff0c;它是Servlet技术中比较激动人心的技术&#xff0c;WEB开发人员通过Filter技术&#xff0c;对web服务器管理的所有web资源&#xff1a;例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截&#xff0c;从而实现一些…

pause容器作用_Kubernetes学习之pause容器

根据代码看到,pause容器运行着一个非常简单的进程,它不执行任何功能,一启动就永远把自己阻塞住了,它的作用就是扮演PID1的角色,并在子进程称为"孤儿进程"的时候,通过调用wait()收割这个子进程,这样就不用担心我们的Pod的PID namespace里会堆满僵尸进程了,这也是为什么…

Spring Integration –轮询文件的创建和修改

1引言 文件支持是Spring Integration与外部系统通信的另一个端点。 在这种情况下&#xff0c;它提供了几个组件来读取&#xff0c;写入和转换文件。 在这篇文章中&#xff0c;我们将编写一个监视目录的应用程序&#xff0c;以便读取其中的所有文件。 具体而言&#xff0c;它执行…

为什么需要消息队列MQ

主要原因&#xff1a;是在高并发情况下&#xff0c;由于来不及同步处理&#xff0c;请求往往会发生堵塞&#xff0c;比如诸多的insert、update之类的请求同时到达mysql&#xff0c;直接导致无数的行锁表锁&#xff0c;甚至最后请求会堆积很多&#xff0c;从而触发大量的too man…

数据库连接池的使用

关于数据库连接池的使用&#xff0c;首先我们要明白我们为什么要用它&#xff0c;对应普通的数据库连接操作&#xff0c;通常会涉及到以下一些操作是比较耗时的&#xff1a; 网络通讯&#xff0c;涉及到网络延时及协议通讯身份验证&#xff0c;涉及安全性检查连接合法性检查&a…

mysql基础知识整理_MYSQL基础知识整理

目录1、客户端命令2、服务器端命令3、常用数据类型3.1、数值型3.2、字符型3.3、日期时间型3.4、布尔型4、mysql的执行方式5、用户管理1、客户端命令客户端命令不需要以分号结尾 &#xff0c;如果想获取客户端命令的帮助信息则&#xff1a;mysql> helpmysql常用客户端命令如下…

python 学习DAY11

动态传参 形参* # 聚合所有位置参数的实参 实参* #打散一个位置参数成多个 形参** #聚合所有关键词参数 实参** #打散实参的关键词参数 命名空间 第一种 内置名称空间 第二种 全局名称空间 第三中 局部名臣空间 作用域 全局作用域(是内置的,全局也可以调用) 局部作用域(局部可调…

【网络技术设备安全】BGP 基础与概述-2-中转 AS 中的 IBGP 路由传递

0x01 中转 AS 中的 IBGP 路由传递 参考该图&#xff1a; 上图&#xff0c;我们模拟一个 1.0 的路由通过 AS 65101 来传递 1&#xff1a;通过图可知&#xff0c;A 与 B 之间的 Peer 为 EBGP&#xff0c;B 与 E 之间为 Peer IBGP&#xff0c;E 与 F 之间为 Peer EBGP 邻接 2&a…

python函数变量的作用域_学不会的Python函数——变量作用域

1. LEGB函数Python中&#xff0c;程序的变量并不是在哪个位置都可以访问的&#xff0c;访问权限决定于这个变量是在哪里赋值的。我们先来看一段代码。上述代码有两个变量a&#xff0c;当在test函数中输出变量a的值是&#xff0c;为什么输出的是20&#xff0c;而不是10呢&#x…

浅谈JSP表单中的form传值

不同JSP页面之间、不同action之间,以及JSP中form与其对应的action之间,JSP中form与其不对应的action之间如何传值。本文将介绍JSP表单中的form传值。 JSP表单中的form传值 页面间链接和数据传递的三种方式 &#xff08;1&#xff09;通过JSP表单form将数据提交到下一个页面&…

react.js从入门到精通(一)

web端三大框架react、vue和angular&#xff0c;下面是对react.js的一些总结。 一、环境搭建 1、npm搭建项目 推荐使用npm搭建项目环境&#xff0c;如果网速过慢&#xff0c;可是使用cnpm进行项目的搭建&#xff08;cnpm是淘宝的npm镜像&#xff0c;与npm有些差异&#xff0c;有…

java 代码冲突检测_Java中常见的代码冲突

java 代码冲突检测在工作中&#xff0c;最近我对现有Java项目进行了代码清理。 完成该练习后&#xff0c;我可以看到在代码中一次又一次地发生了一组常见的代码冲突。 因此&#xff0c;我想出了此类常见违规的清单&#xff0c;并与同行共享&#xff0c;以提高安全意识&#xff…

ubuntu 编译mysql_Ubuntu编译MySQL5

编译MySQL5源码提示 No curses/termcap library found&#xff0c;但安装curses termcap都提示已经安装。编译时加上路径即可解决&#xff0c;即./conf编译MySQL5源码提示 No curses/termcap library found&#xff0c;但安装curses termcap都提示已经安装。编译时加上路径即可…

WIN7下搭建FTP

步骤如下&#xff1a; 一、 二、 三、 四、 五、 六、 七、 八、 九、检验 注意&#xff1a;只有本机可以访问ftp&#xff0c;外部电脑无法访问ftp&#xff1f;可能是防火墙未关闭。

Android调用系统拍照裁剪和选图功能

最近项目中用到修改用户头像的功能,基本上都是模板代码,现在简单记录一下. 调用系统拍照private fun openCamera() { //调用相机拍照// 创建File对象&#xff0c;用于存储拍照后的图片var outputImage File(externalCacheDir, "output_image.jpg")try {if (outputI…

忘记番石榴:5个Google库Java开发人员应该知道的

什么是最有用但未知的Google Java库&#xff1f; 如果我们在激烈的黑客马拉松中阻止某人并要求她命名一个受欢迎的Google Java库&#xff0c;那么答案可能就是Guava。 这也就不足为奇了&#xff0c;因为它的主要重点是提高开发人员的生产力。 但是其他Google图书馆呢&#xff…

VS在win32平台与mysql链接_mysql5.5.28-win32 + qt--4.8.2-vs2008 数据库驱动编译与连接...

我们来编译配置qt的mysql数据库驱动&#xff0c;首先看看官方文档的说明&#xff0c;如下How to Build the QMYSQL Plugin on WindowsYou need to get the MySQL installation files.RunSETUP.EXEand choose "Custom Install".Install the "Libs & Include …

JAVA知识学习——类的修饰符

Java程序在定义类时&#xff0c;除了使用class关键字标识之外&#xff0c;还可以在class之前增加若干类的修饰符来修饰限定所定义的类的特性。类的修饰符分为访问控制符和非访问控制符两大类。修饰符之间的先后排列次序对类的性质没有任何影响。一&#xff0c;非访问修饰符。 1…

神秘的数组初始化_I / O神秘化

神秘的数组初始化由于对高度可扩展的服务器设计的所有炒作以及对Node.js的狂热&#xff0c;我一直想重点研究IO设计模式&#xff0c;直到现在为止都没有足够的时间进行投资。 现在已经做了一些研究&#xff0c;我认为最好记下我遇到的东西&#xff0c;作为对我以及可能遇到这篇…