• 一个小型公司怎么落地微服务


    背景

    我所在的公司是一家做直播和视频通话APP的公司,我主要负责服务端。最开始我们的架构很简单,就是单体PHP,全部用lumen写成。Redis缓存都用的少,后端人员也只有两人。

    此时最大的问题主要是慢,单机扛不住多少并发。

    大概2年前想要做直播,开始引进声望、腾讯IM,但是直播房间需要大量的缓存处理,swoole开始进入我的视野。将架构拆分成了API和服务,服务使用的swoft1.0。将原来的lumen还是作为API层保留了。

    此时的问题主要是curl请求依然是一条通道,导致注册IM的时候卡顿,一旦推广人数多了,会卡在注册接口。虽然swoole在后面的版本添加了curl的请求。
    其次是swoft1.0还是雏形,很多高级点的功能并不成熟。大多数的业务都用的Redis在抗。

    随着业务场景的不断扩大,加上GO的火热,我开始考虑将架构中需要集中运算和追求并发的模块用GO重写,于是有了对微服务的研究。准确的说还称不上微服务,只是业务有针对性地选择语言,进行了一些业务模块的拆分。

    那么怎样从PHP到GO,又不影响既有业务?让我们慢慢聊。

    微服务是什么

    对于微服务的讨论网上已经足够多了。其实微服务是一种思想,和分层一样。

    像以前,网络架构、操作系统架构,大多数采用的是分层的思想,因为大家的视野都集中在一台机器上。我们一直在考虑怎样将事情分散给不同的人,比如用户态和管态,比如网络协议的7层架构,包括MVC,都是为了将事情分散。也都是基于大家在一起。

    到了现在,用户数飞速增长,单机再厉害也不可能抗住业务请求了,于是产生了一个新的观念,那就分而治之。

    从横向上来看,可以将全国乃至全球的用户分片,湖北就湖北的机房,杭州就杭州的机房,这样分到每个机房的请求数大大减少。这也就是大家所说的“多活”。
    从纵向来看,可以将不同的业务采用不同的技术,不同数量的集群,不同的处理方式,分而治之,比如账号服务,可以用最优的机器,最好的管理,保证服务永不中断,而采集服务,可以放到每个CND节点,将其分散到全国各地,进行打包汇总了再上传到数据中心进行分析,而数据中心采用CPU密集型的机器,进行分析和存储。这样分工明确,好钢使在刀刃上。

    听上去很美好,是真的很美好么?

    单体应用的不足

    每个公司都是从单体应用过来的,如果有人上来就是集群和微服务,分库分表都已经做好了,那一定是土豪级公司。

    业务都不是一蹴而就的,而是慢慢演化的。

    我也经历过单体应用,其实作为一个人开发是很爽的,没有那么多问题,只用关心MySQL优化一下,该套缓存套一下,然后上线的时候注意下兼容,写起来好爽好快。运维起来也爽,直接上服务器看日志,PHP脚本语言,改了就生效,贼爽。

    其实PHP确实是一个试错最好的语言,对于一个新项目,就是要开发快、上线快,好维护、好运维。

    别上来就微服务,几个开发人员的小公司,去追求微服务、去追求中台架构,这是追求完美吗?不是,是找死。

    但是渐渐的,业务量上来了,开发人员也变多了,问题就显现了:

    • PHP首先就是效率问题,单机能抗的业务量太少了。对于Java首先就是编译开始变慢,IDE开始变卡。
    • 开发人员的变多,导致代码风格也变多,而且代码冲突也变多了,如果是Java还涉及到编译不过的问题。
    • 如果涉及到业务重构,很难,代码量的变多导致耦合性难以保持,很容易牵一发而动全身。
    • 框架升级困难。无法有针对性的选择语言和技术。
    • 难以扩展,可能久了就谁都不敢动了。新同事一来需要阅读大量代码,学习成本极高。如果相关负责人离职,那将是雪崩效应。
    • 对于数据库和Redis是个考验,如果有一个人掌握的不好,则直接崩盘。

    开始拆分

    架构的演进一定是源于痛点,所以在小公司说把集群、微服务玩到很溜是不可能的,那都是实验室的玩具。如果想要当架构师,一定要在业务量足够大的公司。但是在小公司并不妨碍我们对技术的学习。

    最开始由于技术不足和为了方便,我们采用了纵向拆分,就是将业务分块,按路由分组,采用NGINX反向代理,重构一个模块就上一个模块,最后实现了重构。我称为纵向拆分。

    好处是:

    • 模块分离了,模块A有问题不影响B,而且上线可以分开上。
    • 可以用多种语言。
    • 开发人员分离,减少了代码量和代码冲突。

    问题:

    • 公共模块多套,我们采用的一个公共库,比如用户数据、鉴权等,go直接包含这个应用。但是一旦改了这个公共库,所有项目都要打包。
    • 数据库还是没有分离,一个bug拖垮全局的问题依然存在。
    • 最后还是以单体的形式上线的,只是负载均衡更加灵活,运维起来其实很麻烦。
    • 对于单个业务场景,无法隔离,无法降级,无法熔断,挂就是一个业务一起挂。

    后来我开始考虑横向拆分。也就是业界采用比较多的方式。

    就是用户中心、通话中心、直播中心这样分,一个服务只做好一件事。

    其实最主要的因素是人员的增加,现在后端有5个人了,虽然还是小团队,但是对于现在的业务量可以开始探索这种重构方式了。

    所带来的问题

    凡事有利就有弊,没有银弹,也没有不变的架构。往往分久必合,合久必分。

    天然的复杂性:

    • 模块之间调用会不会有问题?账号中心挂了就全挂了。
    • 日志好难查啊, 原来最多就4台机器,现在拆分后一个服务一个机器,虽然加上了docker,但是道理是一样的,日志分散了。
    • 链路追踪很难,一个接口ABCD4个服务,出了问题到底在哪一层挂掉的,不知道。
    • 测试困难,A同事重启了一个服务,调用它的服务全挂。好难。
    • 文档变多了, 原来写个接口文档就好了,现在服务和服务之间也要写文档。
    • 兼容问题,必须要统一标准,不然每个服务暴露的接口都不一样,那真的千奇百怪。
    • 分布式事务问题。如果账号中心有A和B两个机器,我在A机器关注了一个人,从B机器请求到的关注数据没更新,或者在B机器取消关注,怎么保证数据一致性?其实和MySQL的ACID一样。

    面对问题:

    • 首先添加日志采集,现在用的是阿里的日志中心,后面可以用ELK建立自己的日志中心。
    • 其次采用链路ID,根据ID可以直接检索到所有服务的请求状态和耗时。
    • gPRC,直接代码即文档,还挺好。
    • 对于测试,可以加入染色标签,将主分支和开发分支分离,引导流量到不用的机器。
    • 分布式事务是个大话题,后面聊。

    问题肯定是层不不穷的,发现了慢慢优化即可,保持热情,不畏艰险吧。

    为什么要这么费力

    其实我们公司的业务量,基于现在的PHP架构完全扛得住,我完全可以悠哉喝茶写写业务代码。

    首先源于我本来就是一个闲不住的人,其次对于新技术有些热情。

    换句话说,我就是在作死。

    没有把握,千万别这样,真的是吃力可能还不讨好。架构演进必然会带来线上系统的不稳当,如果不是扛不住业务量了,不要轻易尝试。搞不好到最后头发少了,工资还降了。

    我也是小步试错,逐步修改,慢慢演进的。

    总结

    • 根据自己公司的实际情况选择架构。不要盲目和脑袋一热就开始换架构。单挑真的死无全尸。
    • 好的架构都是逐步演进过来的,不要急,适合当前业务场景的架构才是最好的。
    • 不要放弃梦想,不要丢掉程序员的尊严,不要向bug低头,不要向屎一样的代码妥协,不要每天加班都是重复着增删改查完全不考虑全局。

    后面我会继续慢慢分享演进中的学习和经历,欢迎大家指点和讨论。

  • 相关阅读:
    亚马逊云科技面向 macOS 的 Amazon 云服务器 EC2 M1 Mac 实例
    【JDBC Part 1】概述、获取连接、CRUD
    MySQL慢查询:慢SQL定位、日志分析与优化方案
    算法分析至栈与队列
    SpringCloud - 项目组织架构如何搭建
    Himall商城Zip帮助类压缩文件(Zip)
    代码审计:python代码审计汇总(持续更新中)
    2022年湖北助理工程师职称评审费用是多少?多久出证呢?甘建二
    java内部类详解
    向虚拟机里拖文件,VMtools安装问题
  • 原文地址:https://blog.csdn.net/happy_teemo/article/details/115334463