[实践]如何让我们的线上系统实现高性能、高可用、高扩展性的

背景

我们已经有很多种业务系统在生产环境上跑了。大多数项目初期都是小规模的业务,或者是新开辟的业务,都是要求快速迭代上线,所以在规范和要求上都没有做太多的考虑。开发模式都是来一个业务就直接上一个springboot web项目。导致各大业务系统都是独立的,数据都不互通,还不好管理。后来我们将公司所有业务系统重构成一个SpringCloud 分布式微服务项目(这将会在后续的文章中介绍)。
但现在我们关注如何将现有的系统重构后,让我们的线上系统实现高性能、高可用、高扩展性。
PS: 当然这个改造也是有代价的,就是需要投入人力、物力、财力等资源。我们在改造过程中,也需要尽量减少对现有业务的影响,保证业务的连续性和稳定性。除此之外从代码层面来说,过于复杂的系统还会增加维护成本和出错的概率。这些还没办法避免的,总得有取舍不是吗?代码开发没有银弹,只有不断地优化和改进,在需求和成本之间找到一个能接受的平衡点。

目标

将系统进行改造,实现以下目标:

  1. 高性能:系统能够处理大量的并发请求,响应时间要短。
  2. 高可用:系统能够在故障发生时有备用服务或者或者降级,要具备自动恢复能力。
  3. 高扩展性:系统能够根据业务需求的变化,灵活地进行扩展和缩减。

我们如何改造实现

基础

在进行优化之前,我们先对系统进行了以下的重构:

  1. 模块服务拆分:我们已经将所有业务系统系统整合拆分,按照业务、结算、基础 三个大模块进行拆分,每个大模块又各自拆了对应的子模块。
  2. 分布式微服务架构:采用Spring Cloud作为微服务架构的基础,使用Spring Boot来构建每个微服务。每个微服务负责特定的业务功能,通过RESTful API(Feign)进行通信。这样可以实现服务的独立部署和扩展。
  3. 容器化部署:使用Docker将每个微服务打包成容器,便于部署和管理。使用容器编排工具Kubernetes帮助我们管理容器的生命周期并进行资源分配。
    经过上面三个方式的改造后,我们的系统已经具备了基础的分布式微服务架构。而分布式微服务架构本身就具备了一定的高可用性和高扩展性。接下来我们将进一步优化系统,达到高性能、高可用、高扩展性的目标。

高性能

高性能意味着系统能够处理大量的并发请求,响应时间短。为了实现高性能,我们采取了以下措施:

增加缓存

对于基础服务模块,使用Redis作为缓存数据库,减少对关系型数据库的访问频率,提高数据读取速度。对于一些频繁访问的数据,可以将其缓存到Redis中,减少数据库的压力。
比如我们的用户信息、客户信息、业务数据、基础数据等等。对每个缓存数据做好缓存生命周期管理,避免缓存雪崩和缓存穿透问题。

使用消息队列

可以使用异步替换我们的同步操作减少系统响应耗时,提高吞吐量。
我们最初用的是PulsarMQ, 后续因为从腾讯云迁移到阿里云,Pulsar在阿里云上没有托管服务,所以我们改用了RocketMQ。后续还是因为集团要求,要使用私有云,所以我们又改用了自建的RabbitMQ。

为应对消息队列的切换我们还特地开发了一个消息队列适配器,来适配不同的消息队列。这样我们就可以在不影响业务的情况下,随时切换消息队列。

比如以下两个场景:

  1. 比较耗时的操作切换为异步,如结算账单生成,账单对账,账单分发等操作。
  2. 一些批量操作,比如批量生成账单, 批量导入订单等。
    这样原来用户需要等待蛮久的操作现在能很快响应用户请求。
数据库优化

这部分主要以下多个方式对数据库进行优化:

  1. 数据库分库分表:将单一的数据库拆分成多个数据库,将单一的表拆分成多个表。这样可以减少单个数据库或表的压力,提高查询性能。
    比如我们对结算系统的订单费用表进行了分表处理,将订单常用字段和不常用字段拆分成两个表,提高查询性能。
    对于小包这种大订单量的业务,我们还对订单表进行了分库处理。将订单按照创建时间进行分库分表处理。
  2. 索引优化:为数据库表添加合适的索引。
    因为前期开发阶段对于常用查询字段没有做索引,后续通过对慢查询的监控和分析,添加了合适的索引,提高查询速度。
  3. SQL优化:对SQL语句进行优化,减少不必要的查询和计算。
  4. 读写分离:将数据库的读操作和写操作分离,使用主从数据库架构。主数据库负责写操作,从数据库负责读操作。这样可以提高系统的读性能。
高可用

SpringCloud分布式微服务架构本身就具备了一定的高可用性。为了进一步提高系统的高可用性,我们项目进行了以下操作:

  1. 为每个微服务部署多个实例,使用A/B发布减少发布的影响。这应该是最基础的保障。
  2. 除了微服务本身,所有的中间件比如Redis、消息队列、数据库等都要部署多个实例,使用集群模式。
  3. 配置好Hystrix来实现服务的降级和熔断。这样可以在某个服务不可用时,自动切换到备用服务或者降级处理。

这里另外补充下,多实例的情况下增加了系统的复杂度,包括数据一致性问题等等(可以参考分布式事务的不可能三角:一致性、可用性、分区容错性)。这是需要我们在设计开发中考虑的,同样我们也需要去迭代优化上面这些问题。

高扩展性

服务拆分好了,从架构上就具备了高扩展性。除此之外,我们采用了以下改造:

  1. 将业务系统按照业务所处领域进行服务拆分,形成独立的微服务。每个微服务可以独立部署和扩展,满足业务需求的变化。
    • 比如我们将每个业务系统拆分出来: CRM,供应商......
  2. 从代码层面来说,制作规范并培训团队成员,形成统一的开发代码规范。选用DDD领域驱动设计来进行开发和改造服务等等。
  3. 发布运行使用容器化部署,使用Kubernetes进行容器编排。Kubernetes可以根据负载情况自动扩展和缩减服务实例。

总结

以上的改造有些是我,有些是同事,有些是一起配合进行改造的,期间印象的最深的改造就是,DDD领域驱动设计的方式改造关键业务代码,形成的高聚合低耦合的代码。这种新型开发代码的模式和之前开发方式相比确实新颖有效。除了DDD,其他的要素都在之前或多或少都已经实践过。
通过之前的优化我们可以总结下核心要点:
SpringCloud,Docker,Kubernetes,Redis,消息队列(这里多个取一个),SQL,降级,DDD,监控,团队协作,代码规范