Redian新闻
>
这10种神级性能优化手段,你用过几个?(下)

这10种神级性能优化手段,你用过几个?(下)

公众号新闻

推荐关注↓

转自:Joey Yang

链接:

https://code2life.top/2020/08/13/0056-performance3/

索引

  • 软件设计杂谈——性能优化的十种手段(上篇),我们总结了六种普适的性能优化方法,包括 索引、压缩、缓存、预取、削峰填谷、批量处理,简单讲解了每种技术手段的原理和实际应用;
  • 软件设计杂谈——性能优化的十种手段(中篇),我们简单了解了程序是如何消耗执行时间和内存空间的;
  • 软件设计杂谈——性能优化的十种手段(下篇),再讲另外几类涉及更多技术细节的性能优化方向。

本篇也是本系列最硬核的一篇,本人技术水平有限,可能存在疏漏或错误之处,望斧正。仍然选取了《火影忍者》的配图和命名方式帮助理解:

  • 八门遁甲 —— 榨干计算资源
  • 影分身术 —— 水平扩容
  • 奥义 —— 分片术
  • 秘术 —— 无锁术

(注:这些“中二”的前缀仅是用《火影》中的一些术语,形象地描述技术方案)

八门遁甲 —— 榨干计算资源


让硬件资源都在处理真正有用的逻辑计算,而不是做无关的事情或空转

从晶体管到集成电路、驱动程序、操作系统、直到高级编程语言的层层抽象,每一层抽象带来的更强的通用性更高的开发效率,多是以损失运行效率为代价的。但我们可以在用高级编程语言写代码的时候,在保障可读性、可维护性基础上运行效率更高、更适合运行时环境的方式去写,减少额外的性能损耗《Effective XXX》、《More Effective XXX》、《高性能XXX》这类书籍所传递的知识和思想。

落到技术细节,下面用四个小节来说明如何减少“无用功”、避免空转、榨干硬件。

聚焦

减少系统调用与上下文切换,让CPU聚焦。

https://stackoverflow.com/questions/21887797/what-is-the-overhead-of-a-context-switch 

https://stackoverflow.com/questions/23599074/system-calls-overhead

less copy, less context switch, less system call 

fsync 10-50ms, ssd 100-10000μs (SATA NVME) 

ctx switch : system call -> mode switch, thread switch: cache change, work set change, full ctx switch (1-30 μs)

大部分互联网应用服务,耗时的部分不是计算,而是I/O。

减少I/O wait, 各司其职,专心干I/O,专心干计算,epoll批量捞任务,(refer: event driven)

//jolestar.com/parallel-programming-model-thread-goroutine-actor/

  • 利用DMA减少CPU负担 - 零拷贝 NewI/O Redis SingleThread (even 6.0), Node.js

避免不必要的调度 - Context Switch

CPU亲和性,让CPU更加聚焦

蜕变

用更高效的数据结构、算法、第三方组件,让程序本身蜕变。

从逻辑短路、Map代替List遍历、减少锁范围、这样的编码技巧,到应用FisherYates、Dijkstra这些经典算法,注意每一行代码细节,量变会发生质变。更何况某个算法就足以让系统性能产生一两个数量级的提升。

适应

因地制宜,适应特定的运行环境

在浏览器中主要是优化方向是I/O、UI渲染引擎、JS执行引擎三个方面。I/O越少越好,能用WebSocket的地方就不用Ajax,能用Ajax的地方就不要刷整个页面;UI渲染方面,减少重排和重绘,比如Vue、React等MVVM框架的虚拟DOM用额外的计算换取最精简的DOM操作;JS执行引擎方面,少用动态性极高的写法,比如eval、随意修改对象或对象原型的属性。前端的优化有个神器:Light House,在新版本Chrome已经嵌到开发者工具中了,可以一键生成性能优化报告,按照优化建议改就完了。

与浏览器环境颇为相似的Node.js环境, https://segmentfault.com/a/1190000007621011#articleHeader11

Java

C1 C2 JIT编译器 

栈上分配

Linux

  • 各种参数优化
  • 内存分配和GC策略
  • Linux内核参数 Brendan Gregg 内存区块配置(DB,JVM,V8,etc.)

利用语言特性和运行时环境 - 比如写出利于JIT的代码

  • 多静态少动态 - 舍弃动态特性的灵活性 - hardcode/if-else,强类型,弱类型语言避免类型转换 AOT/JIT vs 解释器, 汇编,机器码 GraalVM

减少内存的分配和回收,少对列表做增加或删除

对于RAM有限的嵌入式环境,有时候时间不是问题,反而要拿时间换空间,以节约RAM的使用。

运筹

把眼界放宽,跳出程序和运行环境本身,从整体上进行系统性分析最高性价比的优化方案,分析潜在的优化切入点,以及能够调配的资源和技术,运筹帷幄。

其中最简单易行的几个办法,就是花钱,买更好或更多的硬件基础设施,这往往是开发人员容易忽视的,这里提供一些妙招:

  • 服务器方面,云服务厂商提供各种类型的实例,每种类型有不同的属性侧重,带宽、CP、磁盘的I/O能力,选适合的而不是更贵的
  • 舍弃虚拟机 - Bare Mental,比如神龙服务器
  • 用ARM架构CPU的服务器,同等价格可以买到更多的服务器,对于多数可以跨平台运行的服务端系统来说与x86区别并不大,ARM服务器的数据中心也是技术发展趋势使然
  • 如果必须用x86系列的服务器,AMD也Intel的性价比更高。

第一点非常重要,软件性能遵循木桶原理,一定要找到瓶颈在哪个硬件资源,把钱花在刀刃上。如果是服务端带宽瓶颈导致的性能问题,升级再多核CPU也是没有用的。我有一次性能优化案例:把一个跑复杂业务的Node.js服务器从AWS的m4类型换成c4类型,内存只有原来的一半,但CPU使用率反而下降了20%,同时价格还比之前更便宜,一石二鸟。

这是因为Node.js主线程的计算任务只有一个CPU核心在干,通过CPU Profile的火焰图,可以定位到该业务的瓶颈在主线程的计算任务上,因此提高单核频率的作用是立竿见影的。而该业务对内存的消耗并不多,套用一些定制v8引擎内存参数的方案,起不了任何作用。

毕竟这样的例子不多,大部分时候还是要多花钱买更高配的服务器的,除了这条花钱能直接解决问题的办法,剩下的办法难度就大了:

  • 利用更底层的特性实现功能,比如FFI WebAssembly调用其他语言,Java Agent Instrument,字节码生成(BeanCopier, Json Lib),甚至汇编等等
  • 使用硬件提供的更高效的指令
  • 各种提升TLB命中率的机制,减少内存的大页表
  • 魔改Runtime,Facebook的PHP,阿里腾讯定制的JDK
  • 网络设备参数,MTU
  • 专用硬件:GPU加速(cuda)、AES硬件卡和高级指令加速加解密过程,比如TLS
  • 可编程硬件:地狱级难度,FPGA硬件设备加速特定业务
  • NUMA
  • 更宏观的调度,VM层面的共享vCPU,K8S集群调度,总体上的优化

小结

有些手段,是凭空换出来更多的空间和时间了吗?天下没有免费的午餐,即使那些看起来空手套白狼的优化技术,也需要额外的人力成本来做,副作用可能就是专家级的发际线吧。还好很多复杂的性能优化技术我也不会,所以我本人发际线还可以。

这一小节总结了一些方向,有些技术细节非常深,这里也无力展开。不过,即使榨干了单机性能,也可能不足以支撑业务,这时候就需要分布式集群出场了,因此后面介绍的3个技术方向,都与并行化有关。

影分身术 —— 水平扩容

本节的水平扩容以及下面一节的分片,可以算整体的性能提升而不是单点的性能优化,会因为引入额外组件反而降低了处理单个请求的性能。但当业务规模大到一定程度时,再好的单机硬件也无法承受流量的洪峰,就得水平扩容了,毕竟”众人拾柴火焰高”。

在这背后的理论基础是,硅基半导体已经接近物理极限,随着摩尔定律的减弱,阿姆达尔定律的作用显现出来,https://en.wikipedia.org/wiki/Amdahl%27s_law

水平扩容必然引入负载均衡


多副本 

水平扩容的前提是无状态 

读>>写, 多个读实例副本 (CDN) 

自动扩缩容,根据常用的或自定义的metrics,判定扩缩容的条件,或根据CRON 

负载均衡策略的选择

原理:并行化

奥义 —— 分片术

水平扩容针对无状态组件,分片针对有状态组件。二者原理都是提升并行度,但分片的难度更大。负载均衡也不再是简单的加权轮询了,而是进化成了各个分片的协调器


分片 - 百科全书分册 

Java1.7的及之前的 ConcurrentHashMap分段锁 https://www.codercto.com/a/57430.html 

有状态数据的分片 

如何选择Partition/Sharding Key 

负载均衡难题 

热点数据,增强缓存等级,解决分散的缓存带来的一致性难题 

数据冷热分离,SSD - HDD

分开容易合并难

区块链的优化,分区域

秘术 —— 无锁术


Don’t communicate by sharing memory, share memory by communicating

有些业务场景,比如库存业务,按照正常的逻辑去实现,水平扩容带来的提升非常有限,因为需要锁住库存,扣减,再解锁库存。票务系统也类似,为了避免超卖,需要有一把锁禁锢了横向扩展的能力。

不管是单机还是分布式微服务,锁都是制约并行度的一大因素。比如上篇提到的秒杀场景,库存就那么多,系统超卖了可能导致非常大的经济损失,但用分布式锁会导致即使服务扩容了成千上万个实例,最终无数请求仍然阻塞在分布式锁这个串行组件上了,再多水平扩展的实例也无用武之地。

避免竞争Race Condition 是最完美的解决办法。上篇说的应对秒杀场景,预取库存就是减轻竞态条件的例子,虽然取到服务器内存之后仍然有多线程的锁,但锁的粒度更细了,并发度也就提高了。

线程同步锁 

分布式锁 

数据库锁 update select子句 

事务锁 

顺序与乱序 

乐观锁/无锁 CAS Java 1.8之后的ConcurrentHashMap 

pipeline技术 - CPU流水线 Redis Pipeline 大数据分析 并行计算 

原理:并行化

TCP的缓冲区排头阻塞 QUIC HTTP3.0

总结

以ROI的视角看软件开发,初期人力成本的投入,后期的维护成本,计算资源的费用等等,选一个合适的方案而不是一个性能最高的方案。

本篇结合个人经验总结了常见的性能优化手段,这些手段只是冰山一角。在初期就设计实现出一个完美的高性能系统是不可能的,随着软件的迭代和体量的增大,利用压测,各种工具(profiling,vmstat,iostat,netstat),以及监控手段,逐步找到系统的瓶颈,因地制宜地选择优化手段才是正道。

有利必有弊,得到一些必然会失去一些,有一些手段要慎用。Linux性能优化大师Brendan Gregg一再强调的就是:切忌过早优化、过度优化。

持续观测,做80%高投入产出比的优化。

除了这些设计和实现时可能用到的手段,在技术选型时选择高性能的框架和组件也非常重要。

另外,部署基础设施的硬件性能也同样,合适的服务器和网络等基础设施往往会事半功倍,比如云服务厂商提供的各种字母开头的instance,网络设备带宽的速度和稳定性,磁盘的I/O能力等等。

多数时候我们应当使用更高性能的方案,但有时候甚至要故意去违背它们。最后,以《Effective Java》第一章的一句话结束本系列吧。

首先要学会基本的规则,然后才能知道什么时候可以打破规则。

参考

  • 《高性能JavaScript》 —— Nicholas C. Zakas

  • 《Effective Java》 第三版 —— Joshua Bloch

  • //www.brendangregg.com/ —— Brendan Gregg

  • https://colin-scott.github.io/personal_website/research/interactive_latency.html

  • https://stackoverflow.com/questions/23599074/system-calls-overhead

  • https://stackoverflow.com/questions/21887797/what-is-the-overhead-of-a-context-switch

  • //jolestar.com/parallel-programming-model-thread-goroutine-actor/

  • https://www.codercto.com/a/57430.html

  • https://segmentfault.com/a/1190000007621011#articleHeader11

  • https://en.wikipedia.org/wiki/Andy_and_Bill's_law)

- EOF -


加主页君微信,不仅Linux技能+1

主页君日常还会在个人微信分享Linux相关工具资源精选技术文章,不定期分享一些有意思的活动岗位内推以及如何用技术做业余项目

加个微信,打开一扇窗


推荐阅读  点击标题可跳转

1、Linux 性能优化

2、这几种神级性能优化手段,你用过几个?

3、一文读懂 Linux 内存分配策略


看完本文有收获?请分享给更多人

推荐关注「Linux 爱好者」,提升Linux技能

点赞和在看就是最大的支持❤️

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
钱学森的“回国观感”在美国271.害人害己新加坡街头“五大神兽”,你见过几个?【亲子出游】18岁之前必有的体验,你带娃去过几个?低欲望人群的几个特征,你中了几个?这10种神级性能优化手段,你用过几个?(中)20个年度锐词,你听过几个?万圣节著名闹鬼圣地,你去过几个?Linux 性能优化实战-网络丢包问题分析MySQL性能优化浅析及线上案例系统性能优化的十大策略(强烈推荐,建议收藏)你用过这款国外的保健品吗?如何为孩子进行语言教育?(下)“灵光”“精光”“捎地光”......这些“金光锃亮”的上海话,你用过吗?投资移民关停,还有什么方式获得爱尔兰长居身份?(下)漫画类作文怎么写?(下)Nginx 一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化...走资派邓小平窃国大盗乱世奸雄这 10 种神级性能优化手段,你用过几个?雕刻南瓜灯,红薯干这几种神级性能优化手段,你用过几个?最近很流行的骗小孩手段,不少成年人都中招了,你也不例外哈哈哈哈哈系统性能优化十种手段(并行)我国有多少民航机场?252座你去过几个?无愧枫叶国!全球10大最佳赏枫地点出炉:前三位全在加拿大!你去过几个?习大帝也不是一无是处,治好了朋友的抑郁性能优化的十种手段(取与舍)Nginx一网打尽:动静分离、压缩、缓存、黑白名单、跨域、高可用、性能优化...你知道新年心想事成的秘诀吗?(下)Ceph OSD CPU 性能优化 -第 1 部分【探索】申城的湿地风光,你打卡过几个?ChatGPT已经这么聪明了,怎样才能让孩子在未来更好的生存?(下)数字资产管理服务商「Share Creators」完成500万美元融资,以工具化手段帮助企业从数字资产管理中解放|36氪首发性能优化的十种手段(时间和空间)15部最受欢迎动画片,快看看你家孩子看过几个?
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。