性能的秘诀 chrome插件支持推送
目录 性能的分类 问题的定位 优化的思路 chrome案例
性能的分类
问题:分别是什么原因? 笔记本开机花费5分钟 看直播的时候浏览器卡顿
性能问题分2类 CPU IO
感受硬件性能的进步 https://people.eecs.berkeley.edu/~rcs/research/interactive_latency.html
练习:属于哪类? 618期间,关注业务分发feed时出现队列堆积问题,feed无法 及时写入数据库 双11期间,用户Redis Cluter出现连接超时,导致无法完成 请求 618期间,先发后审出现任务堆积,导致无法及时发出爆料
问题的定位
问题:电脑慢怎么办? 升级CPU 加内存条 换SSD 换主板
我的经历 曾经想在斗鱼直播游戏,发现电脑带不动 我I5+660不服,一顿直播软件调参,还是卡 突然看斗鱼官网要求E3+760,都很贵,犹豫都要买么? 无论如何,升级主板才能用新硬件... 先买了E3,发现还是卡... 再买1060...终于不卡了,原来是显卡的问题,E3几乎白买
不要盲目猜测 用工具:ab、top、vmstat、iostat、perftop、sar、callgrind 等,做量化分析! 用经验:直觉、猜测、验证、总结、纠错,不要轻信以往经 验,不要忽略场景的差异!
CPU常见问题 CPU慢 例:redis单线程纯内存操作,CPU主频越高则处理越快,核心多没有收 益 用户代码慢 例:用in_array遍历查找,而没有使用array_key_exists哈希查找 系统代码慢: 例:php短连接到redis,导致内核大量时间处理tcp握手,sys cpu打高
IO常见问题 延迟高: redis循环get 10次,耗费10倍时间 吞吐低: mysql插入一条10毫秒,1秒只能插100条 随机读写: 机械磁盘的磁头需要寻道
练习:分析下面的性能问题 关注feed流,插入mysql队列堆积 好价点赞,更新mysql队列堆积了
怀疑与定位的差距 == 量化 QPS/TPS USR/SYS CPU MEM IOPS PPS 怀疑与定位的差距 == 量化 QPS/TPS USR/SYS CPU MEM IOPS PPS Bandwidth(disk, network)
优化的思路
问题:CPU问题有哪些优化思路? 更快: 换主频更快的处理器 -- 技术革新 更多: 换核心更多的处理器 -- 能扩容解决的不是问题 更少 让代码做更少的计算 -- 减少重复的,保留必要的
练习:优化下面的代码 foreach ($articles as $article) { $channels = ["post", "news"]; if (!in_array($article['channel'], $channels)) { continue; } sleep(0.1);
问题:哪个更难优化? 代码还没怎么跑,CPU就已经没了 人活着,钱就没了 CPU还有剩余,代码却提升不动了 人挂了,钱没花了
锁是CPU低利用率第1杀手 锁 == 并行变串行 减小锁粒度,充分利用多核并行
练习:优化下面的CPU低利用率场景 好价点赞,更新mysql队列堆积了 增加消费进程?不是本质。 mysql行锁导致,可以利用redis累加,定期更新到mysql。
谁是CPU低利用率第2杀手? IO 同步网络调用 磁盘寻道
问题:磁盘IO问题有哪些优化思路? 更快: 用更快的SSD替换HDD -> 技术革新 更多: 更大: 用更大的批次读写磁盘 -> 减少随机IO
练习:分析原因 慢SQL第二次执行就不慢了,为什么? 为什么编程软件第一打开慢,第二次就变快了?
问题:网络IO问题有哪些优化思路? 更大: 请求批量发送,减少小包传输 -- 直接提升吞吐 更长: 能用长连接就别用短连接 -- 降低负载/延迟,间接提升吞吐 更宽: 异步IO编程,无需同步等待结果 -- 吞吐不受延迟影响
案例:用户系统对接ES 用户重构需将实时变化的用户金币、积分等数据存储到ES中 ,此前只存在Redis里。
我们的方案 金币、积分变化仍旧实时更新到Redis 向Redis去重集合中set uid job周期性运行,把set中的uid的金币、积分同步到ES 向ES更新时,采用bulk批量接口同时更新多个uid的记录
练习:给出优化方案 某业务接口需要进行5000次Redis get请求,耗时5秒无法接 受 用户redis cluster经常连接超时,如何优化?
优化的几个金句 战略层面 2:8原则 大拆小 战术层面 延迟 换 吞吐 空间 换 时间 CPU-bound与IO-bound 资源隔离
chrome推送案例
背景 当前 目前chrome插件采用定时拉取实现,时效性低 以后 产生新文章后,主动推送给chrome插件
要做的事情 基于websocket协议,维持50万长连接在线 产生1篇新文章,遍历50万长连接推送
定位:CPU - 重复计算 协议采用json,50万次推送需要编码50万次json,服务器要 炸了
优化:CPU - 重复计算 消息只json编码一次,直接写给50万连接 试错是积累这方面经验的主要途径,不试不知道,不自信
定位:CPU - 锁瓶颈 遍历50万连接推送消息,花费时间很长 每时每刻都有连接上下线,集合锁粒度很粗,并发能力很差 ,各种僵死感
优化:CPU - 锁瓶颈 连接随机打散到多个集合,每个集合大约1万个连接,有独立 的锁保护 多线程并行遍历多个集合推送,单个集合的锁占用时间很短 使用读写锁取代互斥锁,提升多条消息同时遍历推送的并发 能力
优化:IO - 小包传输 1秒发10篇文章,就需要推送10*50万=1000万次/秒
优化:IO - 小包传输 按秒级时间窗口,将要推送的文章合并成数组,整体json编 码后,再遍历推送出去 linux协议栈的PPS经验值大概就是100-150万左右,再多 就会丢包 减少小包即减轻协议栈处理压力,整个链路上的设备都会 降低CPU损耗
优化:IO - 异步通讯 因为推送遍历集合需要锁整个集合,同步等待每个 websocket write完成无法接受
优化:IO - 异步通讯 每个websocket有独立的读写goroutine,读写消息通过 channel缓冲 遍历websocket推送时,只需向channel投递消息,不需要等 待网络发送,因此遍历很快
内部设计 连接 连接 连接 连接 连接 集合 集合 集合 多线程分发 打包与编码 消息 消息 消息
整体架构 Websocket推送消息 HTTP/2广播消息 HTTP 提交消息 连接 gateway网关 gateway网关 logic逻辑层 HTTP 提交消息 业务方 业务方 业务方
优化成果 内存占用与长连接个数呈线性关系 消息推送期间,可以用尽整机的CPU 消息推送期间,带宽高达6Gbit/s
交流环节 你有哪些优化经验分享一下?