不少开发团队于项目起始阶段,经历过单体架构带来的那种感受犹如操作迅猛如虎一般快速顺畅的体验,一番操作迅速且有力,项目便能够上线并开始运行。

可一旦用户数量以及业务复杂程度攀升起来以后,这般的“畅快之感”将会转变为“苦涩滋味”,每一回的调整都极有可能引发一系列多米诺骨牌效应,致使你切实领悟到所谓的“成长过程中的困扰”究竟是怎样的一番境遇。

现如今,我们着手去谈论有关怎样从单体朝着分布式迈进的话题,将这期间所存在的陷阱以及积累的经验,一次性阐释得明明白白。

单体集中式架构的生存法则

单体应用,是将全部业务逻辑,都塞入到一个代码库之中,在进行部署的时候,它呈现为一个完整的包。

曾在2018年时,我参与了一个电商创业项目,起初的三个月呈现为典型的单体架构,团队仅仅有5个人,从用户注册到下单支付均处于一个工程之中,每日能够迭代三个版本并上线。

对于日活用户低于1万的小项目,单体架构反而是最高效的选择。

那时,我们借助Spring Boot来构建,一台服务器有着4核8G的配置,如此配置下全部流程得以运行通畅,关于开发环境搭建仅需十分钟,新人在入职当天便能够参与到开发之中。

但单体架构有个致命弱点就是模块间耦合严重。

有一回,我们对订单模块当中的某个工具类作了修改,随后,用户模块的登录功能就出现了异常状况,花费了一下午的时间去排查,最终才发觉是依赖冲突的问题。

这种问题在高并发场景下会被无限放大。

垂直拆分要掌握好边界

在业务代码数量达到超过十万行这个状况出现的时候,或者是开发人员数量多于十五人这种情形发生那会儿,就应当要去考虑进行垂直拆分这个行为了。

在二零一九年,当我们团队的用户量突破五万之际,便把商城的前台以及后台管理拆分成了两个独立自主的应用,其中前台由三个人进行维护,而后台则由两个人负责维护,二者之间互不产生干扰。

垂直拆分时要特别注意接口定义。

我们那时将前后台共同使用的商品查询逻辑,给抽离成了jar包,然而在后期的时候,却发现每次进行修改,就都得重新打包发布,这显得极为麻烦。

在处理数据同步这件事情上,正确的做法是,构建起清晰的数据同步机制,比如说,采用消息队列来处理跨应用的数据一致性问题。

垂直拆分后虽然代码清爽了,但数据库依然是单点。

我们曾遭遇一回数据库死锁造成整个商城陷入瘫痪持续两小时之久的事故,诱因在于后台的一项批量报表查询致使整张商品表被锁定,进而直接对前台用户下单产生影响。

微服务拆分粒度要结合团队规模

微服务不是越细越好,要根据团队人数来决定服务粒度。

当我们团队人数为20人之际,将系统拆解成了五个微服务,分别是用户微服务、订单微服务、商品微服务、支付微服务还有库存微服务,每个人负责其中一个服务,进而使得沟通成本显著降低了。

服务进行拆分的时候,是得要遵循业务边界的这样子的规则的,就好比说订单服务它仅仅只是处理订单核心流程这部分内容的,而物流查询那样的情况却是独立成为了一个辅助服务的状态的。

数据库独立是微服务的关键。

我们曾经犯下过错误,使得订单服务以及支付服务共用同一个数据库,进而一次订单表索引重建致使支付超时,最终大量交易失败。

之后痛感过后冷静思索,强行规定每个微服务独自占有数据库,即使起初数据量少也坚决维持物理隔离。

接口容错设计必须前置。

在2020年双十一那段时期,我们所提供的促销服务,由于流量规模过于庞大,从而出现了宕机的状况,致使那些依赖该促销服务的商品详情页面,全部都无法正常打开。

过后引进Hystrix熔断器,给每个服务设定超时阈值,在核心服务出现降级情况的时候确保基本功能能够正常使用。

容器化部署让弹性伸缩成为可能

Docker让环境一致性不再是难题。

往昔之时,新服务器开展部署环境这一行为,需费诸多周折,绵延许久,如今呢,经打包形成镜像后,于任何一台机器之上,皆能够在极短时间内,以秒为计时单位迅速启动。

我们的团队,将每一个微服务,制作成为独立的镜像,版本号码,严格地对应着Git提交记录,在要进行回滚操作的时候,只需要重新去部署上一个版本。

K8S的自动伸缩功能在应对流量波峰时效果显著。

在前年 618 大促来临之前,我们针对基于 CPU 的使用率配制了 HPA 的策略,当订单服务的 CPU 超出 70%,便瞬间自动扩充实例数量,从平常的 3 个副本骤然扩展至 20 个,稳稳地承受住了三倍流量。

灰度发布能有效控制风险。

对于 K8S 的 Ingress 所用之流量控制,我们采取如下做法,先于新版本上线单个实例,并且接入到 5%的流量,而后观察半小时之久,待证明确无反常情况而后,接着逐步开展滚动更新操作。

有一回,新版本出现内存泄漏情形,正是借助这样的途径,及时实施拦截操作,进而避免了全面性的故障状况。

分布式带来的新挑战需要配套解决

服务发现组件本身的高可用必须保障。

我们运用Consul集群,将其部署于三台处于不同机房的机器之上,哪怕是单个机房出现断电的情况,也不会对服务注册发现造成影响。

每隔三个月会开展一回故障方面的演练,随机地停止掉一个Consul节点,以此来验证业务是不是处于正常状态。

分布式事务是微服务中最棘手的难题。

我们所运用的方式是尽可能去避开强一致性的要求,为例如下,订单创建以及库存扣减产中,涉及对于本地消息表予以实施,并且凭借定时任务进行补偿,最终达成保证数据一致如此的情况即可。

核心交易场景是借助Seata的AT模式来处理的,不过这会额外增添30%的事务响应时间。

全链路监控体系必须提前搭建。

对于每个请求的完整路径,我们借助SkyWalking予以追踪,当用户投诉下单缓慢之际,能够迅速地定位出,是物流服务调用外部快递接口出现了超时情况,而非属于自身代码方面的问题。

从单体到分布式的演进节奏建议

不要为了微服务而微服务。

倘若你的业务模式尚处于不稳定状态,需求频繁地发生变更,那么强行进行拆分的行为,只会导致维护成本出现增加的情况。

有一个创业公司,它仅有10万用户。然而,这家公司却硬是拆分出了20个微服务。最终导致,每天在处理服务间调用时产生异常,为此耗费了大量的精力。

逐步替换比推翻重来更稳妥。

我们花费了三个月之久的时间,首先将用户中心予以从单体中剥离,之后鉴于运行稳定了,才开展拆分商品中心的操作,最后再拆分订单中心。

单体集中式_数据库容器化部署_垂直拆分部署

每次进行拆分的时候,会同步地去完善与之对应的监控,以及日志,以此来确保在新的服务上线之后,能够迅速地发现问题。

核心业务要留足冗余容量。

不管架构怎样进行演进,数据库的容量规划需要留出50%余量,核心服务的容量规划同样也要留出50%余量。

今年年初,某家大厂出现故障,存在业务成长过度超乎预期的情况,致使数据库连接数量抵达上限,进而造成全线瘫痪状态,此一教训,值得每一位技术人员牢牢铭记。

你在项目演进中踩过哪些架构上的坑?

如果你有经历,欢迎于评论区予以分享,烦请点赞并收藏此文章,以便能够随时进行回看,同时也热忱欢迎你将其转发给身旁正为架构选择而发愁的友人。