本文是鱼皮在腾讯实习期间,从零开始一周紧急上线百万高并发系统的相关经验、思路及感悟,分享给大家。
花 5 分钟阅读本文,你将收获:
1. 加深对实际工作环境、工作状态的了解
2. 学习高并发系统的设计思路、技术选型及理解
3. 学习工作中对接多方的沟通技巧
4. 学会与测试打配合的技巧
5. 学习紧急事故的处理方式
6. 事后如何进行归纳总结
7. 感受笔者爆肝工作的痛苦与挣扎
前言
从年前开始和导师二人接手了一个紧急项目,年前加班做完一期后项目效果显著,于是年后开工立刻加急开发二期,目标是一周上线。由于项目业务逻辑复杂、工期紧、人手缺、对接方多,难度很大,极具挑战性,因此和导师二人开始了 007 的爆肝工作。
远程办公无疑为 007 无休工作制提供了有利条件,那段时间,我做梦都在敲代码。
项目介绍
首先要介绍下负责的项目及系统。项目背景、业务等信息自然不能透露,这里剥离业务,仅介绍关键系统模型,如下图:
如图,我负责的是一个状态流转系统和查询系统,以及它们依赖的数据库服务。
状态流转系统的作用是按照逻辑修改数据库中某条数据的状态字段,并在修改成功后依据状态向其他业务侧发送通知。
查询系统,顾名思义就是从数据库中查询数据,包括最基础的鉴权、查询等功能。
先分析一下系统中一些难点:
1. 查询系统是一个高扇入服务,被其他各业务侧调用,会存在三个问题:
高并发:将各业务侧请求量聚集,经评估,会产生百万量级的高并发请求。
兼容性:如何设计一套 API,满足各业务侧需求的同时容易被理解。
对接复杂:要同时与多个业务侧的同学沟通来讨论接口,想想就是一件很复杂的事情。
2. 状态流转系统的业务逻辑相当复杂。
3. 状态流转系统和查询系统、其他业务侧之间存在交互(比如互相发送通知和调用),对时延、容错性、一致性的要求很高。
分析出了难点,在写代码之前,要先编写可行的技术方案。
设计思路
在实际工作中,编写详细的技术方案是非常有必要的。优秀的工程师会在技术方案中考虑到各种场景、评估各种风险、工作量估时、记录各种问题等,不仅帮助自己梳理思路、归纳总结,同时也给其他人提供了参照以及说服力(比如你预期7天上线,没有方案谁信你?)。
根据二八定理,复杂的系统中,编写技术方案、梳理设计思路的时间和实际敲代码开发的时间比例为 8 : 2。
设计遵循的原则是 “贴合业务”,没有最好的架构,只有最适合业务的架构。切忌过度设计!
此外,还要考虑项目的紧急程度和人力成本,先保证可用,再追求极致。
一些简单的设计这里就略过了,下面针对系统难点和业务需求,列举几个重点设计及技术选型:
1. 高并发
提到高并发,大家首先想到的是缓存和负载均衡,缺一不可。
负载均衡说白了就是 “砸钱,加机器!”,但是为公司省机器、节约成本是每位后端工程师的信仰,这就要靠技术选型和架构设计来实现了。目标是尽可能利用每台机器的资源,抗住最大的并发请求。
选型如下:
编程框架:选择轻量级的 Restful 框架 Jersey,搭配轻量级依赖注入库 Guice
Web服务器:选择高性能的轻量级 NIO 服务器 Grizzly
缓存:腾讯自研海量分布式存储系统 CKV+(支持Redis协议,有数据监控平台)
数据库分库分表:选用公司自研的基础设施,不细说了
负载均衡:轻量级反向代理服务器 Nginx 和 L5 负载均衡,百万并发需要增加十余台机器
CDN 及预热:能够支持高效的文件下载服务
其中,缓存是抗住高并发流量的关键,须重点设计。
缓存方案
1. 数据结构设计
用过缓存的同学都了解,关于缓存 Key 的设计是很重要的。根据业务来,保证缓存 key 之间不冲突、便于查找就好。此处我选择请求参数 + 接口唯一 id 来拼接 key。并且分页查询接口可复用全量查询接口的缓存。
2. 缓存降级
找不到对应 key / redis 连接失败时直接查库。
3. 缓存更新
当数据库发生修改时,