智能配料

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

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

图1

上面的图1.描绘了通过引入类似队列的结构来暂存要发送的消息/事件,以及通过进行批量处理以写入到设备的线程,将对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/372314.shtml

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

相关文章

mysql从myisam_将MySQL从MyISAM转换成InnoDB错误和解决办法

原来自己用的是为了装的&#xff0c; 所以在设置database usage(如下图1)的时候按照discuz官方的建议&#xff0c;选的都是Non-Transactional Database Only(只支持MyISAM数据引擎的非事务数据库)&#xff0c;用MyISAM数据库&#xff0c;还没涉及到需要InnoDB&#xff0c;因此打…

相似性度量中用到的一些距离函数

本文目录 1. 欧氏距离 2. 曼哈顿距离 3. 切比雪夫距离 4. 闵可夫斯基距离 5. 标准化欧氏距离 6. 马氏距离 7. 汉明距离 8. 杰卡德距离 & 杰卡德相似系数 9. 相关系数 & 相关距离 10. 信息熵 1. 欧氏距离(Euclidean Distance) 欧氏距离是最易于理解的一种距离计算方法&a…

计算1~n之间所有奇数之和_所有奇数长度子数组的和

所有奇数长度子数组的和题目&#xff1a;给你一个正整数数组 arr &#xff0c;请你计算所有可能的奇数长度子数组的和。子数组 定义为原数组中的一个连续子序列。请你返回 arr 中 所有奇数长度子数组的和 。示例 1&#xff1a;输入&#xff1a;arr [1,4,2,5,3]输出&#xff1a…

JMX:一些入门说明

JMX&#xff08;Java管理扩展&#xff09;是一种J2SE技术&#xff0c;可以管理和监视Java应用程序。 基本思想是实现一组管理对象&#xff0c;并将实现注册到平台服务器&#xff0c;在平台服务器上&#xff0c;可以使用一组连接器或适配器从本地或远程调用这些实现到JVM。 一个…

解释java程序中的异常机制_Java编程中的异常机制

本文旨在以初学者的角度来学习Java异常的知识&#xff0c;尽量简单&#xff0c;一些细枝末节的知识不会讲述&#xff0c;但不影响对知识的掌握。&#xff08;比如try-catch可以嵌套&#xff0c;不太会这么用&#xff09;1.什么是异常我们先举个例子int x 10/0;在IDE里输入这样…

配置环境变量

由于写了一个关于生成签名需要配置环境变量&#xff0c;所以在这里顺便把配置环境变量的步骤说一下 1.右键点击计算机&#xff0c;然后点击高级系统设置 2.点击环境变量&#xff0c;下方出现的即为系统变量&#xff0c;双击path就能直接修改&#xff0c; 转载于:https://www.cn…

使用JavaFX AnimationTimer

回想一下&#xff0c;给AnimationTimer起个名字可能不是一个好主意&#xff0c;因为它不仅可以用于动画&#xff0c;还可以用于测量&#xff1a;fps速率&#xff0c;碰撞检测&#xff0c;模拟步骤&#xff0c;游戏主循环等实际上&#xff0c;大部分时间我都看到了AnimationTime…

JavaFX 2 GameTutorial第3部分

介绍 Ť他是与一个六个部分组成的系列的第3部分的JavaFX 2游戏教程。 如果您错过了第1部分和第2部分 &#xff0c;建议您在开始本教程之前先进行阅读。 回顾第二部分&#xff0c;我讨论了游戏循环的内部工作原理&#xff0c;其中我们使用动画&#xff08;JavaFX Timeline &…

Selenium WebDriver + python 自动化测试框架

目标 组内任何人都可以进行自动化测试用例的编写 完全分离测试用例和自动化测试代码&#xff0c;就像写手工测试用例一下&#xff0c;编写excel格式的测试用例&#xff0c;包括步骤、检查点&#xff0c;然后执行自动化工程&#xff0c;即可执行功能自动化测试用例&#xff0c;包…

mysql游戏减少积分活动图_plantuml-绘制状态图和活动图和部署图​

背景状态图&#xff1a;对象的所有状态&#xff0c;以及基于事件发生的状态改变的过程&#xff1b;活动图&#xff1a;用例的工作流程&#xff1b;部署图&#xff1a;系统的软硬件物理体系结构&#xff1b;状态图基本语法元素语法说明开始和结束状态[*]标识开始和结束状态箭头-…

windows中当你的键盘无法使用时我们可以用另一种方法哦

1.使用WinR打开cmd窗口 2.输入osk回车就出现了一个虚拟的小键盘啦&#xff0c;当你的键盘坏掉后非常实用哦 转载于:https://www.cnblogs.com/qianzf/p/6780496.html

NetBeans 7.2引入了TestNG

代码生成的优点之一是能够查看如何使用特定的语言功能或框架。 正如我在《 NetBeans 7.2 beta&#xff1a;更快&#xff0c;更有用》一文中所讨论的那样&#xff0c; NetBeans 7.2 beta提供了TestNG集成 。 除了对该功能的单一引用之外&#xff0c;我在该帖子中没有进一步阐述&…

Javascript模块化编程(三):require.js的用法

一、为什么要用require.js&#xff1f; 最早的时候&#xff0c;所有Javascript代码都写在一个文件里面&#xff0c;只要加载这一个文件就够了。后来&#xff0c;代码越来越多&#xff0c;一个文件不够了&#xff0c;必须分成多个文件&#xff0c;依次加载。下面的网页代码&…

几万条数据的excel导入到mysql_【记录】2万多条数据的Excel表格数据导入mysql数据库...

主题刚开始的时候做了两个小方案&#xff01;第一个是直接Excel处理完导入&#xff0c;但是这个导入的话虽然简单出错率很大&#xff01;第二个是想直接用php做个小程序直接导入数据&#xff0c;但是想了想2万条数据处理&#xff0c;百分之百浏览器会一直转&#xff0c;最后不知…

JDeveloper中的Java反编译器

Java Decompiler是一个独立的图形实用程序&#xff0c;显示“ .class”文件的Java源代码。 下面是Java Decompiler程序的快照 您可以从这里下载该程序 我将说明如何将此程序用作Jdeveloper中的外部工具 Java Decompiler和Jdeveloper之间的集成 您可以将此程序添加到Jdevelo…

具有Java Kickstart的MongoDB

NoSQL数据库由于其可伸缩性而变得越来越流行。 适当使用时 NoSQL数据库可以提供真正的好处。 MongoDB是使用C 编写的高度可扩展的开源NoSQL数据库。 1.安装MongoDB 您可以根据所使用的操作系统&#xff0c;按照MongoDB官方网站上的说明安装MongoDB&#xff0c;而不会遇到很多麻…

Linux Shell——函数的使用

文/一介书生&#xff0c;一枚码农。 scripts are for lazy people. 函数是存在内存里的一组代码的命名的元素。函数创建于脚本运行环境之中&#xff0c;并且可以执行。 函数的语法结构为&#xff1a; function <function-name> {<code to execute> } 创建函数不需要…

FFmpeg学习2:解码数据结构及函数总结

在上一篇文章中&#xff0c;对FFmpeg的视频解码过程做了一个总结。由于才接触FFmpeg&#xff0c;还是挺陌生的&#xff0c;这里就解码过程再做一个总结。本文的总结分为以下两个部分&#xff1a; 数据读取&#xff0c;主要关注在解码过程中所用到的FFmpeg中的结构体。解码过程中…

JavaFX 2 GameTutorial第4部分

介绍 这是与JavaFX 2游戏教程相关的六个部分系列的第四部分。 如果您错过了第1部分 &#xff0c; 第2部分或第3部分 &#xff0c;我建议您在开始本教程之前仔细阅读它们。 回顾一下&#xff0c;在第3部分中&#xff0c;我为您提供了许多经典街机风格游戏和所使用的不同输入设备…

java构造函数_JAVA的构造函数是怎么写的。万分感谢。路过的请不要嘲笑%_%

展开全部JAVA的构造函数是&#xff1a;SetLocal EnableDelayedExpansionset classpath.for %%c in (lib\*.jar) do set classpath!32313133353236313431303231363533e59b9ee7ad9431333431363030classpath!;%%cset classpath%classpath%;./classes;java com.ham.server.Server。…