[实践]如何让我们的线上系统实现高性能、高可用、高扩展性的
背景
我们已经有很多种业务系统在生产环境上跑了。大多数项目初期都是小规模的业务,或者是新开辟的业务,都是要求快速迭代上线,所以在规范和要求上都没有做太多的考虑。开发模式都是来一个业务就直接上一个springboot web项目。导致各大业务系统都是独立的,数据都不互通,还不好管理。后来我们将公司所有业务系统重构成一个SpringCloud 分布式微服务项目(这将会在后续的文章中介绍)。
但现在我们关注如何将现有的系统重构后,让我们的线上系统实现高性能、高可用、高扩展性。
PS: 当然这个改造也是有代价的,就是需要投入人力、物力、财力等资源。我们在改造过程中,也需要尽量减少对现有业务的影响,保证业务的连续性和稳定性。除此之外从代码层面来说,过于复杂的系统还会增加维护成本和出错的概率。这些还没办法避免的,总得有取舍不是吗?代码开发没有银弹,只有不断地优化和改进,在需求和成本之间找到一个能接受的平衡点。
目标
将系统进行改造,实现以下目标:
- 高性能:系统能够处理大量的并发请求,响应时间要短。
- 高可用:系统能够在故障发生时有备用服务或者或者降级,要具备自动恢复能力。
- 高扩展性:系统能够根据业务需求的变化,灵活地进行扩展和缩减。
我们如何改造实现
基础
在进行优化之前,我们先对系统进行了以下的重构:
- 模块服务拆分:我们已经将所有业务系统系统整合拆分,按照业务、结算、基础 三个大模块进行拆分,每个大模块又各自拆了对应的子模块。
- 分布式微服务架构:采用Spring Cloud作为微服务架构的基础,使用Spring Boot来构建每个微服务。每个微服务负责特定的业务功能,通过RESTful API(Feign)进行通信。这样可以实现服务的独立部署和扩展。
- 容器化部署:使用Docker将每个微服务打包成容器,便于部署和管理。使用容器编排工具Kubernetes帮助我们管理容器的生命周期并进行资源分配。
经过上面三个方式的改造后,我们的系统已经具备了基础的分布式微服务架构。而分布式微服务架构本身就具备了一定的高可用性和高扩展性。接下来我们将进一步优化系统,达到高性能、高可用、高扩展性的目标。
高性能
高性能意味着系统能够处理大量的并发请求,响应时间短。为了实现高性能,我们采取了以下措施:
增加缓存
对于基础服务模块,使用Redis作为缓存数据库,减少对关系型数据库的访问频率,提高数据读取速度。对于一些频繁访问的数据,可以将其缓存到Redis中,减少数据库的压力。
比如我们的用户信息、客户信息、业务数据、基础数据等等。对每个缓存数据做好缓存生命周期管理,避免缓存雪崩和缓存穿透问题。
使用消息队列
可以使用异步替换我们的同步操作减少系统响应耗时,提高吞吐量。
我们最初用的是PulsarMQ, 后续因为从腾讯云迁移到阿里云,Pulsar在阿里云上没有托管服务,所以我们改用了RocketMQ。后续还是因为集团要求,要使用私有云,所以我们又改用了自建的RabbitMQ。
为应对消息队列的切换我们还特地开发了一个消息队列适配器,来适配不同的消息队列。这样我们就可以在不影响业务的情况下,随时切换消息队列。
比如以下两个场景:
- 比较耗时的操作切换为异步,如结算账单生成,账单对账,账单分发等操作。
- 一些批量操作,比如批量生成账单, 批量导入订单等。
这样原来用户需要等待蛮久的操作现在能很快响应用户请求。
数据库优化
这部分主要以下多个方式对数据库进行优化:
- 数据库分库分表:将单一的数据库拆分成多个数据库,将单一的表拆分成多个表。这样可以减少单个数据库或表的压力,提高查询性能。
比如我们对结算系统的订单费用表进行了分表处理,将订单常用字段和不常用字段拆分成两个表,提高查询性能。
对于小包这种大订单量的业务,我们还对订单表进行了分库处理。将订单按照创建时间进行分库分表处理。 - 索引优化:为数据库表添加合适的索引。
因为前期开发阶段对于常用查询字段没有做索引,后续通过对慢查询的监控和分析,添加了合适的索引,提高查询速度。 - SQL优化:对SQL语句进行优化,减少不必要的查询和计算。
- 读写分离:将数据库的读操作和写操作分离,使用主从数据库架构。主数据库负责写操作,从数据库负责读操作。这样可以提高系统的读性能。
高可用
SpringCloud分布式微服务架构本身就具备了一定的高可用性。为了进一步提高系统的高可用性,我们项目进行了以下操作:
- 为每个微服务部署多个实例,使用A/B发布减少发布的影响。这应该是最基础的保障。
- 除了微服务本身,所有的中间件比如Redis、消息队列、数据库等都要部署多个实例,使用集群模式。
- 配置好Hystrix来实现服务的降级和熔断。这样可以在某个服务不可用时,自动切换到备用服务或者降级处理。
这里另外补充下,多实例的情况下增加了系统的复杂度,包括数据一致性问题等等(可以参考分布式事务的不可能三角:一致性、可用性、分区容错性)。这是需要我们在设计开发中考虑的,同样我们也需要去迭代优化上面这些问题。
高扩展性
服务拆分好了,从架构上就具备了高扩展性。除此之外,我们采用了以下改造:
- 将业务系统按照业务所处领域进行服务拆分,形成独立的微服务。每个微服务可以独立部署和扩展,满足业务需求的变化。
- 比如我们将每个业务系统拆分出来: CRM,供应商......
- 从代码层面来说,制作规范并培训团队成员,形成统一的开发代码规范。选用DDD领域驱动设计来进行开发和改造服务等等。
- 发布运行使用容器化部署,使用Kubernetes进行容器编排。Kubernetes可以根据负载情况自动扩展和缩减服务实例。
总结
以上的改造有些是我,有些是同事,有些是一起配合进行改造的,期间印象的最深的改造就是,DDD领域驱动设计的方式改造关键业务代码,形成的高聚合低耦合的代码。这种新型开发代码的模式和之前开发方式相比确实新颖有效。除了DDD,其他的要素都在之前或多或少都已经实践过。
通过之前的优化我们可以总结下核心要点:
SpringCloud
,Docker
,Kubernetes
,Redis
,消息队列
(这里多个取一个),SQL
,降级
,DDD
,监控
,团队协作
,代码规范