我眼中的 Nginx(一):Nginx 和位运算

本文探讨了 Nginx 中位运算的运用,如内存对齐以提高性能,位图用于标记状态,以及寻找最低位和最高位 1 的位置的技巧。作者张超分享了 Nginx 源码中的经典位运算实例,这些技巧在 Nginx 的性能优化中起着关键作用。
摘要由CSDN通过智能技术生成

作者张超:又拍云系统开发高级工程师,负责又拍云 CDN 平台相关组件的更新及维护。Github ID: tokers,活跃于 OpenResty 社区和 Nginx 邮件列表等开源社区,专注于服务端技术的研究;曾为 ngx_lua 贡献源码,在 Nginx、ngx_lua、CDN 性能优化、日志优化方面有较为深入的研究。

众所周知 Nginx 以性能而出名,这和它优秀的代码实现有着密切的关系,而本文所要讲述的——位运算,也是促成 Nginx 优秀性能的原因之一。

位运算在 Nginx 的源码是处处可见,从定义指令的类型(可以携带多少参数,可以出现在哪些配置块下),到标记当前请求是否还有未发送完的数据,再到 Nginx 事件模块里用指针的最低位来标记一个事件是否过期,无不体现着位运算的神奇和魅力。

本文会介绍和分析 Nginx 源码里的一些经典的位运算使用,并扩展介绍一些位其他的位运算技巧。

对齐

Nginx 内部在进行内存分配时,非常注意内存起始地址的对齐,即内存对齐(可以换来一些性能上的提升),这与处理器的寻址特性有关,比如某些处理器会按 4 字节宽度寻址,在这样的机器上,假设需要读取从 0x46b1e7 开始的 4 个字节,由于 0x46b1e7 并不处在 4 字节边界上(0x46b1e7 % 4 = 3),所以在进行读的时候,会分两次进行读取,第一次读取 0x46b1e4 开始的 4 个字节,并取出低 3 字节;再读取 0x46b1e8 开始的 4 个字节,取出最高的字节。我们知道读写主存的速度并不能匹配 CPU,那么两次的读取显然带来了更大的开销,这会引起指令停滞,增大 CPI(每指令周期数),损害应用程序的性能。

因此 Nginx 封装了一个宏,专门用以进行对齐操作。

#define ngx_align(d, a)     (((d) + (a - 1)) & ~(a - 1))

如上代码所示,该宏使得 d 按 a 对齐,其中 a 必须是 2 的幂次。

比如 d 是 17,a 是 2 时,得到 18;d 是 15,a 是 4 时,得到 16;d 是 16,a 是 4 时,得到 16。

这个宏其实就是在寻找大于等于 d 的,第一个 a 的倍数。由于 a 是 2 的幂次, 因此 a 的二进制表示为 00…1…00 这样的形式,即它只有一个 1,所以 a - 1 便是 00…01…1 这样的格式,那么 ~(a - 1) 就会把低 n 位全部置为 0,其中 n 是 a 低位连续 0 的个数。所以此时如果我们让 d 和 ~(a - 1) 进行一次按位与操作,就能够把 d 的低 n 位清零,由于我们需要寻找大于等于 d 的数,所以用 d + (a - 1) 即可。

位图

位图,通常用以标记事物的状态,“位” 体现在每个事物只使用一个比特位进行标记,这即节约内存,又能提升性能。

Nginx 里有多处使用位图的例子,比如它的共享内存分配器(slab),再比如在对 uri(Uniform Resource Identifier)进行转义时需要判断一个字符是否是一个保留字符(或者不安全字符),这样的字符需要被转义成 %XX 。

static uint32_t   uri_component[] = {
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */

/* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
        0xfc009fff, /* 1111 1100 0000 0000  1001 1111 1111 1111 */

/* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
        0x78000001, /* 0111 1000 0000 0000  0000 0000 0000 0001 */

/*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
        0xb8000001, /* 1011 1000 0000 0000  0000 0000 0000 0001 */

        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
        
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值