支持生产阻塞的线程池
在各种并发编程模型中,生产者-消费者模式大概是最常用的了。在实际工作中,对于生产消费的速度,通常需要做一下权衡。通常来说,生产任务的速度要大于消费的速度。一个细节问题是,队列长度,以及如何匹配生产和消费的速度。 (更多…)
在各种并发编程模型中,生产者-消费者模式大概是最常用的了。在实际工作中,对于生产消费的速度,通常需要做一下权衡。通常来说,生产任务的速度要大于消费的速度。一个细节问题是,队列长度,以及如何匹配生产和消费的速度。 (更多…)
前几天发现某个系统对某个远程调用接口的调用量大幅上升,涨幅不可思议。根据接口调用上升的时间点和发布记录,查看SVN提交记录,发现是在系统主路径中添加了这个接口的调用,难道这个接口没有做Cache吗?仔细一看,倒是也做了Cache,并且这个RPC对应的DB表的数据量非常小,按理说是能全部被缓存起来的。那么为什么会反复调用,看起来仿佛没有Cache一样呢?
直觉是缓存被不存在的数据击穿了,马上验证。
通过对系统方法的追踪,发现每次调用传入的参数都是0,再去DB里面查,0对应的结果确实为空。
所以这是一个典型的因为空记录导致的缓存被击穿的案例。
解决方法很简单,对不存在的记录做一个null的Cache,下次就不会落到远端了。不过这里结合业务的特定场景,我只是加了一个判断,当值大于0才会去查询,这样连一次查询Cache的开销也省掉了。
这个简单的问题可以衍生出一些思考。 (更多…)
上一节说到,流水线中的分支预测本身是为了提高整条流水线的并行度,为此,CPU做了很多努力,例如乱序执行,甚至于流水线本身也是为了这个目的而诞生的。
和我们编写一般程序一样,顺序执行总是最简单、最安全的,指令被一条接着一条地顺序执行,没有人会思考任何有关并发的隐患。但是一旦踏入并发编程的范畴,似乎就开始变得一团糟,你需要考虑数据竞争、锁、内存等等一系列问题。和分支预测一样,有时候你会采用一些试探性的方法去处理并发中产生的问题,例如经典的CAS(Compare And Swap)算法,可能成功可能失败,喜忧参半。
在流水线中也存在着类似的大冒险,典型的有三种:
数据冒险
结构冒险
控制冒险
对应的,也有一些方法去辅助CPU在这些冒险的过程中,尽可能地达到我们期望的结果。 (更多…)
在现代CPU中,为了提高执行的性能,CPU的多个单元会同时执行多条指令。例如当取址单元正在寻找下一条指令前,上一条指令的译码和执行已经在进行中了,这一套机制被称作CPU流水线(pipeline)。
CPU流水线架构把指令的执行分为了多个阶段,每个单元只负责完成指令执行过程中的一个阶段,而中间结果由专门的流水线寄存器暂存。这样理论上,一条指令的执行假设被分为5个阶段,那么当5个单元同时运行一段时间后,理论上相同时间可以同时执行5条指令,当然这只是最简单的情况,实际的情况要复杂得多。

流水线的引入相当于程序中引入了并发,相应的,会带来很多额外的问题。例如为了更好地让指令流水般地执行,不涉及顺序一致性的指令会被重排序。这里不详细讨论太多流水线的技术细节,只要知道指令并不是一条一条顺序执行的,那样会严重阻碍处理器的性能。
CPU流水线引入的目的在于,希望能够在每个CPU的时钟周期都发射一条新的指令,这样理论上可以达到最高效率。但这有一个前提:如果指令的执行是每个时钟周期一条,那么指令的取值也必须达到每个时钟周期一条,如此,当你在取址阶段拿到要执行的指令时,下一条指令的地址必须被确定了,否则下一个时钟周期便无法取出对应的指令。 (更多…)
在大规模互联网应用中,负载均衡设备是必不可少的一个节点,源于互联网应用的高并发和大流量的冲击压力,我们通常会在服务端部署多个无状态的应用服务器和若干有状态的存储服务器(数据库、缓存等等)。
负载均衡设备的任务就是作为应用服务器流量的入口,挑选最合适的一台服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的,是后端的集群。
一个典型的互联网应用的拓扑结构是这样的:
之前写过一个Blog分享Linux下的几种I/O Scheduler,这次分享一个slide,内容更全一点。
你也可以在slideshare查看和下载:http://www.slideshare.net/heseymx/linux-io-scheduler
在现代计算机体系中,机械硬盘仍然作为大部分情况下的存储设备使用,而机械硬盘的访问相对内存差了多个数量级,主要原因在于机械臂转动的寻道时间太长,机械操作没法跟上电子信号的传递,所以OS不可能对每次I/O请求都直接作寻道处理,而是需要额外的工作。
在Linux中,这部分工作主要由I/O调度器完成。 (更多…)
早期的SSLv2根据经典的公钥基础设施PKI(Public Key Infrastructure)设计,它默认认为:一台服务器(或者说一个IP)只会提供一个服务,所以在SSL握手时,服务器端可以确信客户端申请的是哪张证书。
但是让人万万没有想到的是,虚拟主机大力发展起来了,这就造成了一个IP会对应多个域名的情况。解决办法有一些,例如申请泛域名证书,对所有*.yourdomain.com的域名都可以认证,但如果你还有一个yourdomain.net的域名,那就不行了。
在HTTP协议中,请求的域名作为主机头(Host)放在HTTP Header中,所以服务器端知道应该把请求引向哪个域名,但是早期的SSL做不到这一点,因为在SSL握手的过程中,根本不会有Host的信息,所以服务器端通常返回的是配置中的第一个可用证书。因而一些较老的环境,可能会产生多域名分别配好了证书,但返回的始终是同一个。
既然问题的原因是在SSL握手时缺少主机头信息,那么补上就是了。
SNI(Server Name Indication)定义在RFC 4366,是一项用于改善SSL/TLS的技术,在SSLv3/TLSv1中被启用。它允许客户端在发起SSL握手请求时(具体说来,是客户端发出SSL请求中的ClientHello阶段),就提交请求的Host信息,使得服务器能够切换到正确的域并返回相应的证书。
要使用SNI,需要客户端和服务器端同时满足条件,幸好对于现代浏览器来说,大部分都支持SSLv3/TLSv1,所以都可以享受SNI带来的便利。 (更多…)
©2006 - 2012 Hesey (舒)