最近在做在线架构的实现,在线架构和离线架构近线架构最大的区别是服务质量(SLA,Service Level Agreement,SLA 99.99代表10K的请求最多一次失败或者超时)和延时。而离线架构在意的是吞吐,SLA的不会那么严苛,比如99.9。离线架构一般要有流控,以控制用户发送请求的速度。以免多于服务端处理能力的请求造成大量的数据在buffer或者队列里堆积,造成大量的超时。在线架构不可能有流控了,你不能限制用户的请求。因此在线架构对于弹性扩容有很高的要求,在大量请求到来时自动扩展后台的服务能力。比如当前的请求已经占用了集群的70%的资源时,系统需要自动的扩容;相反,当前的请求仅仅占用了集群20%的资源时,有必要回收一部分资源了。要知道,公司机房的电费还是很贵的。

当然了在线和离线架构的相同和区别谈起来完全是一个大文章。本文主要关注在处理高并发请求的锁的使用上。几个原则吧:

  1. 不要使用全局锁。使用全局锁代表在需要请求锁时,其他为得到锁的线程都会等待,这将导致服务能力急剧下降。
  2. 一定要注意锁的作用范围,一定要保证锁作用于足够小的范围。一定不要在锁定区域有等待操作,比如IO调用。
  3. 尽量的考虑修改架构,避免加锁。

试想一个场景,为了服务质量,我们可能发送多个请求到后台,以达到:

  1. 高可用行,后台的某个节点挂了,有其他的backup request会被请求。如果节点的SLA是99%(很低了),那么发送2个请求到后台,SLA可以达到99.99%;如果单个节点的SLA是99.9%的话,SLA可以达到99.9999了,即百万次请求至多一次失败。
  2. 低延时,第一个回来的请求会响应,这样的话能够保证某些慢的节点不会影响系统整体的延时。

那么如何判断第一个请求是第一个达到的呢?

先想一个比较粗暴的办法:使用一个set记录未返回的request 的id,然后在接到响应时,查看这个set有没有这个id,如果有,删除它,并且响应client;第二个以后的响应达到时,由于在set已经没有这个id了,因此这些请求将被丢弃。

这个里边涉及到对set的读和写操作,这个需要加锁;如果这个set是进程内可见的,那么这个锁就是进程级别的(或者说该进程或者说是线程的子线程都是可见的),加锁时很多线程都会等待该锁。这样的话对性能会有很大损耗。

这个方法对于每秒几百次请求是没有问题的。但是如果达到千这个级别,那么锁的使用会达到数千次(比如1000个请求,发送3个请求到后台,那么每次写set加一次锁,3个请求回来都会加一次锁,因此相当于一个真实的请求会加锁4次,1000个请求就是4000次,想想都恐怖,1s要加锁4000次,锁的代价再小也很恐怖吧,别说set的插入和查询,删除也有不可忽略的性能损耗)。

那么可不可以加线程级别的锁?线程级别的锁会减少对其他线程的影响。但是,set如果也是线程级别的,那么得保证异步回调的借口也得是在同一个线程才可以。否则这个线程发出的请求,被其他的线程得到,那么上述的逻辑是不通的,因为set是线程级别的,对于其他线程来说是不可见的。这样的话如果架构能够保证一个异步请求的返回,也是在同一个线程处理就好了。那么,如果架构可以这么保证,那么你根本不需要锁,为什么呢?因为一个线程都是顺序执行的,不会有资源的竞争,因此读写set都是安全的,因此不需要加锁。

那么问题来了,架构如何支持这个异步回调也是走到相同的线程里?

一个实现就是实现一个线程池,对于特定的request id,基于一定的规则将他调度给一个工作线程;等到异步返回时,再通过这个request id调度给相同的线程处理。

那么如何实现一个线程池?boost 里有; 如果调度,boost 支持调度给哪个线程。问题解决。

睡觉。

当然了,你以为无锁编程会涉及CAS,那么可以移步 并发编程(三): 使用C++11实现无锁stack(lock-free stack)

海量并发的无锁编程 (lock free programming)的更多相关文章

  1. 我是如何一步步的在并行编程中将lock锁次数降到最低实现无锁编程

    在并行编程中,经常会遇到多线程间操作共享集合的问题,很多时候大家都很难逃避这个问题做到一种无锁编程状态,你也知道一旦给共享集合套上lock之后,并发和伸缩能力往往会造成很大影响,这篇就来谈谈如何尽可能 ...

  2. 【Java并发编程】2、无锁编程:lock-free原理;CAS;ABA问题

    转自:http://blog.csdn.net/kangroger/article/details/47867269 定义 无锁编程是指在不使用锁的情况下,在多线程环境下实现多变量的同步.即在没有线程 ...

  3. [转]透过 Linux 内核看无锁编程

    非阻塞型同步 (Non-blocking Synchronization) 简介 如何正确有效的保护共享数据是编写并行程序必须面临的一个难题,通常的手段就是同步.同步可分为阻塞型同步(Blocking ...

  4. 无锁编程以及CAS

    无锁编程 / lock-free / 非阻塞同步 无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Sy ...

  5. 无锁编程(一) - Double-checked Locking

      Double-checked Locking,严格意义上来讲不属于无锁范畴,无论什么时候当临界区中的代码仅仅需要加锁一次,同时当其获取锁的时候必须是线程安全的,此时就可以利用 Double-che ...

  6. 4.锁--无锁编程以及CAS

    无锁编程以及CAS 无锁编程 / lock-free / 非堵塞同步 无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被堵塞的情况下实现变量的同步,所以也叫非堵塞同步(Non-b ...

  7. 无锁编程 - Double-checked Locking

    Double-checked Locking,严格意义上来讲不属于无锁范畴,无论什么时候当临界区中的代码仅仅需要加锁一次,同时当其获取锁的时候必须是线程安全的,此时就可以利用 Double-check ...

  8. C++11原子操作与无锁编程(转)

    不讲语言特性,只从工程角度出发,个人觉得C++标准委员会在C++11中对多线程库的引入是有史以来做得最人道的一件事:今天我将就C++11多线程中的atomic原子操作展开讨论:比较互斥锁,自旋锁(sp ...

  9. C++性能榨汁机之无锁编程

    C++性能榨汁机之无锁编程 来源 http://irootlee.com/juicer_lock_free/ 前言 私以为个人的技术水平应该是一个螺旋式上升的过程:先从书本去了解一个大概,然后在实践中 ...

随机推荐

  1. Go学习——new()和 make()的区别详解(转载)

    这篇文章主要介绍了Go语言中new()和 make()的区别详解,本文讲解了new 的主要特性.make 的主要特性,并对它们的区别做了总结,需要的朋友可以参考下 概述 Go 语言中的 new 和 m ...

  2. 【BZOJ2705】【Sdoi2012】Longge的问题

    Description Longge的数学成绩非常好,并且他非常乐于挑战高难度的数学问题.现在问题来了:给定一个整数N,你需要求出\(\Sigma gcd(i, N) (1 \leq i \leq N ...

  3. ●POJ 1741 Tree

    题链: http://poj.org/problem?id=1741题解: 树上点分治. 入门题,不多说了. 代码: #include<cstdio> #include<cstrin ...

  4. UVA 11584 划分回文字串

    将其划分为尽可能少的回文串 dp[i] = min(dp[i],dp[j] + 1)    来表示j+1~i是回文串 #include <iostream> #include <cs ...

  5. python中读取文件数据时要注意文件路径

    我们在用python进行数据处理时往往需要将文件中的数据取出来做一些处理,这时我们应该注意数据文件的路径.文件路径不对,回报如下错误: FileNotFoundError: File b'..Adve ...

  6. Spring使用webjar

    注意事项 这玩意很简单,但是我们第一次搞就是搞不成功,为什么呢?因为我们都用的是idea或者eclipse编译.webjar只能在maven上才能打包,所以在使用时,记得maven-clean和mav ...

  7. MySQL中UTF8编码的数据在cmd下乱码

    MySQL中UTF8编码的数据在cmd下乱,在数据库ide中看到的却是中文. 其实,原因是cmd用gbk的格式来显示数据,那么我们只需要将utf-8存储的数据用gbk的格式输出到cmd即可. 解决方法 ...

  8. 如何用cmd通过sublime打开文件?

    sublime 提供了专门的命令工具subl.exe,就在它的安装目录之下,讲安装目录配置到系统环境变量中就OK了.具体如下: 1.找到sublime安装路径 如我的默认路径:C:\Program F ...

  9. day06 Request Response

    rw 读写模板的设置 day05 Request Response 1. HttpServletResponse 简介 1.1 Response 的 OutputStream 输出中文的问题 1.2 ...

  10. Why Helm? - 每天5分钟玩转 Docker 容器技术(160)

    本章我们将学习 Helm,Kubernetes 的包管理器. 每个成功的软件平台都有一个优秀的打包系统,比如 Debian.Ubuntu 的 apt,Redhat.Centos 的 yum.而 Hel ...