简单粗暴
几乎所有的互联网产品刚开始的时候都是简单粗暴的,我们也不例外。你不可能在最初的时候就把之后所有的场景都考虑进去,既没必要也不可能。最好也是最常用的做法是,基于我们熟悉的技术,先出一个1.0版本,然后在这个版本上不断的更新调整,以适应越来越复杂的场景。
话不多说先上图。
框架图
我们从一开始就坚持前后端分离,前段负责controller和view,后端专注model。
接下来就简单描述一下这一套框架和他的优缺点吧。
前段主要基于Angular来做,由于我是后端所以略过前端不谈。
优点
1. 采用Linux+nginx+Mongo+php架构,Yii2框架,提供RESTful API,接受前端请求然后返回json数据。成熟的体系可以满足大部分业务需求,模块化编程,公众号,会员,营销,商城,每一个模块有自己的model,controller,view业务范围清晰,方便我们扩展,也方便我们基于已有的基础模块做差异化定制。也给未来要面对的微服务界限划分提供了先天的参考。
2. 随着业务不断复杂,我们加入了后台任务调度系统resque来处理异步请求,统计数据。极大的减小了业务处理那一块的压力,也使系统更加灵活方便。后台任务可以说是相对独立的一块系统,横向扩展极为方便,基本,没有出现过job处理不及时的问题。
3. 和各大社交平台对接,每个平台一套自己的API,如果要放到业务处理里面,那情景可想而知。所以就有了单独的社交服务,社交服务单独的team来做,整合各大社交平台,然后提供统一的RESTful API。业务处理这一块的开发工作由微信,微博,支付宝三份API文档变成了一份API文档,极大的方便了业务开发。
4. 我们既是在做产品也是在做平台,面向企业用户,自然会有第三方开发者。我们需要基于已有的业务,给第三方开发者提供API。有人说go语言天生就是做服务端的,我想给他点个赞。我们当时选go来重新开发是基于以下几点考虑:
- go语言在执行效率上高于php,并且多线程用起来很方便,这个网上很多人有过相关评测
- 由于是给第三方开发者的API, 权限验证,限流,版本控制,错误处理等等都和已有的不太一样。并且也只是部分业务需要提供给第三方,工作量也不大(ps:后来的事实证明,工作量越来越大),索性拎出来单独做
- 不断尝试新的东西可能是我们程序员的优良传统
5. cdn的应用,所有由用户上传的东西都采用云存储。现在这个应该是趋势了,好处看得见。
缺点
1. 社交服务这里只提供API,微信事件没法主动通知后端业务。比如当微信用户扫描二维码时,业务层想给扫码的人标记出来做后续处理,这种业务实现起来就很困难。
2. 后端业务处理各模块之间耦合严重。虽说各个模块从职责上区分开了,但是彼此间少不了数据交互,代码严重耦合,导致业务层越来越肥并且不可拆分。而且各模块的开发团队虽然各自开发,却只能统一在规定时间点上线,也是矛盾点之一。
3. 客户越来越多,需要提供给第三方的API也越来越多,很多业务既要提供一套api给我们自己的前段集成(php),又要用go写一份给我们第三方,造成了不小的人力成本的浪费。
4. 数据量越来越大,单表数据突破千万,查询效率明显降低,单纯的复制集读写分离,加索引已经没办法彻底解决问题了。
于是基于以上的一些缺点,我们很快做了一些调整, 1.1到来了。
开始微调
MQ和Webhook
消息队列 社交服务层和业务处理层只需要在事件发生时将消息入队,不关心谁会接收这个消息。
事件分发层只需要从配置里面读取webhook配置,并转发出去。
需要接受事件的用户只需要subscribe自己关心的事件,然后在相应的url上接收事件。
由此我们打通了社交渠道和业务层之间的通信,剪断各模块的耦合,并且还给第三方开发者提供了方便的服务
Opensearch
为了解决,数据量大查询效率低下的问题,我们引入了Aliyun opensearch。将部分数据量大,并且查询业务频繁,搜索条件复杂的数据,在数据入库的同时存入opensearch。这样只是解决了部分问题,因为opensearch不适合存一些频繁改动的数据,只适合聊天记录这种一旦生成不会再变得死记录,对于频繁改动的数据,opensearch实在不是一个好的选择。
分库
上面说到了,我们并没有一次性解决数据量大的问题,还有些频繁改动并且数据量大的表还是存在这样的问题。
我们的客户是企业级的,所以客户不会太多。于是按客户分库,每一个客户一个数据库,主库中只保留客户信息和客户数据库的Mapping关系。同时调整原有的复制集,建立多个数据中心,各客户库的数据节点在各个数据中心交叉复制,最大限度的保证可用性。
微调时代到此为止了,这时候我们的系统已经大致上能抗住现有的规模了。但是还是留下了部分问题,随着业务发展,第三方API(go)维护和开发工作越来越多,并且已经大量和后端(php)重复,每次都得维护两份代码实在欲哭无泪。并且后端业务层还是太大了,并且还在增长。这时候我们想如果能按照模块划分各自完全拆开来,每个模块写自己的RESTful api, 完全用go来实现该多好。于是我们迎来了微服务时代。
微服务
下面这张图是我们理想中的样子,当然这只是简化版负载均衡,trace跟踪,熔断,限流,监控虽然没有画出来,但是每一项都至关重要。
微服务
以模块为边界我们将业务服务化,每一块服务可以按照需要起多个实例,各服务有自己的db互不干扰。这样解决了代码冗余的问题,进一步提高了系统的可用性和稳定性。但是同时也引入了更深层次的问题,运维成本大大增加,对监控系统的要求也比以往更加严苛。新的问题带来新的挑战,只有不断探索,不断挑战才能走的更远。
路漫漫其修远兮,吾将上下而求索。
网友评论