性能主题

单独写原则Single Writer Principle

  当我们试图建立一个高度可扩展的系统,最大的一个限制是:对同一个资源会有多个竞争写操作。 计算机科学归结为2个基本的方法:一是提供资源的互斥锁,另一种是采取乐观的策略。

Mutual Exclusion互斥

  相互排斥是某个时间对同一个受保护资源保证只有一个写操作,这是通过锁策略实施的。锁策略需要一名仲裁员,通常这个仲裁员是来自操作系统内核,当发生争夺时它决定谁能获得锁,以及以什么顺序获得。这是一个非常昂贵的过程,通常我们需要更多的CPU循环实现我们的业务逻辑,而不是做这些“家务事”。对于那些等待进入临界区,提前进行Mutual的还必须排队,排队效果(Little’s Law)导致延迟变得难以预测,最终制约了吞吐量。这是一种堵塞Blocking做法。

 

Optimistic Concurrency Control乐观并发锁

  比如Hibernate或JPA都有乐观锁策略,见:JPA/Hibernate:基于版本的乐观锁并发控制,包括MongoDB的乐观锁

  乐观的策略是:保留有数据的一个副本,当修改数据时,如果在此期间原本尚未发生变化,那么复制数据的变化覆盖原本。如果在此期间原本发生的变化,你重复这个过程,直到成功为止。

  这种重复过程中增加争夺可能性,会造成排队的效果,就如同相互排斥锁一样。现实中源代码控制系统如Subversion或CVS都在使用这种算法。乐观的策略能够在争夺数据情况下使用,但在争夺一些硬件资源下却工作得不怎么好,因为你不能获得一个硬件资源的副本! 也许只有通过CAS指导硬件完成执行原子数据的变化。

CPU管理争夺

  CPU每个循环周期会处理一个或多个指令。例如,现代英特尔CPU内核,每个内核有6个执行单元,可以做并行算法、分支逻辑、字操作和内存加载/存储组合等指令。如果一边做工作时, CPU核未命中高速缓存,它就会到主内存去拿取,它会循环数百次等待直到该内存请求返回的结果。现代 CPU为此提升了预测算法进行预测,对一个内存请求将返回继续处理这种情况做一些预测。如果第二个未命中再次发生时, CPU将不再预测,只需等待内存请求返回,因为它通常不能保持状态进行预测直至超过两个未命中高速缓存。管理高速缓存的未命中,是扩展我们目前这一代处理器性能的最大限制。

  当系统花费更多时间实现争夺管理而不是做实际业务工作时,高争夺反而更容易发生,下表显示管理争夺的时间,程序状态很小,很容易从L2/L3重新加载,不用考虑主内存:

Method Time (ms)
One Thread 300
One Thread with Memory Barrier 4,700
One Thread with CAS 5,700
Two Threads with CAS 18,000
One Thread with Lock 10,000
Two Threads with Lock 118,000


单写操作设计

  如果只有一个线程对资源进行写操作,它实际上是比你想象的更容易,这个方案是可行的。当然,如果有多个线程读取相同的数据。 CPU可以通过高速缓存一致性的子系统广播只读数据的拷贝到其他核。这虽然有成本的,但它的尺度非常好。

  单个线程写操作无需CPU浪费管理资源争夺或上下文切换。目前 Node.js, Erlang, Actor 模式, SEDA 都采取了单写解决方案,但是他们大多数使用基于队列的下实现的,它打破单一作家的原则,而Disruptor分离了关注,真正实现单写原则。(Disruptor的特点是将多线程生产者通过Ringbuffer变成单线程消费者,通过单线程消费者对共享资源进行写操作)

  而Disruptor提供了比锁和基于状态的竞争策略更好地吞吐量,也提供了更多可预见的延迟,而不是传统的J-curve型曲线延迟轮廓保持不变,直到硬件饱和。

  这一原则也适用于各级规模,比如原来认为在SOA架构将数据写入存储库中也许能更好地扩展,在这样情况下,相关数据都是被存储在一个数据库和其他服务中,如果是直接去访问这些数据,而不是向拥有数据的服务发送消息,那么数据库就也是需要管理争夺的。当然,这也会阻止了服务从缓存中获取数据以快速响应客户端,降低整体性能,导致数据库IO经常成为吞吐量和性能的瓶颈。

  总结如下:

  多个线程如果同时写同一个资源,必有争夺,就需要用锁或乐观锁等堵塞方法,而非堵塞的单线程写比多线程写要快,能获得高吞吐量和低延迟,特别是多核情况,一个线程一个CPU核,大大增加其他CPU核并行运行其他线程的概率。LMAX架构使用Disruptor每秒处理600万订单。

SOA并不能解决高并发事务

低延迟系统的最佳实践

Disruptor

并发编程

为什么说互联网金融是对传统软件的一种颠覆

JPA/Hibernate:基于版本的乐观锁并发控制

LMAX架构

PayPal从Java迁移到Node.js 

Jdon框架

猜你喜欢