1.如何理解高并发 ①不能只看数字,要看具体的业务场景。不能说 10W QPS 的秒杀是高并发,而 1W QPS 的信息流就不是高并发。 ②业务都是从 0 到 1 做起来的,并发量和 QPS 只是参考指标,最重要的是:在业务量逐渐变成原来的 10 倍、100 倍的过程中,你是否用到了高并发的处理方法去演进你的系统。 2.高并发系统设计的目标是什么 1.宏观目标 ①高性能:性能体现了系统的并行处理能力,在有限的硬件投入下,提高性能意味着节省成本。 ②高可用:表示系统可以正常服务的时间。一个全年不停机、无故障;另一个隔三差五出线上事故、宕机,用户肯定选择前者。另外,如果系统只能做到 90% 可用,也会大大拖累业务。 ③高扩展:表示系统的扩展能力,流量高峰时能否在短时间内完成扩容,更平稳地承接峰值流量,比如双 11 活动、明星离婚等热点事件。
2.微观目标 性能指标:通过性能指标可以度量目前存在的性能问题,同时作为性能优化的评估依据。一般来说,会采用一段时间内的接口响应时间作为指标。 ①平均响应时间:最常用,但是缺陷很明显,对于慢请求不敏感。比如 1 万次请求,其中 9900 次是 1ms,100 次是 100ms,则平均响应时间为 1.99ms,虽然平均耗时仅增加了 0.99ms,但 是 1% 请求的响应时间已经增加了 100 倍。 ②TP90、TP99 等分位值:将响应时间按照从小到大排序,TP90 表示排在第 90 分位的响应时间, 分位值越大,对慢请求越敏感。
③吞吐量:和响应时间呈反比,比如响应时间是 1ms,则吞吐量为每秒 1000 次。
可用性指标:高可用性是指系统具有较高的无故障运行能力,可用性=平均故障时间/系统总运行时间,一般使用几个 9 来描述系统的可用性。
可扩展性指标:面对突发流量,不可能临时改造架构,最快的方式就是增加机器来线性提高系统的处理能力。
因此,高扩展性需要考虑:服务集群、数据库、缓存和消息队列等中间件、负载均衡、带宽、依赖的第三方等,当并发达到某一个量级后,上述每个因素都可能成为扩展的瓶颈点。
3.高并发的实践方案有哪些 3.1 纵向扩展 3.1.1 提升单机的处理能力 方案包括如下两种: 提升单机的硬件性能:通过增加内存、CPU 核数、存储容量、或者将磁盘升级成 SSD 等堆硬件的方式来提升。 提升单机的软件性能:使用缓存减少 IO 次数,使用并发或者异步的方式增加吞吐量。 3.2 横向扩展 因为单机性能总会存在极限,所以最终还需要引入横向扩展,通过集群部署以进一步提高并发处理能力。 ①做好分层架构:这是横向扩展的提前,因为高并发系统往往业务复杂,通过分层处理可以简化复杂问题,更容易做到横向扩展。
②各层进行水平扩展:无状态水平扩容,有状态做分片路由。业务集群通常能设计成无状态的,而数据库和缓存往往是有状态的,因此需要设计分区键做好存储分片,当然也可以通过主从同步、读写分离的方案提升读性能。
高性能的实践方案: 集群部署,通过负载均衡减轻单机压力。 多级缓存,包括静态数据使用 CDN、本地缓存、分布式缓存等,以及对缓存场景中的热点 Key、缓存穿透、缓存并发、数据一致性等问题的处理。 分库分表和索引优化,以及借助搜索引擎解决复杂查询问题。 考虑 NoSQL 数据库的使用,比如 HBase、TiDB 等,但是团队必须熟悉这些组件,且有较强的运维能力。 异步化,将次要流程通过多线程、MQ、甚至延时任务进行异步处理。 限流,需要先考虑业务是否允许限流(比如秒杀场景是允许的),包括前端限流、Nginx 接入层的限流、服务端的限流。 对流量进行削峰填谷,通过 MQ 承接流量。 并发处理,通过多线程将串行逻辑并行化。 预计算,比如抢红包场景,可以提前计算好红包金额缓存起来,发红包时直接使用即可。 缓存预热,通过异步任务提前预热数据到本地缓存或者分布式缓存中。 减少 IO 次数,比如数据库和缓存的批量读写、RPC 的批量接口支持、或者通过冗余数据的方式干掉 RPC 调用。 减少 IO 时的数据包大小,包括采用轻量级的通信协议、合适的数据结构、去掉接口中的多余字段、减少缓存 Key 的大小、压缩缓存 Value 等。 程序逻辑优化,比如将大概率阻断执行流程的判断逻辑前置、For 循环的计算逻辑优化,或者采用更高效的算法。 各种池化技术的使用和池大小的设置,包括 HTTP 请求池、线程池(考虑 CPU 密集型还是 IO 密集型设置核心参数)、数据库和 Redis 连接池等。 JVM 优化,包括新生代和老年代的大小、GC 算法的选择等,尽可能减少 GC 频率和耗时。 锁选择,读多写少的场景用乐观锁,或者考虑通过分段锁的方式减少锁冲突。
高可用的实践方案: 对等节点的故障转移,Nginx 和服务治理框架均支持一个节点失败后访问另一个节点。 非对等节点的故障转移,通过心跳检测并实施主备切换(比如redis的哨兵模式或者集群模式、MySQL 的主从切换等)。 接口层面的超时设置、重试策略和幂等设计。 降级处理:保证核心服务,牺牲非核心服务,必要时进行熔断;或者核心链路出问题时,有备选链路。 限流处理:对超过系统处理能力的请求直接拒绝或者返回错误码。 MQ 场景的消息可靠性保证,包括 Producer 端的重试机制、Broker 侧的持久化、Consumer 端的 Ack 机制等。 灰度发布,能支持按机器维度进行小流量部署,观察系统日志和业务指标,等运行平稳后再推全量。 监控报警:全方位的监控体系,包括最基础的 CPU、内存、磁盘、网络的监控,以及 Web 服务器、JVM、数据库、各类中间件的监控和业务指标的监控。 灾备演练:类似当前的“混沌工程”,对系统进行一些破坏性手段,观察局部故障是否会引起可用性问题。
高扩展的实践方案: 合理的分层架构:比如上面谈到的互联网最常见的分层架构,另外还能进一步按照数据访问层、业务逻辑层对微服务做更细粒度的分层(但是需要评估性能,会存在网络多一跳的情况)。 存储层的拆分:按照业务维度做垂直拆分、按照数据特征维度进一步做水平拆分(分库分表)。 业务层的拆分:最常见的是按照业务维度拆(比如电商场景的商品服务、订单服务等),也可以按照核心接口和非核心接口拆,还可以按照请求源拆(比如 To C 和 To B,APP 和 H5)。 分布式 Trace、全链路压测、柔性事务都是要考虑的技术点