关于性能优化之空间时间可靠性的辩证关系思考

前言

最近对多线程、锁、事务隔离、JVM、数据结构、分布式等方面的知识进行了梳理和思索,对性能优化的常用“伎俩”进行了一些反思和总结提炼,不过受山东大葱哥本人经验和能力所限难免有错误过欠妥之处,如有发现还请不吝指出为盼,看在所有内容全部手机码字的面子上请多多支持。

性能归结起来是空间和时间的此消彼长,当然再引申下就是空间、时间、可靠性的折中和侧重。受限于空间(存储、资源)和可靠性等的限制,性能在一定阶段不可能无限制的提升,在提升性能的同时我们也需要保证可靠性(去线程安全问题等),不过随着科技的进步过一段时间可能有会产生新的的性能提升空间(如内存、CPU二级缓存、GPU等)。
接下来我将对访问量线性增长的基于web典型应用的性能优化手段进行简述,剖析其中的时间 空间 可靠性关系。

升级到更加强大的资源

主要指性能方面的强大,如内存扩容或升级、CPU升级、GPU运算、固态硬盘、USB2.0到USB3.1等,这些都是随着科技的进度,用更先进的资源来为性能提升提供更好的空间支撑,当然这些先进资源的可靠性是有科技进步来保证的。这是单主机机时代性能优化的第一考量。

如数据库索引,用空间换时间

硬件资源升级后,接下来要优化的自然是io方面,而web应用的io以数据库为主。
数据库最常用的优化手段就是加索引,mysql的索引一般使用B+树,通过动态维护树的平衡和深度来维护索引。而索引就相当于字典的目录,它在增加了存储空间的同时,提高了查询的性能,当然前提是你要能有效使用索引,比如增删改比较多的应用增加索引后会降低性能,比如有些查询语录会是索引失效。

程序层面基本性能优化

主要从sql语句的优化充分利用索引、sql语句的合并或减少、代码优化重构减少冗余逻辑几方面着手。
数据库访问本质是读取的硬盘,所以访问速度肯定低于内存,所以减少sql访问的一种途径就是多条语句所需的数据一次读取到内存中,基于内存中的数据进行计算处理,这也是以更强大空间资源换取时间的方式。

连接池管理

建立数据库链接(建立io链接也是一样)也是一个比较耗费性能的工作,web应用需要频繁的建立链接、访问数据、关闭连接,于是乎就走了连接池(数据库连接池、io连接池等等),连接池顾名思义就是存放连接的池子,当需要访问数据库时,不再是每次都新建连接,而是直接在池子里面取来复用,节省了创建连接的时间,但条件是需要牺牲空间来存放连接。

缓存

在很多情况下,应用会多次访问数据库中的相同数据,而每次都从数据库读取明显是影响性能的。目前主流的ORM框架都有一级缓存、二级缓存用来提供数据缓存功能,通过读取缓存数据进而提高访问性能,很明显这也是空间换取时间的策略。缓存方案需要考虑命中策略,毕竟缓存是有限的,缓存使用代价是比硬盘要贵很多的,不可能无限制的缓存数据,所以尽量缓存命中率高的数据,一般常用的最近最不常使用策略进行缓存的更替。其实这个操作系统层面的内存管理方案是相似的。

web层基本性能优化

web层常用的优化手段有合并js、css,开启内容压缩、减小图片大小(无损压缩)、开启页面缓存、js后加载、图片懒加载。
web层主要涉及浏览器和服务器的网络交互,而网络交互显然是耗费时间的,所以要尽量减少交互次数,降低每次请求或响应数据量。这里面的开启压缩,在服务端是时间换空间的策略,服务端需要牺牲时间(其实是极短的)进行压缩以减小响应数据大小,压缩后的内容可以获得更快的网络传输速度,所以总体上时间是得到了优化的。

应用数据分离

随着性能需求进一步提升,单主机应用已经出现瓶颈,这时我们就需要进行第一步拆分了,将数据库独立出来,用一台单独的服务器来跑数据库。这个总体看是空间换取时间的策略,但在局部看的话却不是,如拆分后原先的本地io操作变成了网络访问,而网络访问速度肯定是低于本机io访问的,从这个角度来看是以牺牲时间来换取原单一主机的空间资源。而效果上来看,通过两台主机对应性能的提升(应用处理和数据访问),山东大葱哥认为肯定超过因网络带来的时间损耗。

多线程:

因大部分web应用都是与基于多线程的,不需要开发人员再单独启动多线程,但多线程作为一种性能优化的方式还是有必要说说。多线程以更加充分的利用cpu资源换取总体时间的节省。这个过程中可能会带来多线程间脏读或者数据不一致的问题,解决办法是加锁来保证串行,实质又是以牺牲时间换取可靠性。
针对锁带来的时间开销又有了悲观锁(同步) 乐观锁的区分,悲观锁是典型的以时间空间换取可靠性的策略,乐观锁有一种方案是cas方式,这又是通过空间开换取时间的方案。(类似于数据库的锁)
java语言中还有一个volitile关键字(其他语言也有类似关键字),该关键字将数据描述为多线程可见,这也算乐观锁的一种方式,牺牲了一点线程安全性、牺牲了比同步要少的时间时间换取的折中方案。

Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

数据库再优化

如果性能需求进一步提升,而且经过分析,瓶颈在于数据库,那就需要对数据库进行读写分离、集群部署、数据分区分片等优化。本质上都属于空间换时间的策略。

应用服务器优化

如果性能瓶颈在于应用服务器,那就需要对应用服务器进行集群部署、应用拆分、静态内容拆分等优化,本质上也是属于以空间换时间的策略。
基于应用拆分又可以进一步进行前后端分离、服务拆分,本质还是空间换取时间。
服务拆分方面比较优秀的分布式服务治理框架dubbo可以带来很多实用方案,而其中的注册中心又相当于一种服务提供池(不过它存放的不是连接而只是服务提供者的地址信息),而这也是空间换取时间和可靠性的策略。

应用缓存进一步优化

在应用缓存方面还可以继续优化,如采用内存数据库中间件redis、memcache等,这些内存数据库也支持分布式集群,以减少单点故障。对于分布式的内存数据库方案是空间换时间策略,对于单机的内存数据库方案与传统缓存方案类似,山东大葱哥觉得只不过第三方产品做了优化而已。

JVM启动参数优化

JVM启动参数主要作用为设置虚拟机堆栈大小,配置新生代 老年代 永久代大小或比例,最终决定的是java垃圾回收机制 。
复制算法 空间换取时间
标记清理 时间换取空间

web端再优化cdn加速

以大量的近终端网络节点实现静态内容的缓存,以加速资源访问速度,其实是对静态资源分离的进一步扩展。这也是空间换时间策略。

消息队列

随着性能需求进一步提升,应用提升空间不大的情况下就要改变策略了,不是一味地第一时间满足用户请求,而是第一时间听取用户请求,等有结果后再通知用户。这就是消息队列的应用,比如秒杀项目,用户请求过来后不是立即进行数据处理而是放入消息队列,有应用根据处理速度有先到后得进行异步处理,有处理结果后再告知用户(类似好莱坞模式),这是典型的牺牲时间换取可靠性策略。

其他软技能

数组 单向链表 双向链表

ArrayList数组,LinkedList单向链表
ArrayList是实现了基于动态数组的数据结构,适合随机访问
LinkedList基于链表的数据结构,随机访问要移动指针遍历,适合新增和删除操作。
LinkedHashMap既能随机访问,也便于增删,但增加可存储空间。

线程安全的类HashMap结构

concurrentHashMap内部的实现逻辑为分段后再hash存放,多线程下对某个分段进行加锁,不影响其他分段的读写,所以性能会比HashTable好很多。这也是以增加存储空间换取时间的方式。
终于把山东大葱哥最近一周的思考和反思总结完毕了,后续有新的想法会继续补充完善,希望读者朋友们给我多多提出宝贵意见个批评建议。

学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入技术爱好者交流群373107565,我们一起学技术!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 葸文信 14020110016 嵌牛导读:最近对多线程、锁、事务隔离、JVM、数据结构、分布式等方面的知识进行了梳...
    myonlymy阅读 669评论 0 1
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,082评论 1 32
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,146评论 0 9
  • 在服务器端程序开发领域,性能问题一直是备受关注的重点。业界有大量的框架、组件、类库都是以性能为卖点而广为人知。然而...
    dreamer_lk阅读 1,000评论 0 17
  • 大家好!我是您的老朋友轻舞飞燕 我现在天津,老家山东济南人,网络似海,相识是缘!感谢我生命中遇见的每一位朋友!擅长...
    轻舞飞燕666阅读 800评论 1 2