进程上下文切换 – 残酷的性能杀手(上)

对于服务器的优化,很多人都有自己的经验和见解,但就我观察,有两点常常会被人忽视 – 上下文切换 和 Cache Line同步 问题,人们往往都会习惯性地把视线集中在尽力减少内存拷贝,减少IO次数这样的问题上,不可否认它们一样重要,但一个高性能服务器需要更细致地去考察这些问题,这个问题我将分成两篇文章来写:

1)从一些我们常用的用户空间函数,到linux内核代码的跟踪,来看一个上下文切换是如何产生的

2)从实际数据来看它对我们程序的影响

另外,关于Cache Line 的测试大家可移步 http://www.cppthinker.com/cpp/9/cpu_cache/

Chaos网络库(二)- Buffer的设计

对于buffer的设计,chaos和其他网络库的做法稍有不同,就拿libevent-stable-1.4.13(以下所提到libevent处皆为该版本)来说,它采用一种能够自动扩张的buffer,基本策略如下:

1. 当缓冲区不够存放新数据时,它会先在内部做marshal,看看是否能够腾挪出足够的空间

2. 假如没有满足,那么对buffer进行expand, 大小为原来的两倍,扩张之后该buffer就不会缩小

另外,libevent中有两个buffer,input 和 output, 分别代表读缓冲和写缓冲,libevent对他们扩张时的策略稍有不同

对于input,libevent限定它最大的缓冲大小为4096,这对于现在的网络环境,尤其是内网环境肯定是不太够的

对于output,libevent没有限定大小

这样做在普通的稳定传输下不会有什么问题,但是假如上层将很大的一块数据块(1MB以上)放进output,或者是上层快速地将小块数据放入output,而底层的IO复用的线程由于某些情况没有来得及响应,都会导致output增长到非常大的程度,而由于buffer只能伸不能缩的性质,在之后的传输过程中内存使用率就会很低

考虑这样一个场景,一个应用在接收一个新连接之后,会首先发送一大块的数据(2MB)给对端进行初始化,而上层又没有对这2MB的数据进行分块发送,直接放进了output中,output被直接撑大到2MB(应该说起码2MB),这当然没问题,传输一样可以顺利完成,但在数据初始化完毕后,该应用持续发送的都是小包,那么这2MB多的output就被浪费了

Chaos网络事件库开篇介绍(一)

Chaos是一个基于Linux平台, c++开发的reactor模式的网络事件库, 目前仅支持TCP传输协议, 仅在x86_64下编译, 并遵循3-clause BSD开源协议. 在使用上, 可以说它很像boost asio, 可能是由于我对boost asio的接口设计很有爱吧, 而且对于boost asio在异步编程方面的思想, 我个人也比较认同, 但至今我也没有仔细阅读过boost asio的源码, 一是boost的模板化编程在可读性上让我比较折磨, 其二则是不想在对设计先入为主的情况下去开发chaos, 很多事情只有我们自己亲自去思考, 才能有所收获.

 

进入主题, 关于chaos库源码和所有测试用例和应用服务, 都可在https://github.com/lyjdamzwf/chaos 下载

Linux服务器时间相关结构体和函数整理

一、时间类型
Linux下常用的时间类型有4个:time_t,struct timeb, struct timeval,struct timespec,clock_t, struct tm.

(1) time_t是一个长整型,一般用来表示用1970年以来的秒数
该类型定义在中,一般通过 time_t time = time(NULL); 获取.

(2) struct timeb结构: 主要有两个成员, 一个是秒, 另一个是毫秒, 精确度为毫秒.

    struct timeb
    {
        time_t time;
        unsigned short millitm;
        short timezone;
        short dstflag;
    };

多核环境下编写程序需注意Cache

前 阵子接触到一道关于数组内部链表(多用于内存池技术)的数据结构的题, 这种数据结构能够比普通链表在cache中更容易命中, 理由很简单, 就是因为其在地址上是连续的(=.=!), 借这个机会, 就对cpu cache进行了一个研究, 今天做一个简单的分享, 首先先来普及一下cpu cache的知识, 这里的cache是指cpu的高速缓存. 在我们程序员看来, 缓存是一个透明部件. 因此, 程序员通常无法直接干预对缓存的操作. 但是, 确实可以根据缓存的特点对程序代码实施特定优化, 从而更好地利用高速缓存. 

高速缓存的置换策略会尽可能地将访问频繁的数据放入cache中, 这是一个动态的过程, 所以cache中的数据不会一直不变. 目前一般的机器的cpu cache可分为一级缓存和二级缓存. 一级缓存更靠近cpu, 速度比二级缓存更快. 二级缓存比一级缓存速度更慢, 容量更大, 主要就是做一级缓存和内存之间数据临时交换的地方用.
这两者和RAM在空间和效率上的关系如下:
L1 Cache —> L2 Cache —> RAM
————> 容量递增 ————>
————> 速度递减 ————>
—–> CPU访问优先级递减 —–>

在linux系统中, 我们可以使用cat /proc/cpuinfo 来获知机器的cpu和核数.