您的 Java 低延迟应用程序的开发清单是啥?

Posted

技术标签:

【中文标题】您的 Java 低延迟应用程序的开发清单是啥?【英文标题】:What is your development checklist for Java low-latency application?您的 Java 低延迟应用程序的开发清单是什么? 【发布时间】:2011-02-04 04:46:01 【问题描述】:

我想为 Java 低延迟应用程序创建综合清单。您可以在此处添加您的清单吗?

这是我的清单 1. 让你的对象不可变 2.尽量减少同步方法 3. 锁定订单应有据可查,并谨慎处理 4. 使用分析器 5. 使用 Amdhal 定律,找到顺序执行路径 6. 使用 Java 5 并发实用程序和锁 7. 避免线程优先级,因为它们依赖于平台 8. 可以使用JVM预热 9. 更喜欢不公平的锁定策略 10. 避免上下文切换(许多线程会导致适得其反) 11. 避免装箱、拆箱 12. 注意编译器警告 13.线程数应等于或小于内核数

每毫秒调整一次低延迟应用程序。

【问题讨论】:

许多人编写响应时间远低于 1 毫秒的低延迟 Java 应用程序。对我来说,Java 中的低延迟意味着亚毫秒级。 "6. 使用锁" => 甚至更好,尝试让你的算法无锁。 (A) 锁定还不错,争用才是。了解如何避免争用(如果争用 CAS,无锁可能会更糟)。 (B) 利特尔定律。 (C) 围绕 CPU 缓存进行优化 【参考方案1】:

虽然不变性很好,但不一定会改善延迟。确保低延迟可能取决于平台。

除了一般性能之外,GC 调优也很重要。减少内存使用将有助于 GC。特别是如果你可以减少需要移动的中年对象的数量 - 让它保持长期或短期的对象。还要避免任何接触烫发的东西。

【讨论】:

Hawtin,当您不必围绕共享数据进行同步时,使用不可变数据结构是否有助于延迟? 这可能是这里最好的答案【参考方案2】:

避免装箱/拆箱,尽可能使用原始变量。

【讨论】:

【参考方案3】:

在消息处理路径上尽可能避免上下文切换 后果:使用 NIO 和单事件循环线程(reactor)

【讨论】:

【参考方案4】:

购买、阅读并了解Effective Java。还有available online

【讨论】:

【参考方案5】:

避免大量锁定和多线程,以免破坏现代处理器(及其缓存)中的增强功能。然后,您可以使用单线程达到令人难以置信的极限(每秒 600 万次事务),并且延迟非常低。

如果您想查看真实世界的低延迟 Java 应用程序,并了解其架构的足够详细信息,请查看 LMAX:

The LMAX Architecture

【讨论】:

【参考方案6】:

测量,测量和测量。使用尽可能接近真实数据和接近生产硬件的数据来定期运行基准测试。低延迟应用程序通常被更好地视为设备,因此您需要考虑部署的整个盒子,而不仅仅是特定的方法/类/包/应用程序/JVM 等。如果您没有在生产环境等设置上构建现实的基准测试,您将在生产。

【讨论】:

【参考方案7】:

在您的应用程序中调度的线程数不要超过底层硬件上的内核数。请记住,操作系统将需要线程执行,并且可能需要其他服务共享相同的硬件,因此您的应用程序可能需要使用少于可用内核的最大数量。

【讨论】:

这适用于计算密集型任务,不一定适用于具有更多线程有意义的阻塞/IO/其他任务。如果您有更多线程然后是内核,那么您将需要“聚集”它们,以便计算密集型线程与阻塞线程分开固定。【参考方案8】: 考虑使用非阻塞方法而不是同步。 考虑在阻塞数据结构和锁上使用易失性或原子变量。 考虑使用对象池。 使用数组而不是列表,因为它们对缓存更友好。 由于锁定以及内存和缓存访问延迟,通常对于将数据发送到其他内核的小型任务可能比在单个内核上处理需要更多时间。因此,请考虑通过单个线程处理任务。 降低访问主存的频率,并尝试使用缓存中存储的数据。 考虑选择专注于性能优化的服务器端 C2 JIT 编译器,而不是专注于快速启动时间的 C1。 当不同线程使用的两个字段可以位于单个缓存行上时,请确保您没有错误的对象字段共享。 阅读https://mechanical-sympathy.blogspot.com/ 考虑使用 UDP over TCP

【讨论】:

【参考方案9】:

在生成大字符串时使用StringBuilder 而不是String。例如查询。

【讨论】:

只有当你想用字符串做某事时才有意义,例如连接其他字符串或反转等。 通常没有区别。 Java 编译器为字符串连接生成的字节码使用 StringBuilders! 循环(或多个语句)中的连接是显式 StringBuilder 获胜的常见情况。【参考方案10】:

另一个重要的想法是首先让它工作,然后测量性能,然后隔离任何瓶颈,然后优化它们,然后再次测量以验证改进。

正如 Knuth 所说,“过早的优化是万恶之源”。

【讨论】:

很少有应用程序的成功或失败只取决于性能。尽管过早优化是错误的,但该规则不适用于每个应用程序。低延迟应用程序的构建必须遵循一定的准则。 我一直喜欢“先让它工作,然后再让它快速工作”。 我想记住,话虽如此,Knuth 将大部分时间都献给了算法效率。 :) 牢记完整的引用:“我们应该忘记小的效率,比如大约 97% 的时间:过早的优化是万恶之源。但我们不应该放弃我们的机会关键的 3%。”【参考方案11】:

我认为“仅在适当的情况下使用可变对象”比“使您的对象不可变”更好。许多非常低延迟的应用程序都有他们重用的对象池以最小化 GC。不能以这种方式重用不可变对象。例如,如果您有一个 Location 类:

class Location 
    double lat;
    double lon;

您可以在启动时创建一些并反复使用它们,这样它们就不会导致分配和随后的 GC。

虽然这种方法比使用不可变的位置对象要复杂得多,所以它应该只在需要的地方使用。

【讨论】:

【参考方案12】:

除了这里已经推荐的开发人员级解决方案之外,考虑加速 JIT 运行时(例如 Zing)和堆外内存解决方案(如 Teracotta BigMemory、Apache Ignite)也非常有益,以减少 Stop-the-world GC 暂停。 如果某些 GUI 涉及使用像 Hessian 这样的二进制协议,ZERO-C ICE 而不是 webservice 等是非常有效的。

【讨论】:

以上是关于您的 Java 低延迟应用程序的开发清单是啥?的主要内容,如果未能解决你的问题,请参考以下文章

高吞吐低延迟Java应用的垃圾回收优化

高吞吐低延迟 Java 应用的 GC 优化实践

java中Spring是啥?

Cloudflare Stream 低延迟高性价比,值得入手

低延迟架构体系初探:如何从硬件到应用开发提升性能?

低延迟架构体系初探:如何从硬件到应用开发提升性能?