C10k problem是一个研究和优化领域,试图在一个单一的商品服务器上实现10,000个并发连接。即使是现在,用传统的Java工具包来解决这个工程任务也是一个挑战。有许多可以很容易实现C10k的响应式方法,RxJava可以使它们非常容易接近。在本章中,我们将讨论几个实现技术,这些技术将提高几个数量级的可伸缩性。它们都围绕着响应式编程的概念。如果您足够幸运地横在做一个新项目,您可能会考虑将您的应用程序从头到尾地响应化。这样的应用程序不应该同步等待任何计算或操作。为了避免阻塞,架构必须完全由事件驱动和异步的。我们将介绍几个简单的HTTP服务器示例,并观察它在设计选择方面的表现。不可否认,性能和可伸缩性确实有一个复杂的代价标签。但是对于RxJava,额外的复杂性将会显著减少。
每个连接对应一个线程的经典模型可以努力来解决C10k问题,有1000个线程我们会像如下这么做:
使用数以GB的RAM存储堆栈空间
对垃圾收集机制施加很大压力,尽管栈空间没有垃圾收集(大量的GC Root和存活的对象)
为了运行不同的线程(上下文切换),浪费了大量的CPU时间。
经典的thread-per- Socket(一个连接一个线程)模型为我们提供了很好的服务,事实上,它在很多应用程序中都非常好用。但是,在达到一定的并发级别之后,线程的数量就变得非常危险。由单个商品服务器处理1000个并发连接并不少见,尤其是使用持久的TCP / IP连接(比如HTTP),它有一个keep- alive的Header、服务器发送事件或WebSockets。然而,每个线程占用了一点内存(栈空间),不管它是计算什么,还是只是在等待数据。
有两种独立的方法可以实现伸缩性:水平和垂直。要处理更多的并发连接,我们可以简单地增加更多的服务器,每个服务器都管理负载的一个子集。这需要前端负载均衡器,并且不能解决我们前面所说的单台服务器的C10k问题。另一方面,垂直可扩展性意味着购买更大更有能力的服务器。但是,由于阻塞I / O,我们需要与未充分利用的CPU相比不成比例的内存 。即使大型企业服务器能够处理成百上千个并发连接(以很高的价格),它也远不能解决C10M问题------一千万个并发连接。这个数字不是巧合;几年前,一个设计合理的Java应用程序在一个典型的服务器上达到了这个巨大的水平。
本章将介绍如何通过不同的方式实现HTTP服务器。从单线程的服务器,通过线程池,到完全事件驱动的架构。这个练习背后的想法是比较(实现的复杂性)VS(性能和吞吐量)。最后,您将注意到,使用RxJava的版本既简单又性能出色。