后端架构设计的一些想法

存在问题

一般的项目,在初始阶段由于团队人力物力有限,不大可能把模块拆分得很细。为了节省资源和快速开发,会选择把所有功能做在一个项目中,一次部署就完成了整个系统的部署。

随着需求的变化、用户数量的增加,并发量提高,系统复杂度也会不断提高,原来的架构和开发模式会带来很多问题。

  1. 系统各个模块之间具有强耦合性。
  2. 很多业务逻辑关联度不大的代码会对实际的业务逻辑代码造成比较强的侵入,比如各种写日志的操作代码会遍布系统的各个角落。
  3. 一些功能可能会重复被开发,且开发人员的水平参差不齐,容易造成代码冗余,严重情况下可能造成性能问题。
  4. 原来的项目协作方式会成为项目推进的瓶颈,所有人都工作在同一份代码上,沟通不顺畅,团队内部一团糟。

解决方法

此时是项目架构调整的好时机。需要考虑以下一些问题:

  1. 如何对系统功能进行划分,解耦系统的各个部分。
  2. 各个子系统之间如何沟通?
  3. 如何做到高可用?
  4. 如何把系统设计成可以水平扩展的架构(只要增加机器就能线性地提高性能,理论上可以拥有无限的性能)?
  5. 新架构下的团队协作如何展开?

一个比较通用的后端架构如下图:

后端架构

对于一些可以独立出来开发的功能,比如用户模块、支付模块、日志模块、消息模块、后台模块,都可以考虑单独封装成服务来开发和运维。这些独立的服务对外提供一致的接口,供API端、后台等用户界面调用。这样各个模块之间的耦合度就非常低了,对于一个特定的服务调用,可以由专门的人进行集中维护和优化,调用方也不会直接接触到数据库,提高了整体的安全性和可用性,再也不用担心别的系统用一个效率很差的查询来把数据库拖垮了。对于调用方来说,事情变得简单了,只要调用后端服务提供的接口就好,所有调用方都可以从服务层获得稳定、一致、高效的服务。

服务拆分粒度

我们也需要慎重考虑服务拆分的粒度。拆分粒度太粗,还是容易造成原来的那些问题;拆分粒度太细,维护成本又高。服务拆分粒度需要具体问题具体分析,如何判断要不要拆分一个服务呢?下面列举几种可能的情况供参考:

  1. 当系统中的某个功能模块对整体性能造成影响时,应该考虑拆分出来,并且在服务级别做负载均衡。
  2. 一个模块很明显地和很多模块有直接联系,应该考虑拆分出来,独立对外提供服务。

调用方和服务的交互

一般来说,存在两种类型的远程调用:

  1. 需要立刻得到响应的调用。
  2. 不需要立刻得到响应的调用。

需要立刻得到响应的调用的例子有查询用户订单记录、查询用户基本信息等。不需要立刻得到响应的调用有写一个行为日志到日志服务中、请求某个服务执行某个异步操作等。
这两种类型的远程调用应该区别对待,对于需要立刻得到响应的,我们可以使用各种RPC方案,比如JSONRPC、thrift、protobuf等,具体RPC方案的选择在此不讨论。对于不需要立刻得到响应的,可以利用消息队列来处理,上游调用方只管往MQ的某些频道中中扔消息,下游相关服务会订阅这些频道,负责消费消息。比如刚才提到的写行为日志的操作,调用方根本不关心如何写日志,这些调用方(生产者)仅仅是把一条日志消息给MQ,由MQ路由这些消息到下游服务(消费者),这样就完成了相关服务和调用方的解耦。而且可以对同一个服务启动多个实例进行消费,MQ会对这些实例做轮询,保证服务的负载均衡。