导言:
记得在远2012年时,因为向往着能写高并发程序,自己选择了跳槽。开始时是写支撑数万设备并发的程序(我们物联网设备业务需要保持长连接),随着企业的发展,逐渐增长到十万、数十万设备,当时还讲究挖掘单机性能,所以紧着各种线程模型、I/O模型……不断地挖掘潜能,实在挖不动了就开始着手用分布式方案的解决。比如当时开源的一个高性能服务模型:<https://github.com/yaocoder/HPNetServer>
后来,有幸在这家集团公司开启了内部创业生涯,主导创立运营了一个服务大百万用户的互联网平台级产品,也多多实践了高并发&高性能&高可用服务的编写和运维。
再后来,出去北京参与创业和自己创业了几年,失败后就又回到曾经的公司,这时这个平台已经有千万级用户,百万日活了。但是曾经因为人员的陆续调整,曾经负责高并发&高性能服务的有经验的同事陆续去了北京一线大厂,此时的研发团队对于如何编写运维高并发&高性能&高可用服务经验有限,于是几个月前我结合自己的实践经验和其他业界高手的知识分享编写了这样的指导手册,希望能给予团队这样的指导:找问题、定目标、做实践。
还有,在写这份手册前,又把十年前反复阅读实践的一本书《构建高性能Web站点》重新阅读了一遍,虽然技术在更新迭代,但优秀的书籍和思想永远不会老,年龄焦虑中的我也希望我们每一个曾经的程序员不会老,或者社会和公司不会嫌弃我们老。致青春永在!
一、找问题
1. 对平台业务的了解
平台业务现状决定着服务的特点,如平台的有效用户量/设备量,业务平峰期、业务高峰期、业务低谷期的情况
以我们业务为例:
典型的2B再2C的业务,为幼儿园提供SaaS系统和链接家庭的家校互动平台。累计服务了数万幼儿园与千万规模的家庭用户。
- 园所端的用户体量涉及不到高并发与高性能,只需保证高可用即可。
- 家长端有千万级的用户规模,是高并发、高可用、高性能服务的标准场景。
- 源于用户使用场景,在清晨家长送孩子与中午时间家长休息时是使用APP的高峰期,幼儿园工作日白天属于平峰期,夜晚和周末属于低谷期。
- 源于业务发展特点,在每年的开学季是业务的高峰期+增峰期,原有系统面临着极大的挑战和压力。
2. 对衡量系统性能数据指标的了解
实际工作中发现很多后台同事对基本的性能衡量指标缺乏了解,无法评估系统的性能水平。
一些常见衡量指标
-
RT(响应时间)
系统对请求作出响应的时间
-
Throughput(吞吐量)
吞吐量是指系统在单位时间内处理请求的数量,和响应时间成反比
-
并发用户数
同时在线(建立TCP长连接)用户数
-
RPS(Requests Per Second)
-
QPS( Queries Per Second)
对于一个查询服务,每秒的响应请求数
-
TPS(Transactions Per Second )
服务器每秒处理的事务数。TPS包括一条消息入和一条消息出,加上一次数据库访问
-
-
平均负载(Load averages)
是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,它不仅包含了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
- CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的
- I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高
- 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高
……
压测报告示例
::: hljs-center
图 MeterSphere压测报告
:::
3. 对技术框架、技术组件的了解
实际工作中发现很多同事对所采用的技术框架、技术组件仅仅限于了解和基本应用,但掌握不透彻,应用有限,无法发挥其有效价值。
服务端架构中常见的微服务,数据库(关系型、NoSQL),消息队列,云服务组件等。
4. 对技术原理的了解
浅尝辄止是做好技术工作的大忌,如果对技术原理缺乏了解,造成潜在问题的同时,出现问题无法快速定位问题。
如我们在某年开学季遭遇的服务不可用问题,由于系统某几个接口响应超时产生了级联影响,导致集群单服务器堆积了太多的TCP并发连接,相应耗尽了系统的多种核心资源。同事却因为这种表现现象却直接选择水平拓展资源,而没意识到是接口响应缓慢导致并发连接累积造成socket 句柄资源耗尽和CPU等待造成的高负载的问题,既浪费了资源又没解决问题。
在这个场景中涉及到
- 对TCP和Socket编程原理的理解
- 长连接:是指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。
- 短连接:短连接是指通讯双方有数据交互时,就建立一个连接,数据发送完成后,则断开此连接,即每次连接只完成一项业务的发送。
- 并发连接:并发连接指客户端向服务器发起请求并建立了TCP连接的总和
- ……
5. 系统的全局观
涵盖系统开发、系统测试、服务治理、运维保障
除去技术开发环节,在系统测试环节的故障注入、压力测试……等演练,在服务治理环节的自动缩扩容、熔断降级……等演练,在运维保障环节的监控、告警、处理机制等。
6. 技术债务情况
业务复杂度、数据复杂度、技术复杂度
- 在需求和业务积累过程中导致系统架构复杂化、数据架构复杂化,需要择期进行系统重构。
- 在前期技术选型时技术框架落后,需要择期升级技术框架。
二、定目标
系统的目标:高性能、高可用、高扩展
1. 高性能
- 性能体现了系统的并行处理能力,也就是前面提到Throughput(吞吐量)指标。在有限的服务器资源投入下,并行处理能力的提高也就意味着成本的降低。
- 性能体现了系统的响应能力,也就是前面提到的RT(响应时间)指标。响应时间越短用户的体验越好,也就意味着用户价值的提升。
2. 高可用
- 可用性表示系统可以正常提供服务的时间,高可用体现了系统具有较高的无故障运行能力。
大家可以想象一下一个支持亿万用户的服务宕机的影响。一般用SLA(服务等级协议)来约束,衡量标准为:可用性 = (一定周期内)正常运行时间 / 系统总运行时间,一般使用几个9来描述系统的可用性。
可用度 | 9的个数 | 年停机时间(分钟) | 适用产品 | 备注 |
---|---|---|---|---|
0.999 | 三个9 | 500(8.8天) | 一般服务器 | 测试环境,不能用于生产环境 |
0.9999 | 四个9 | 50 | 企业级服务 | 生产环境最低要求 |
0.99999 | 五个9 | 5 | 一般电信级服务 | 大型商城级等应用 |
0.999999 | 六个9 | 0.5 | 更高要求电信级服务 | 金融级服务器 |
3. 高扩展
- 表示系统的扩展能力,流量高峰期需要在短时间内且不中断现有服务的情况下完成扩容,平滑稳定地承接峰值流量。
在我们业务场景中的体现如:开学季和热门运营活动
- 高扩展性需要考虑:自身的应用服务集群,数据库、缓存、消息队列等中间件,云服务器、带宽、负载均衡器等第三方依赖。当并发量级提升至某个临界点,上述每一个都可能成为扩展的瓶颈点。
三、做实践
1. 高性能的实践方案
1.1 缓存
- 多级缓存:使用CDN、本地缓存、分布式缓存等缓存静态数据或更新频率低的动态数据。同时注意对缓存场景中的热点key、缓存雪崩(缓存穿透、缓存击穿、缓存并发)造成的数据一致性等问题的处理。
- 缓存预热:通过异步任务提前预热数据到本地缓存或者分布式缓存中。
- 预计算:比如非实时个性化推荐场景,可以提前计算好的推荐页面缓存起来,用户登录时直接获取。
1.2 数据库
- 关系型数据库的分库分表和索引优化。
- 借助搜索引擎技术(如Elasticsearch)解决复杂查询问题。
- 选用新型高性能分布式数据库的使用,比如HBase、 ClickHouse等。
1.3 流量治理
- 集群部署,通过负载均衡机制进行自动缩扩容,减少单服务压力。
- 对流量进行削峰填谷,通过MQ(消息队列)承接流量。
1.4 程序及架构
- 并发处理,通过多线程将串行逻辑并行化。
- 异步化,将次要流程通过多线程、MQ、甚至延时任务进行异步处理。
- 减少IO次数,比如数据库和缓存的批量读写、RPC的批量接口调用。
- 减少网络传输或IO时的数据包大小,包括采用轻量级的通信协议、合适的数据结构、减少缓存key的大小、压缩缓存value等。
- 各种池化技术的使用,池大小的合理设置,包括HTTP请求池、线程池(考虑CPU密集型还是IO密集型设置核心参数)、数据库和Redis连接池等。
- 程序逻辑优化,采用更高效的算法。
- 锁选择,读多写少的场景用乐观锁,或者考虑通过更小颗粒度分段锁的方式减少锁冲突。
- JVM优化,GC算法的选择等,尽可能减少GC频率和耗时。
2. 高可用的实践方案
2.1 服务及流量治理
- 对于无状态服务:当前节点出现故障时迅速利用负载均衡组件或服务治理框架切换至另一个可用节点。
- 对于有状态服务:采用主备或者热备方案实施故障节点切换。比如MySQL的主从切换、Redis的哨兵与Cluster集群模式、MongoDB的副本集模式与Sharding 模式。
- 接口层面:合理的超时设置、重试策略和幂等设计。
- 服务熔断降级:为保证核心服务高可用,可牺牲非核心服务,在必要时进行熔断处理。
- 限流处理:对超过系统处理能力的请求直接拒绝或者返回错误码。
对于服务降级与限流,注意客户端也需要进行相应容错设计,尽量降低对用户体验的影响
- MQ(消息队列):消息可靠性保证,包括producer端的重试机制、broker侧的持久化、consumer端的ack机制等。
以上内容可能涉及的组件及技术框架:
- 负载均衡组件:如nginx、公有云弹性负载服务等;
- 服务治理框架:如Dubbo、Spring Cloud、K8s + Service Mesh(Istio)
2.2 运维及监控
- 故障注入与灾备演练:刻意制造系统故障,测试系统高可用能力。
- 降低发布风险:蓝绿部署、滚动部署、金丝雀(灰度)发布。
- 监控告警:搭建基础设施和服务应用级别全方位的监控和告警体系,如CPU、内存、磁盘、网络的监控告警,以及Web服务器、JVM、数据库、各类中间件的监控告警和业务应用指标的监控告警。
3. 高扩展的实践方案
3.1 业务层的拆分:微服务架构
3.1.1 以领域驱动设计(DDD)来进行业务维度的微服务拆分
-
业务中台领域建模
根据流程或功能边界,初步划分子域边界,并将子域分为通用子域和核心子域。在子域内开展事件风暴,找出界限上下文边界,完成领域建模。
-
业务单元化设计
以领域建模为基准进行单元化设计,向上建设微前端实现领域模型的前端页面逻辑,向下建设微服务实现领域模型的领域逻辑。将微服务和微前端组合为业务单元,完成集成、测试和部署。
-
构建企业级前台应用
根据企业级业务流程,组合和编排不同业务单元的微前端页面,实现不同业务单元的业务能力在企业级前台的业务联通和融合。
-
中台和后台的解耦
采用领域事件驱动机制实现中台微服务之间,以及中台与后台之间业务逻辑的解耦,实现数据的融合。
3.1.2 微服务合理的分层架构
::: hljs-center
图 微服务分层架构
:::
参考书籍: 《中台架构与实现——基于DDD和微服务》,作者 欧创新…,出版社 机械工业出版社
3.1.3 微服务框架(生态)的选择
Dubbo、Spring Cloud、K8s + Service Mesh的对比
以下总结大部分摘写自 CSDN用户:chentian114 的文章《技术栈选型之微服务公共关注点及Dubbo、Spring Cloud和K8s横向比对》,我们团队亲自实践的是从Dubbo转向K8s+ServiceMesh(Istio)的技术生态。
- 技术实践对比
Dubbo | SpringCloud | K8s + ServiceMesh | |
---|---|---|---|
服务发现和LB | ZK/Nacos + client | Eureka + Ribbon | K8s service |
API网关 | N/A | Zuul/Spring Cloud Gateway | Ingress Gateway |
配置管理 | Diamond/Nacos | Spring Cloud Config | ConfigMaps/Secrets |
熔断限流 | Sentinel | Hystrix | HealthCheck/Probe/ServiceMesh |
日志监控 | ELK | ELK | EFK |
Metrics监控 | Dubbo Admin/Monitor | Actuator/MicroMeter+Promethus | Heapster+Promethus |
调用链监控 | N/A | Spring Cloud Sleuth/Zipkin | Jaeger/Zipkin |
应用打包 | Jar/War | Uber Jar/War | Docker Image/Helm |
服务语言框架 | Dubbo RPC + Java | Spring(Boot)REST + Java | 框架、语言无关 |
发布和调度 | N/A | N/A | kube-Scheduler |
自动伸缩和自愈 | N/A | N/A | kube-Scheduler/AutoScaler |
进程隔离 | N/A | N/A | Docker/Pod |
环境管理 | N/A | N/A | Namespace/Authorization |
资源配置 | N/A | N/A | CPU/Mem limit,Namespace Quotas |
流量治理 | N/A | N/A | ServiceMesh |
- 生态优劣势对比
Dubbo | SpringCloud | K8s + ServiceMesh | |
---|---|---|---|
优势 | 阿里背书,成熟稳定,RPC高性能,流量治理方面较细致 | Netflix/Pivotal背书,社区活跃,开发体验好,抽象和组件化好 | 谷歌、CNCF背书,抽象和组件化好,微服务生态统一且完整,支持异构语言,社区活跃 |
不足 | 技术较老、更新慢,SDK的耦合度高,仅支持Java技术栈,社区活跃度较低 | 仅支持Java技术栈,运行耗资源 | 技术门槛较高,ServiceMesh的sidecar机制有一定的性能损耗 |
3.2 数据层的拆分
按照业务维度做垂直拆分,按照数据特征维度做水平拆分(分库分表)
4. 扩展实践:云原生技术体系
请参见
Github:<https://github.com/yaocoder/Architect-CTO-growth>
如访问不畅请参见
Gitee:<https://gitee.com/yaocoder/Architect-CTO-growth>