最近参与了几个项目的性能优化,总体来说各个项目都有所提升,能够满足用户使用需求,但是这个过程耗费了大量的人力、物力资源成本,主要原因有以下几点:
- 系统本身没有任何参数指标,这一点其实是大多数系统存在的问题,打个比方我作为乙方给甲方做了一个软件,交付完成后供甲方使用,这个系统的TPS是多少?硬件配置/用户矩阵是什么?系统可靠性4个9还是2个9?你可能会说,我们的客户要求根本没有这么严格,能用就行,实则不然,如果说一年没问题,一年后客户的用户数量增长了一倍,忽然发现系统卡顿,几乎不能使用,客户找你算账,这该怎么办?谁的原因造成的..... 你说我们给自己公司做的产品,不要求这些东西,满足当前用户即可,那我现在问你,你的系统用户承载量是什么?当你真的出现用户数量激增,你该如何应对?
- 框架标准化,如果一个企业中多个项目使用的框架五花八门,真正出现性能问题的时候,只能大家齐上阵,见招拆招,忙的不亦乐乎,其实收效甚微。
- 翻译需求,很多功能逻辑说不通,但又没法改,为什么?客户要求如此、产品经理设计如此,产品经理也已经不在了,原型设计文档找不到了,当然这种项目都是比较老的项目,很多公司都会存在此类问题。
- 灰度发布系统,深夜一群人呆在一起发布一个系统,一起处理bug真的是团队团结的表现吗?回家陪陪老婆孩子,好好休息,第二天的工作效率不是更高吗?
如果现在让我做一个系统,我应该如何设计?趁着周六有时间就这四个问题简单聊聊,希望能够对大家的工作有所启发。
系统参数
你打开的汽车使用说明书,它会告诉你它在什么温度下可以正常工作、最高时速是多少、承客量多大......如果出现问题,仪表盘会给出什么样提示,你应该如何规避这些故障。软件系统也一样,你的安装部署手册里要告诉别人你的系统需要多大内存、多少硬盘、什么规格的CPU来支撑多少用户量。设计文档的非功能性指标应该包含系统每秒处理事务数量(TPS)或查询数量是多少、安全性指标等级甚至支持用户数量;你的管理端界面或者监控系统应该告诉运维人员CPU占用量、内存占用量、硬盘使用情况、带宽使用;阈值告警参数,触发阈值产生告警,研发人员如何查看日志排除故障。
说的简单,这些指标从哪里得到呢?没有特别好的办法,只能通过压力测试、稳定性测试、安全性测试甚至平时的故障模拟中得到。
确实这些度量指标非常昂贵,甚至要超过你系统本身的成本,即便如此,你要去做,因为你不去量化一个系统,你就无法管理一个系统,可以想象一下你每天都是在闭着眼睛开车,你永远不知道您离灾难有多近。所以你要说服你的老板,抵挡住节省金钱的诱惑,认真对待系统指标数据。
当然完全做出这些东西到底有多复杂?我作为过来人认为并不复杂,而且能减轻不少后期工作量,想想一个系统不会所有的接口都对性能有要求,所以你只要评估出存在性能瓶颈的接口加以性能测试即可;另外性能测试脚本开发完成后都是复用的状态,所以不会产生太大工作量,而且又保证了每次上线之前都可以自动化验证部分接口,这不比人肉点点点
香的多吗?
另外像一些系统层面的参数指标,比如Http调用成功/失败情况、CPU、内存占用情况、告警等,可以搭建一套监控工具,比如Prometheus等。完成此类指标的获取。
如果说我的系统总共就几个人用、或者这种付出和收益完全成反比,那当我没说。
框架标准化
框架,通俗来说也就是我们产品/项目架构,就架构本身而言,一定先有设计目标,架构要去干什么样的事情,去完成一个购物网站还是一个管理平台,存在很大区别;根据设计目标,应该定义出设计原则,这也就是平时经常见到的控制反转、里氏替换、最小依赖、单一职责等原则,加上清晰的边界和实现价值(架构做什么,不做什么);最后通过使用Gof总结出来23种设计模式加上算法就形成了一套框架。在这个框架的基础上就可以开发我们的应用。你可能会反驳我们项目五花八门,经常变动,一般架构很难满足,甚至架构需要经常改动,大概率是框架抽象定义的不够好,你看看你平时用到的tomcat框架、spring框架,你感知到它的存在了吗?反而像早期IBM做的weblogic、jboss什么都做的重量级框架,已被抛弃,所以解耦和抽象再怎么强调都不为过。
定义好框架只是第一步,下面就是使用了,就目前国内情况而言,开源项目越来越火爆,所以基本上从网上找找,七拼八凑就行成了一套自己的框架,这本身而言也没有错误,极大降低企业框架定义的成本,但是一个框架通常只能解决某一类的问题,所以前期就需要架构人员进行反复编写代码进行测试和使用,得到这个框架自身的数据,而不是看见别人用的很好,别人多少数据量都可以轻易支撑起来,别人的使用场景很可能跟你不一样,要不然为啥市面充斥着五花八门的框架,大多数原因都不能从根本上解决自己的痛点问题。
接着架构人员要参与到编码中,发现问题及时更正和修改,引导开发人员如何划分模块,关键时刻做出示例,进而形成自己的开发规范,而不仅仅是站在一个指导者的角色,口头告诉程序员该如何使用,满足不了性能指标或者业务一团糟的时候开始考虑拆分,然后拆成几个微服务也是乱上加乱,根本不能从本质上解决问题。
总结来说,做架构首先要考虑的是自己的需求、目的及边界、原则、实现价值,最后才考虑技术实现和工具组件,而不是首先撸出一套框架生搬硬套,最后说程序员不会使用,代码写的太垃圾。
翻译需求
通常来说,一般是提出需求,架构人员进行架构设计,产品经理画出原型设计,开发人员开始设计、开发、提交测试交付。最后一个阶段看似已经定型,按照需求完成任务即可。但是人都会犯错,作为开发/测试人员不能对照原型、设计文档翻译需求,出现问题后,自豪的说,就是这样设计的,我也没办法,你找产品去
。但是你有没有考虑过,即使产品人员改了改需求,最后你不还是照做,受伤的还是自己。所以我们在做任何一个功能的时候都要搞清楚问题的本质,事情的初衷。
你可能会反驳说,我的产品比较强势,他做的东西面向的是用户,开发人员是无法理解的,照着做就行了
。但我觉着这些并不是理由,如果一个产品说用户要求的,你可以站在一个用户的角度去理解,如果是从数据角度,让他把数据拿出来,如果讲不明白,你完全可以拒绝,否则你做出来的东西肯定是四不像
。所谓铁打的营盘,流水的兵,换了几波人之后完全无法理解这种逻辑,产品如何迭代。你要说你的产品功能过于复杂,大多数是产品设计就存在一定问题,你看看你常用的应用,那个不是简单易用。
为什么要对开发人员强调需求呢?因为你的需求做的不严谨,存在漏洞,都会给后期的性能、再次开发埋下祸根,而且这种问题,越往后解决成本越高。
灰度发布
相信大家面试的时候经常会听到面试官问这个问题, 如何保证一个系统高可用?如何做到不停机发布系统?
答案也很简单,负载均衡,当然负载均衡也有很多种,有基于域名重定向、DNS、IP、数据链路层的负载均衡,你可以根据你服务自身情况,选择一种适合自己的。当然你会反驳我说,我的系统就一个副本,不要求高可用,那我会说,你敢白天上线吗?如果不敢,请乖乖做灰度发布(金丝雀、A/B、蓝绿等等)。
这并不是凭空增加大家的工作量,不知道大家认不认这样一个事实,软件发布通常遵循墨菲定律,往往不好的,一般情况下不会出现的问题,甚至没有想到的,都会在线上出现。要么人家都说运维人员都相信玄学,其实倒不是因为玄学,是因为存在未知。线上的用户、历史数据量往往最多的,也是最全面的,所以线上更容易复现一些问题。通过灰度发布部署多套,开发/测试人员完全可以在工作时间、站在用户的角度测试完成后上线发布。否则直接回退,即实现了测试,也没有影响用户使用。
灰度发布说简单也简单,最简单的你在你的nginx写几句lua脚本,便可以把包含特定标识的用户路由到特定服务。
总结
看完本文后,感觉会有点诧异,说的不是性能优化吗?不应该讲讲连接池配置多大、缓存如何使用、系统优化、硬件配置、甚至代码如何编写的一些技巧吗?怎么扯了一堆没用的。从某种程度上来说,软件的性能优化成本往往跟前期的软件设计成本反比,前期在设计上花费的时间越多,往往后期优化成本就越低。没有任何组织能够一开始就做一个高性能的软件系统,大多数都是随着用户和数据的增多演化而来。前期的性能指标、系统架构、甚至功能需求编写都能够为后期软件性能优化带来帮助。