持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第27天,点击查看活动详情
性能设计
5.1 性能指标
- 响应时间
- 吞吐量。单位时间内的响应次数
在资源一定的情况下,性能优化的本质就是榨取资源,利用一切可利用的资源。CPU消耗少的时候,可以考虑增加线程榨取CPU的能力。
5.2 定位瓶颈点
- 压力测试
- 日志分析
- 监控工具
- dstat是一个全能系统信息统计工具
- sar是目前linux是最为全面的性能分析工具之一,可以查看文件读写情况、系统调用、磁盘IO、CPU、内存、进程活动等。
- netstat 可以用来查看网络系统的状态信息
- tcpdump可以用来查看网络连接的封包内容。
5.3 服务通信优化
5.3.1 同步转异步
可以利用ajax技术实现异步
5.3.2 阻塞转非阻塞
阻塞调用是指调用结果返回之前,当前线程被挂起,调用线程只有得到结果才会被返回。当异步调用的时候,如需返回结果,有如下三种方式:
- 状态:通过变量实现,需要主线程不断轮询变量结果
- 通知:通过消息的方式,比状态更高效。
- 回调:本质上和通知类似,如ajax中的回调函数。
在Java中,如果需要返回结果可以采用future模式。因为是异步,调用future.get()的时候不一定能获得结果,如果还没有结果,则会被阻塞。Future是通过轮询或阻塞等待的方式,才能得到结果。更好的方式是通过callback,也就是执行结束的时候异步通知完成状态,然后去future中取执行结果。JDK中有future,但是不支持callback模式。还好Guava给我们提供了ListenableFuture。
5.3.3 序列化
从左往右分别是Avro、Thrift、Protobuf、gRPC、HTTP+json。可以看出前三个是一个级别的,相差不大。gRPC响应时间稍多一点,HTTP+json最慢。
5.4 通过消息中间件提升写性能
当规模不断变大后,数据库通常成为限制系统性能的主要因素。Mysql5.7单表字段个数为8,数据量为500万,写的吞吐量大约在1000TPS左右。而Kafka三节点集群的吞吐量能达到10万TPS。当然水平分表也可以提升吞吐量,但是水平分表带来的复杂度非常难解决。
5.5 通过缓存提升读性能
常见的缓存包括客户端缓存、HTTP缓存、操作系统缓存、CDN、代理缓存、数据库缓存等。
5.5.1 Guava Cache本地缓存
他比HashMap做缓存好的地方在于,他可以设置过期时间,回收空间。
- maximumSize定义了缓存的容量大小,达到了容量大小就会进行LRU缓存回收
- concurrencyLevel定义了Segment的数量,因为Guava Cache重写了ConcurrentHashMap,concurrencyLevel越大,并发能力越强
- expireAfterWrite定义了缓存过期时间
- refreshAfterWrite定义了缓存定时刷新时间
5.5.2 使用缓存常见问题
- 缓存数据需要设置合理的过期时间
- 为缓存设置回收策略
常见回收算法:FIFO(先进先出)、LRU(最近最少使用)、LFU(最不常用) 3. 先预热数据
5.6 数据库优化
数据库通常是各个系统中最难以扩展的点。一般有以下可以优化的地方:
- 索引、冗余、批量写入
- 减小锁粒度
- 减少复杂查询
- 适当转移事务处理
- 提升硬件性能
- 读写分离
- 分库
- 垂直分表
- 水平分表
- 根据业务情况选择其他数据库
5.6.1 优化慢sql
- 通过Explain 分析sql语句
- 通过慢日志分析瓶颈点
5.7 简化设计
架构是需要全方位考虑的,不可能完全从技术角度去解决问题。除了高性能,还需要考虑架构的复杂度、成本、代码可读性、维护性。
5.7.1 转移复杂度
如让我们设计一个抢红包的功能。抢红包的时候如果通过加锁的方式实现,那么数据库压力会很大。单纯从数据库优化的角度去实现,问题会变得越来越复杂。如果把这些抢红包的请求排序,串行修改数据库,那么数据库就不需要加锁了。
另外拆红包的时候的请求数量肯定比发红包的请求数量大,我们可以在发红包的时候就算好随机金额,拆的时候直接返回,这样并不会降低用户体验。
5.7.2 从业务角度优化
大家通常认为12306网站买票像秒杀,实际上比秒杀复杂的多。秒杀无论前端放出多少流量,后端可以根据库存去抛弃多余的量。12306网站并非如此,除了固定时间放出所有的票,其次用户买票的起始站点都不一样,排列组合有很多。
从业务角度可以这么优化:1.分时段放票。2.分地区放票。3.票的剩余数量不具体显示,只展示有票、无票等文字。4.最终采用排队的方式、满足最终一致性即可。