Reactor简介
Reactor是一个基础库,用在构建实时数据流应用、要求有容错和低延迟至毫秒、纳秒、皮秒的服务。
— PrefaceTL;DR
什么是Reactor?
让我们大致了解一下Reactor。在你使用喜欢的搜索敲入一些关键词如Reactive、spring Reactive、Asynchronous java或者仅仅是"What the heck is Reactor?".简而言之,Reactor是一个轻量级的JVM基础库,它可以帮助我们构建的服务和应用高效而异步的传递消息。
高效的含义是什么呢?
传递一个消息从A到B时GC产生的内存很小或者完全没有。
当消费者处理消息的速度低于生产者产生消息的速度时产生了溢出时,必须尽快处理。
尽可能的提供无锁的异步流。
据以往的经验来看,我们知道异步编程是困难的,特别是当一个平台提供了很多选项如JVM。
Reactor瞄准绝大部分场景中真正的无阻塞,并且提供了一组比原生Jdk的java.util.concurrent库更高效的API。Reactor也提供了一个可选性(不建议使用):
阻塞等待:如Future.get()。
Unsafe数据获取:如ReentrantLock.lock()。
异常抛出:如try ..catch ...finally
同步阻塞:如 syschronized
Wrapper配置(GC压力):例如 new Wrapper<T>(event)
让我们先使用一个纯正的Executor方法:
private ExecutorService threadPool = Executors.newFixedThreadPool(8); final List<T> batches = new ArrayList<T>(); Callable<T> t = new Callable<T>() { //1 public T run() { synchronized(batches) { //2 T result = callDatabase(msg); //3 batches.add(result); return result; } } }; Future<T> f = threadPool.submit(t); //4 T result = f.get() //5
1.分配回调方法---可能会导致gc压力。
2.Synchronization将强制对每个线程停止检查。
3. 存在消费者的消费能力低于生产者生产能力的隐患。
4. 使用线程池将task传递到目标线程--肯定通过FutureTask给gc造成压力。
5. 阻塞直至callDatabase()响应。
从上述的简单示例中,容易看出扩展性会受到严重的影响。
不断分配的对象将导致gc停止工作,特别是耗时比较多的大任务时。当一个gc停止工作时将会从降低全局的性能。
队列默认情况下长度是不受限制的。任务会堆积到数据库中。
后台日志不是一个内存泄露的地方,但是副作用就比较烦人了:在gc暂停工作时需要扫描更多对象;损失数据重要bit的风险;等等。
经典链接Queue分配节点时产生的内存压力。
使用阻塞方式应答请求时发生恶性循环。
阻塞方式应答导致生产者效率慢下来。实际上,因为需要提交更多任务时等待响应,流程变成了基本的同步方式。
同数据存储的通信异常将以不友好的形式传递到生产者,通过线程边界来分离工作,这使容错的协商变的比较容易。
完全的、真正的非阻塞比较难以实现---特别是有比较时髦名称的分布式系统中如微服务架构。然而,Reactor却没有妥协,它试图利用可用的最佳模式来使开发者不必觉得像是在写一个数学论文而仅仅是一个微服务(nanservice)。
没有什么比较光更快的了(除了流言蜚语和病毒猫视频),在某些方面,延迟是每个真实世界的系统必须关注的。为此:
限制主消息传送结构,因而不会导致任务无限的累积。
利用流行的模式例如Reactive和事件驱动架构来提供一个包含应答的非阻塞的、端对端流。
实现了最新的Reactive流标准,通过不发送多于当前容量的请求来使受限的结构更有效率。
使用这些概念到进程间通信,提供了理解控制流的非阻塞IO驱动。
对开发者暴露功能API,帮助开发者使用一个无副作用的方式组织代码,也帮助你确定在什么场景下你是线程安全和具有容错性的。