引言
作为一个服务端程序员,在一个领域深耕几年之后,会发现学习的新东西越来越少,这时候怎么办呢?就需要一边深耕,一边增加对相关横向团队的了解和交流,会发现原来端到端链路还有非常广阔的空间等着你去成长。
基于过去几年负责过的亿级用户千万级日活的用户系统、亿级用户业务推送系统,加上跟客户端、前端、服务端、中间件团队的一些技术合作,这里总结一下常见的端到端性能&体验&稳定性的优化方案。
前端
1. 通用手段
- 资源处理
- 拆包:拆bundle。利用webpack4 dynamic import机制,根据页面入口业务不同,引入不同bundle
- 大图片资源:WebP压缩,不用GIF用Lottie
- 小图片资源:矢量图,例如iconfont
- 资源加载控制:业务js尽量异步,异步尽可能用原生 async,容器自带优化
- 业务逻辑
- 首屏请求拆分
- 请求合并:减少同步多次请求,FaaS层请求合并
- 渲染性能
- 情绪安抚
- loading动画
- 骨架屏
- 快照:HTML快照,接口请求后,保存上次访问的HTML在storage中,下次进入优先取storage中的HTML资源展示
2. H5
- 端内手段
- 离线包
- 数据预加载:数据提前推送到客户端,前端在加载JS资源的同时直接从客户端缓存中取数据
- 边缘渲染:CDN
- 性能监控
3. 小程序
- 客户端预置包、预加载、预解析
- 包大小精简
- 分包:主包仅保留首页,其他页面逻辑放到子包
- 代码精简:冗余代码、npm包依赖、代码合并
- 插件化:业务源码组件(考勤、待办等)改插件化,异步加载
- 首屏数据优化:非首屏(下滑、分Tab内容)懒加载或延迟加载
- 代码重构,去除废弃逻辑、不合理调用等
- 可交互快照技术
- 小程序首页保存为图片,即快照。二次打开小程序 -> 展示快照(最上层)-> 启动小程序 -> 启动完成 -> 隐藏快照 -> 保存新快照
- 针对不同区块计算每一个dom的位置及对应link,客户端记录不同坐标对应的link,结合不同位置的优先级算法实现图片可交互
服务端
服务端的性能优化会按照工作台历史上做过性能优化效果大小从高到低梳理
1. 架构优化:设计模式策略+责任链
主链路架构优化。对于大多数基于DDD建模出来的产品,必须掌握的一个设计模式就是策略模式(通常结合工厂模式一起使用)。对于主页或门户类的加载,常常用到的一个设计模式则是责任链模式。好的设计模式+恰到好处的使用=延缓架构腐化,防止性能快速下跌。
策略模式:根据入参组织信息+工作台Id+页面Id => 命中指定策略(标准工作台、自定义工作台、预览模式)
责任链:工作台的加载总体抽象为统一责任链 => 配置获取、权限校验、schema获取、动态布局、组件加载、页面样式适配、动态组件
2. 并发
工作台千万DAU流量,QPS高峰期约2W。4C8G机器不到200台。平均RT接近200ms。通过升级责任链从串行计算到并行计算,RT优化到近100ms。
核心优化思路:
3. 懒加载
页面、组件计算过程中依赖非常多的填充资源,例如组织信息、各种应用信息、用户信息、可见性信息等等,但由于不同类型工作台、不同schema的工作台上的组件内容不一样,所依赖的填充资源也不一样,这些不一样的地方往往要到某个组件的计算逻辑中才知道是否需要。因此可考虑Context+懒加载,需要时才加载。一处加载,处处可用。
4. 依赖限制
页面加载涉及依赖RPC接口超30个,如果每个IO超时限制都允许达到500ms,那基本要不了几个接口超时,整体就超时了。因此对于非核心依赖的超时可以分策略限制得低一些,例如50ms
5. 缓存
- 前端缓存:针对组织+个人分别保持version,无写操作时,version不变,则前端存在最新缓存的场景下,可直接使用前端缓存
- 服务端非多变核心依赖、高耗时依赖,使用内存缓存,可考虑本地缓存。注意缓存一致性问题、批量缓存获取问题、缓存击穿问题等
- 持久化缓存:最近使用等
6. 降级
- 高峰期,针对非首次访问流量进行降级,直接返回使用前端端缓存,保障首次访问流量正常高效加载
- 平滑降级恢复,从降级恢复到非降级状态时,考虑平滑恢复,例如百分比逐步恢复,防止脉冲流量
- 弱依赖直接降级
7. 预加载
- 超99.9的场景需要使用的数据,例如配置类数据,直接预加载,后续直接使用。不要每用一处都请求一次
- 部分可以合并批量预加载的场景,不要每一处独立查询
- 预加载注意可能存在数据过期的极端场景,预加载最好少用于写操作场景
8. 异步化
可解耦的,异步化处理,削峰填谷,延迟处理。注意幂等保障,防止无限消费。注意数据一致性。
9. 推拉结合+边缘计算
有些可提前推送到客户端的非多变数据,可提前推送,减少拉取时的计算量,适合实时性要求高,或读多写少的场景。前端/客户端针对拉取到的数据跟提前推送的数据合并后进行展示。
在耗电量、流量消耗可控等前提下,使用客户端作为边缘计算的设备,而不是全部靠服务端中心式的计算,往往有奇效。
注意推送数据的过期和失效问题,数据一致性、多端一致性问题。
10. 代码规范
遵守阿里巴巴Java代码规范,可以避免很多常见问题
- 防止循环IO,特别是底层的rpc
- SQL命中索引,减少回表查询
- 大数据量分页使用游标,而不是limit
- ……