一次漫长的服务CPU优化过程
从师父那里接了个服务,每天单机的流量并不大,峰值tips也并不高,但是CPU却高的异常。由于,服务十分重要,这个服务最高时占用了100个docker节点在跑,被逼无奈开始了异常曲折的查因和优化过程。
一般情况下,服务的主要性能瓶颈都在cpu和内存,关于内存的瓶颈之前遇到过一次,这次是第一次遇到Cpu的瓶颈。首先介绍下背景,浏览器的插件服务主要服务与QQ浏览器和所有tbs终端,每天的日活超过5亿,而服务的每天流量超过30亿。
这个服务非常重要,从师父那里接过来后一直没有任何改变,直到又一次告警才意外发现这个服务已经自动扩容了100个docker节点了。。。而且每台的负载都还很高(峰值超过70%),然后迫于运维的压力和服务的稳定性考虑,就开始了曲折的查因过程。值得注意的是,这个服务虽然日活很高(因为包含TBS),但是整体的流量不算太多,尤其平分到每个节点上流量并不大。那么问题来了,cpu到底跑哪里了。
一、perf跑火焰图
分析CPU瓶颈,最直接的方法就是用perf看看服务的Cpu到底跑哪里去了,跑的结果也很诡异:

结果显示,CPU并没有耗费在服务的具体某个函数上(火焰图也没看出来),从上面来看服务的主要消耗在int和string的构造和析构上,也就是内存的频繁申请和释放?我把这个结果在组里同步下,组里的各位大神提出了一些建议。其中,bj大神认为,既然都在内存的申请和释放上,建议我把tcmalloc编译进去用于代替libc中内存回收,说对于小内存的频繁释放用tcmalloc会好很多。ok,于是我就照做了,然而吧tcmalloc静态编进去之后,依然没用,所以,应该不是回收机制原因,所以,fail。
二、性能分析
用perf跑出来的东西并没有帮我找到瓶颈,那么只能尝试着换换方法。
于是乎:(1)尝试着查下这个进程在用户态和系统态的cpu时间比,然后想通过strace和time等分析下是不是系统调用等方面的问题,然而我分析了半天和其他服务比较了下,依然没有收获。
(2)这个时候,偶然想到可以看看服务的线程cpu占比是否均衡或者都耗在哪些线程上了。

这个时候就发现诡异的事情了,这个服务的核心线程有30个,其中20个imp主线程,10个异步回调线程,还有些其他的日志线程等。然后,其中有10个线程cpu占比是其他的7到8倍,然后用gstack打了堆栈之后,发现这10个线程居然是回调线程!!!这就奇怪了,为啥回调线程会占这么高的CPU,这个时候结合服务本身的特性,对回调后的插件过滤部分做了和主线程一样的缓存,发到线上,cpu有一定程度的降低,然而,还是没有发现根本原因。因为在单机流量并不大的情况下,服务的CPU到底跑哪里了?按照同等流量下,这个服务的CPU应该是在40%以下,然后实际是80%。而这10个异步线程为啥会这么耗CPU,我review了n遍代码,还是没能解决。。。
三、服务自身优化
这个时候,春节将至,而我查了半个月,发了4个线上版本都没有根本性改变。运维要缩容,服务由很重要,真的头疼。这个时候,就请组里的大佬(xianyi)向他们请教类似的经历和优化方法。这个时候,我们认为,虽然服务的流量不大,但是插件服务没有做任何的缓存和控制,每次请求都会做完整的计算。于是,希望通过和终端联合改版,通过其他方式把服务的计算次数降下来。然而,终端改版要时间,服务的cpu快满了,看来春节是不好过了。。。
四、找到问题or真相
万般无奈下,xianyi告诉我了他们之前关于染色debug日志优化的事情,让我试试改改说不定可以降低很多,于是乎就是下面这段代码:



一次漫长的服务CPU优化过程的更多相关文章
- Linux(2)---记录一次线上服务 CPU 100%的排查过程
Linux(2)---记录一次线上服务 CPU 100%的排查过程 当时产生CPU飙升接近100%的原因是因为项目中的websocket时时断开又重连导致CPU飙升接近100% .如何排查的呢 是通过 ...
- 记一次线上服务CPU 100%的处理过程
告警 正在开会,突然钉钉告警声响个不停,同时市场人员反馈客户在投诉系统登不进了,报504错误.查看钉钉上的告警信息,几台业务服务器节点全部报CPU超过告警阈值,达100%. 赶紧从会上下来,SSH登录 ...
- SQL优化笔记—CPU优化
补充:常规服务器动态管理对象包括,下面有些资料可能会应用到 dm_db_*:数据库和数据库对象dm_exec_*:执行用户代码和关联的连接dm_os_*:内存.锁定和时间安排dm_tran_*:事务和 ...
- PHP服务缓存优化之ZendOpcache、xcache、eAccelerator
PHP服务缓存优化原理 Nginx 根据扩展名或者过滤规则将PHP程序请求传递给解析PHP的FCGI,也就是php-fpm进程 缓存操作码(opcode) Opcode,PHP编译后的中间文件,缓存给 ...
- Spark Tungsten揭秘 Day4 内存和CPU优化使用
Spark Tungsten揭秘 Day4 内存和CPU优化使用 今天聚焦于内存和CPU的优化使用,这是Spark2.0提供的关于执行时的非常大的优化部分. 对过去的代码研究,我们会发现,抽象的提高, ...
- Mysql服务配置优化
mysql服务器优化包含 硬件优化.操作系统配置优化(cpu调度.网络.内存.虚拟内存.磁盘io).Mysql服务配置优化(最大连接数.表缓存等.存储引擎).表结构优化.索引优化 总共5个方面. 本片 ...
- Spark Mllib里的协调过滤的概念和实现步骤、LS、ALS的原理、ALS算法优化过程的推导、隐式反馈和ALS-WR算法
不多说,直接上干货! 常见的推荐算法 1.基于关系规则的推荐 2.基于内容的推荐 3.人口统计式的推荐 4.协调过滤式的推荐 (广泛采用) 协调过滤的概念 在现今的推荐技术和算法中,最被大家广泛认可和 ...
- 一个扩展搜索API的优化过程
概述 API 是一个服务的门面,就像衣装是人的形象一样. 优雅的 API 设计,能让业务方使用起来倍儿爽,提升开发效率,降低维护成本:糟糕的 API 设计,则让业务方遭心,陷入混沌. 本文将展示一个扩 ...
- Netty源码解析 -- 服务端启动过程
本文通过阅读Netty源码,解析Netty服务端启动过程. 源码分析基于Netty 4.1 Netty是一个高性能的网络通信框架,支持NIO,OIO等多种IO模式.通常,我们都是使用NIO模式,该系列 ...
随机推荐
- HDU 2110 Crisis of HDU
Crisis of HDU Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) To ...
- Unix系统编程()发送信号的其他方式:raise和killpg
有时,进程需要向自身发送信号,raise 函数就执行了这一任务. #include <signal.h> int raise(int sig); 在单线程程序中,调用raise相当于对ki ...
- 关于JDK环境变量的配置问题
网上配置JDK环境变量的时候一直说要配置三个环境变量,什么JAVA_HOME,Path,CLASSPATH 其实是说以后如果要修改JDK的版本或者路径,只要更改JAVA_HOME就可以了,Path,C ...
- php -- php数组相关函数
array range ( mixed $low , mixed $high [, number $step ] ) 创建一个连续的数组 range('a','z'); foreach (range( ...
- 利用新浪云平台(SAE) 搭建 HUSTOJ 简易教程
前言: OnlineJudge(OJ)是一种代码在线判定平台,这里有许多的编程题目供你选择,你可以选择题目提交代码,OJ会自动返回你的代码的判定结果.是一种很方便的编程.算法练习平台.详情可见:百度百 ...
- 说说JSON和JSONP 也许你会豁然开朗
说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决 前言 由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只 ...
- 修改CFileDialog的标题
CFileDialog f(TRUE); f.m_ofn.lpstrTitle = "我的标题"; f.DoModal(); 设置标题! CFileDialog ...
- mybatis总结(三)之多表查询
上一节,已经把实体类和配置文件都写过了,这节课直接添加几个方法吧 在DeptMapper.xml文件中添加 <!-- 多表查询(1对多) ,通过部门编号,查询出部门所在的员工姓名,部门名,部门编 ...
- Sublime Text 更新后,Package Control 不见了的解决办法
把红框内配置删掉就可以了! via:http://www.qdfuns.com/notes/14464/f6813e4e18ac31bd856fe17fc8772ebc.html PS: ...
- Python学习笔记5-元组Tuple
tuple和list非常类似,但是tuple一旦初始化就不能修改,它也没有append(),insert()这样的方法.其他获取元素的方法和list是一样的 元组是用圆括号括起来的,其中的元素之间用逗 ...