如何让glog性能提高10倍

背景

最近在给glog做性能优化, 使用c++版本 glog-0.3.4做压测,测试数据总量为1.5g, 起12个线程循环写133个字节的日志条目,测试结果耗时175s,每秒大约8-9MB的吞吐量。
在此测试基础上,我对glog进行了一系列的性能优化,优化后耗时16s,性能为glog原生版本的10倍。

优化过程

去localtime函数调用

查看glog源码,在获取日期的时候使用了localtime, localtime_r这两个函数,而这两个函数调用了__tz_convert, __tz_convert有tzset_lock全局锁,每次获取时间都会使用到kernel级别的futex锁,所以优化第一步是去掉glibc的localtime函数,使用getimeofday获取秒数和时区,用纯耗cpu的方式算出日期,稍微复杂一点的计算就是闰年闰月的转换。将这段函数替换后,耗时从175s减少成46s,性能瞬间提高4-5倍。

减少锁粒度

再翻看glog的源码,glog是一个多线程同步写的操作,简化代码就是 lock();dosomething();fwrite();unlock(); fwrite本身就是线程安全的,缩小锁粒度需要改成lock();dosomething();unlock();fwrite(); 其他变量都比较好处理,比如文件名之类的,不好处理的是轮转的时候会更改fd, fwrite()会使用到fd。我使用了指针托管和引用计数的办法,当轮转文件时,将current_fd_ 赋值给old_fd_, 不直接delete或fclose, 简化代码等于:lock();dosomething();if(true) old_fd_ = current_fd_; currnt_fd_.incr();unlock();fwrite();currnt_fd_.decr(); 当old_fd_ = 0时,才会真正delete 和fclose 这个fd指针。优化后压测耗时30s。

引入无锁队列异步IO化

从第二次优化来看。锁热点已经很少了,性能也有不少提升,已经能满足OCS的需求,但是这种多线程同步堵塞写io的模式,一旦出现io hang住的情况,所有worker线程都会堵住。可以看下__IO_fwrite 这个函数,在写之前会进行__IO_acquire_lock() 锁住,写完后解锁。
为了避免所有线程卡住的情况,需要将多线程同步堵塞转换成单线程异步的io操作,同时避免引入新的锁消耗性能,所以引入无锁队列,算法复杂度为O(1),结构如图所示:

每个生产者线程都有独自的无锁队列,生产者线程做日志的序列化处理等,整个glog有一个单线程的消费线程,消费线程只处理真正的io请求,无锁队列使用环形数组实现,引入tcmalloc做内存管理。消费线程也会有hang住的可能,因为无锁队列使用CAS,当队列满了的时候并不会无限增长内存,而是会重试几次后放弃本次操作,避免内存暴涨。改造后耗时33s。

小细节优化

glog在linux系统下缺省使用的是pthread_rw_lock,在第二步减少锁粒度的基础上,现已不需要内核态的读写锁,所以将rwlock替换成用户态的spinlock。另外__GI_fwrite的热点还是有一些,采用合并队列的方法减少一些写操作,再加上超时机制,防止缓存的日志不及时落地。总结起来的优化就是:

  • 向前合并队列写
  • glog缺省使用的读写锁和mutex锁,换成spinlock
  • 单条message buffer大小调整
  • fwrite设置file buffer

这些优化完成后耗时时间为16s。

使用场景

优化后的glog版本适合使用在需要高日志吞吐量的产品, 比如OCS这种分布式高并发高吞吐量的系统。

高性能日志系统总结

从以上优化可以总结出高性能的日志系统的特性:

  • 使用异步IO实现高并发的日志吞吐量,日志线程与worker线程解耦,worker线程只做序列化之类的工作,日志线程只做io,避免当磁盘满了等异常情况发生时主路径阻塞导致服务完全不可用,这在任何一个高并发的系统中都需要注意的。
  • 其他细节点特性:
    • 不使用localtime取日期,单测localtime和getimeofday 获取时间, gettimeofday 速度比localtime快20倍
    • 选用无锁队列可重试放弃操作,避免内存暴涨。
    • 使用内存池管理,比如tcmalloc
    • 对fd等关键指针做引用计数处理,避免大粒度的锁。
时间: 2024-11-03 21:53:11

如何让glog性能提高10倍的相关文章

CoreOS是如何将Kubernetes的性能提高10倍的?

本文讲的是CoreOS是如何将Kubernetes的性能提高10倍的,[编者的话]本文是CoreOS近期对Kubernetes扩容性的一些针对性试验.检测和研究,分析并且得出了对Kubernetes集群部署和pod吞吐量等Kubernetes集群性能问题.扩容性问题上一系列的尝试和见解.该文章回顾了从硬件到软件层面采用缩小范围以及使用Kubernetes提供的端对端API性能指标和使用benchmarking作为基准工具等手段进行对建立不同规模集群过程中的pod吞吐量测试,从而发现Kuberne

将 Web 应用性能提高十倍的10条建议

将 Web 应用性能提高十倍的10条建议 提高 web 应用的性能从来没有比现在更重要过.网络经济的比重一直在增长:全球经济超过 5% 的价值是在因特网上产生的(数据参见下面的资料).这个时刻在线的超连接世界意味着用户对其的期望值也处于历史上的最高点.如果你的网站不能及时的响应,或者你的 app 不能无延时的工作,用户会很快的投奔到你的竞争对手那里. 举一个例子,一份亚马逊十年前做过的研究可以证明,甚至在那个时候,网页加载时间每减少100毫秒,收入就会增加1%.另一个最近的研究特别强调一个事实,

树莓派发布全新计算模块CM3,性能提升10倍

树莓派 Compute Module 3 树莓派(Raspberry Pi)正式推出全新一代计算模块(Compute Module 3,以下简称CM3),与树莓派3采用的是同款处理器. 树莓派推出的计算模块主要目的是工业用途,第一代计算模块(Compute Module 1,以下简称CM1)于2014年推出,采用的是和第一代树莓派相同的CPU.CM3的全新升级包括:1GB RAM,1.2GHz的博通BCM2837处理器.相比前代,CM3的CPU性能提高了10倍. 虽然这是第二代计算模块,但是它却

神奇五针孔眼镜现世 可提高10倍视力无副作用

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;      [ 科技讯]5月16日消息,据媒体报道,研究发现人们眼镜近视的程度越来越高,近视的年龄段也越来越趋于年轻化,甚至儿童化.一些普通眼镜不能够满足需求,日本公司开发出 一款新型针孔眼镜,佩戴之后可让 视力提高最多十倍. 日本眼科医生表示,视力0.1的人戴上针孔眼镜,视力能提高十倍,针孔眼镜每个只有五个孔,但是它能阻挡周围不需要的反射光,精密科学的针孔能准确的显

美研发新技术可将无线网络速度提高10倍

这张图表显示的是丢包率的高企对网络表现的影响 http://www.aliyun.com/zixun/aggregation/17197.html">北京时间10月26日消息,据国外媒体报道,一个来自麻省理工学院,哈佛以及其它欧洲大学的研究人员组成的科研小组日前设计出一种方法,可以将不增大发射功率,不增加基站,也不需要额外带宽的情况下将无线网络的速度提升10倍.预计这项技术的问世将会对LTE和WiFi领域的发展产生重要影响. 从本质上来说,这项被称作"编码TCP"的技术

新型向日葵形太阳能集中器可使采集率提高10倍

科学家研制的向日葵形太阳能集中器,采用一个巨大的抛物柱面反射器,由多个小镜构成.它们与一个追踪系统相连.追踪系统根据太阳的位置确定最理想的角度 IBM研究院的布鲁诺-米切尔与新型太阳能集中器的一个反射镜原型 新型太阳能集中器采用的芯片,呈角度的镜片和冷却管清晰可见 &http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;    4月25日消息,据国外媒体报道,科学家从向日葵身上 获取灵感,研制出向日葵形太阳能集中器.他们表

SandForce推出SF-2000控制器I/O性能提高两倍

&http://www.aliyun.com/zixun/aggregation/37954.html">nbsp;   继OCZ和OWC之后,Viking Modular Solutions也宣布了基于SF-2000系列全新主控制器的固态硬盘产品,将采用SF-2500和SF-2600两款控制器,产品将于2011年上市. 闪存的出现给存储阵列性能的提高提供了机会.SandForce推出了一款全新的控制器,可以帮助存储阵列进一步提高性能. SandForce去年推出了SF-15000

一次查询性能提高40倍的经历

背景说明 数据库:MongoDB 数据集: A:字段数不定,这里主要用到的两个UID和Date B:三个字段,UID.Date.Actions.其中Actions字段是包含260元素JSON数组,每个JSON对象有6个字段.共有数据800万条左右. 业务场景:求平均数 通过组合条件从A数据表查询出(UID,Date)列表,最多可能包含数万条记录: 然后用第1步的结果从B中查询出对应的数据 用第2步结果去Actions的某个固定位置的元素的进行计算 进化过程 在这里使用python演示 最直接想到

如何把Go调用C的性能提升10倍?

目前,当Go需要和C/C++代码集成的时候,大家最先想到的肯定是CGO.毕竟是官方的解决方案,而且简单. 但是CGO是非常慢的.因为CGO其实一个桥接器,通过自动生成代码,CGO在保留了C/C++运行时的情况下,搭建了一个桥来沟通C/C++世界和Go的世界.这就意味着,兼容性很好,但是对C的函数的调用,必须先把当前的goroutine挂起,并切换执行栈到当前的线程M的主栈(大小2MB).如果不做这个操作,那么只能在goroutine的栈上执行C函数调用,可是,goroutine的栈一般都很小,很