最近在做一个在线平台,架构思路如下
架构演进:1、MVC 2、服务拆分 3、微服务架构 4、领域驱动设计
1、MVC
这个阶段主要是快速实现产品,没考虑其他的,设计之初划分多个app,app内高类聚,app之间低耦合,DB表设计好了之后,实现view层功能需求,利用Django来快速实现功能,后端有许多预留设计,避免产品逻辑的变更带来整个表结构的变动,架构如下图;
MVC架构
nginx是负载均衡,通过权重法,把请求发送到多个Django服务(其实中间还有一个uwsgi),如果是静态请求,nginx直接返回给客户端,如果是其他请求,通过uwsgi传给Django,Django拿到请求,处理响应请求。耗时大的需要异步的,我们用celery处理,使用mysql作为数据库,redis作为缓存,加快请求的响应,减轻mysql负担,同时还有实时消息通知的需要使用了Nginx Push Module。
问题以及处理:
1、Django并不像tornado一样,对并发很支持,Django并发性能差,采用uwsgi+nginx+gevent实现高并发。
2、redis连接数过多,导致服务挂掉,使用redis-py自带的连接池来实现连接复用
3、mysql连接数过多,使用使用djorm-ext-pool
4、Celery配置gevent支持并发任务
5、celery配合rabbitmq任务队列实现任务的异步调度执行
Celery是一个分布式的任务队列。它的基本工作就是管理分配任务到不同的服务器,并且取得结果。至于说服务器之间是如何进行通信的?这个Celery本身不能解决。所以,RabbitMQ作为一个消息队列管理工具被引入到和Celery集成,负责处理服务器之间的通信任务。
随着开发的功能需求越来越多,Django下的app也越来越多,这就带了发布上的不方便,每次发布版本都需要重启所有的Django服务,如果发布遇到问题,只能加班解决了。而且单个Django工程下的代码量也越来越多,不好维护。
2、服务拆分
前面设计的app内高类聚,app之间低耦合是为服务拆分做铺垫的,首先先把公用的代码抽离出来,实现一个公用的库,其他的还是公用。估计当数据量增加后,要对redis以及mysql进行优化,可以分库分表,后续还需要拆分业务,这个要看原来的代码整洁度和互相依赖程度。
service separation
Nginx Push Module,长连接最大数量不够,使用Tornado + ZeroMQ实现了tormq服务来支撑消息通知。
问题:
随着业务拆分,继续使用Nginx维护配置非常麻烦,经常因为修改Nginx的配置引发调用错误。每一个服务都有一个完整的认证过程,认证又依赖于用户中心的数据库,修改认证时需要重新发布多个服务。
前面二层的架构均已实现,后续的微服务以及领域驱动设计由于我还未涉及到(我之前工作是使用Java做的微服务),所以在此贴出一位python开发工程师的解决办法。
3. 微服务架构
Microservices
首先是在接入层引入了基于OpenResty的Kong API Gateway,定制实现了认证,限流等插件。在接入层承接并剥离了应用层公共的认证,限流等功能。在发布新的服务时,发布脚本中调用Kong admin api注册服务地址到Kong,并加载api需要使用插件。
为了解决相互调用的问题,维护了一个基于gevent+msgpack的RPC服务框架doge,借助于etcd做服务治理,并在rpc客户端实现了限流,高可用,负载均衡这些功能。
在这个阶段最难的技术选型,开源的API网关大多用Golang与OpenResty(lua)实现,为了应对我们业务的需要还要做定制。前期花了1个月时间学习OpenResty与Golang,并使用OpenResty实现了一个短网址服务shorturl用在业务中。最终选择Kong是基于Lua发布的便利性,Kong的开箱即用以及插件开发比较容易。性能的考量倒不是最重要的,为了支撑更多的并发,还使用了云平台提供的LB服务分发流量到2台Kong服务器组成的集群。集群之间自动同步配置。
饿了么维护一个纯Python实现的thrift协议框架thriftpy,并提供很多配套的工具, 如果团队足够大,这一套RPC方案其实是合适的,但是我们的团队人手不足,水平参差不齐,很难推广这一整套学习成本高昂的方案。最终我们开发了类Duboo的RPC框架doge,代码主要参考了weibo开源的motan。
4. 领域驱动设计
domain driven design(ddd)
在这一架构中我们尝试从应用服务中抽离出数据服务层,每一个数据服务包含一个或多个界限上下文,界限上下文类只有一个聚合根来暴露出RPC调用的方法。数据服务不依赖于应用服务,应用服务可以依赖多个数据服务。有了数据服务层,应用就解耦了相互之间的依赖,高层服务只依赖于底层服务。
出处:https://zhu327.github.io/2018/07/19/python/后端架构演进/