天天看点

微服务

目录

  • 什么是微服务?
  • 为啥要拆分?
    • 对比传统架构
      • 数据访问杂乱
      • 顺应时代变化
  • 怎么拆分?
    • 压力模型拆分
    • 业务模型拆分
      • 主链路拆分
      • 领域模型拆分
      • 用户群体拆分
      • 前后台业务分离
  • 拆分成微服务后的挑战
    • 服务治理和负载均衡
    • 服务容错
    • 配置管理
    • 服务网关
    • 调用链路追踪
    • 消息驱动
    • 限流

所谓微服务就是将一个单一的服务拆分成多个微小的服务。每个服务遵从单一职责原则,并且可以独立部署。

如果一个项目它的用户只有100个人,那么我想这个项目并不需要做微服务划分,因为对于这种规模的项目来说,单体应用才是最好的选择,微服务反而会增加运维和研发的成本。

那么当你的应用要承受几十万用户的时候,无论是从交付迭代的效率来说,还是从高可用的角度来说,微服务架构会是更好的选择。

随着互联网行业的飞速发展,个人的衣食住行几乎全依赖各种APP来满足。每天早上起来刷刷淘宝,地铁上用视频app看个短句,一天微信不离手,睡前刷个抖音一不小心就刷到了后半夜,这些现象级全民应用层出不穷,所承接的用户访问量远飞上古时期的门户网站所能比拟的。在这种用户量级下还要能够满足不断变化的用户请求,就像给飞行中的飞机换引擎,传统的架构模式已经完全不能满足业务发展的节奏。

我们来举几个“单体应用”中经常被人诟病的几个问题:

微服务

同一个war包内,在数据访问层面没有划分领域模型,比如说我们有User、Product和Order三张表,对于不同的Service来说,都通过直接访问数据库的方式来获取数据。这种做法有几个显而易见的缺点:

  • 数据模型变更

    拿Order表来说,如果某一天我的Data Model发生了重大变更,比如说引入了“子订单”的概念,原先的数据模型不能再很好地支持业务,必须重构Order订单表,与此同时,还要兼容老的订单结构。这种情况下你能贸然改动数据模型吗?恐怕不行,原因就是这个Order表被这个系统中的各个服务引用到了,你的改动可能会破坏其他服务的功能。

    对于传统的应用结构来说,一丁点数据结构的改变都会引起很大的影响。然而对于微服务来说就很简单了,通过微服务架构在各个服务之间做好隔离,将Data Model的影响带来的业务复杂度隔离在当前微服务中,划分好领域模型,上下游服务只要对接微服务的接口就可以,领域模型驱动不用依赖底层数据结构的变更。

  • 底层组件变更

    假如现在我要对Product表的数据访问规则做一个变更,比如引入MyCat分库分表,或者对热点数据的访问加上缓存读写的步骤。那么意味着上下游所有访问Product表的业务,都需要连带着做同样的改动。

    再说个更极端的例子,以前我们使用的是Oracle,这家伙老贵了,领导层想要换成MySQL,即便我们没有存储过程的牵绊,那么这个变更也是极其巨大的,可谓牵一发而动全身。

    理论上来说,我们应该尽可能对业务层屏蔽底层组件的变更,在传统的分布式应用中非常难以办到,但是在微服务架构下却没有那么困难,因为微服务间的访问依赖API接口+业务模型,我们只要在当前微服务中把这种底层组件的变更处理好,对上下游其他服务来讲这个变更其实是无感知的,因为在微服务接口暴露出的业务模型并不会有什么变化。

  • 时不我待!糙快猛才是生产力

    当今互联网公司的业务节奏,拥抱变化不是白叫的,研发团队沉浸在996的福报中不能自拔。就像前面说的,为了支持不断变化的新业务,开发团队对系统的改造就像给飞行中飞机换引擎,既要让飞机飞,又要保证完成任务,还得要快。因此我们提出了“糙快猛”的开发模式,它是继瀑布模型、敏捷模型等等软件工程理论之后的具有中国特色的互联网研发模式。

    面对一个屎山一般的单war包应用,产品的发布节奏往往是以月甚至年来计,一个变更从评估到上线,拖个一年半载是很常见的事情,这种节奏对于互联网公司来说,倒闭100次都够了。

  • 小步快跑

    互联网产品的迭代依靠小步快跑,尽快上线,尽快验证业务模式,有问题立即调整,一切都是“快字当头”。对于传统应用来说,发布节奏只能划归到一个千年等一回的发布窗口,再小的变更都得耗上很长的时间,可能每次发布都要经历很耗时的全链路回归测试。对微服务架构来说完全不存在这个问题,每个微服务模块由于职责边界足够清晰,规模可控便于快速变更和测试,完全可以让团队自己制定发布窗口,即便是上线前的回归测试也只局限在当前服务模块。

  • 回滚

    回滚对于传统的单war包分布式系统来说是个噩梦,好不容易等到了发布窗口,各个团队牟足了劲把所有变更都发布了出去,结果因为其中某个小改动引发的问题,导致全部回滚。又要苦苦等待下一个发布窗口。

    在微服务架构中,回滚只局限在某个微服务的范围内,只要把出问题的应用回滚就好了,不会影响上下游其他应用的发布节奏。

微服务拆分没有一个绝对正确的方案,服务拆分的粒度完全要根据业务场景来规划,而随着业务的发展,原先的架构方案也需要做调整。下面总结几个常用的拆分策略。

压力模型简单来说就是用户访问量,我们要识别出某些超高并发量的业务,尽可能把这部分业务独立拆分出来。这么做的原因非常简单,高并发业务相当于前线战场,战况非常激烈,如果我方部署兵力不够(服务器资源),而敌方攻势又过于猛烈(剁手族们疯狂的流量),万一战线失手了服务器压力抵挡不住,我们不希望让这种情况影响到其他用户场景。

例如:

  • 秒杀:

    秒杀是一个典型的低频突发流量的场景,参加秒杀的商品的数量一般不会很多,但是在秒杀开始的时候,尤其是对爆款商品来说(比如新发布的苹果手机),会有一个很明显的突发流量。

  • 商品详情页:

    商品详情页毫无疑问是电商场景中并发量最大的业务,一笔成功达成的订单背后,可能会调用几十次商品详情页接口。

那么在做具体规划的时候,可以把压力模型拆解为三个维度:

  • 高频高并发场景

    比如商品详情页,它既是一个高频场景(时时刻刻都会发生),同时也是高并发的场景(QPS - Query per seconds极高)

  • 低频突发流量场景

    比如前面提到的秒杀,它并不是高频场景(偶尔发生),但是它会产生突发流量。再跟大家举一个例子,那就是“商品发布”,对新零售业务来说,当开设一个线下大型卖场以后,需要将所有库存商品一键上架,这里的商品总数是个非常庞大的数字(几十万+),瞬间就可以打出很高的QPS

  • 低频流量场景

    这一类多为后台运营团队的服务接口,比如商品图文编辑,添加新的优惠计算规则,上架新商品。它发生的频率比较低,而且也不会造成很高的并发量。

通常我们建议将高频高并发的场景隔离出来,单独作为一个微服务模块,典型的就是商品详情页的后台服务。对低频突发流量的场景,如果条件允许也可以剥离出来独立组成模块,如果必须和其他业务包在一个微服务下,那一定要做好流控措施(最典型的就是削峰策略),而且还要考虑到异常情况下的补偿机制。对于低频流量场景,我们根据业务模型切分就好了。

业务模型拆分的维度有很多,我们在实际项目中应该综合各个不同维度做考量。这里主要从主链路、领域模型和用户群体三个维度来讲一下。

在电商领域“主链路”是一个很重要的业务链条,它是指用户完成下单场景所必须经过的场景。按照我们平时买买买的剁手经验,可以识别出很多核心主链路,比如商品搜索->商品详情页->购物车模块->订单结算->支付业务,这是就是一条最简单的主链路。如果这是一场战斗的话,那么主链路就是这场战斗的正面战场,我们必须力保主链路不失守。

电商领域背后还有很多隐藏的核心主链路,比如下单之前的营销优惠结算,它会影响订单的最终价格;再比如用户地址模块,它会影响下单前的配送地址选择。如果这两个模块出了问题,大部分用户恐怕都要放弃下单了。试想,双十一我们添加了一揽子购物车,结果结算的时候发现所有优惠组合都失效了,或者是无法选择配送地址,那也只好放弃了。

所谓领域模型,其实就是一套各司其职的服务集合,这里涉及到领域和合并和分拆。例如一个电商系统拆分成订单系统、商品服务、营销优惠服务、支付平台、用户账号系统等。做微服务规划的时候要确保各个领域之间有清晰的界限,比如商品服务,和订单服务,尽管他们之间有交集(都围绕商品主数据),但是毕竟是服务于不同领域(商品域和订单域),所以我们要将两者拆分成独立的服务。

根据用户群体做拆分,我们首先要了解自己的系统业务里有哪些用户,比如说电商领域,我们有小卖家,也有大客户,在集团内部有运营、采购、还有客服等等。对每个不同的用户群体来说,即便是相同的业务领域,也有该群体其独有的业务场景。

用户群体相当于一个二级域,我们建议先根据主链路和领域模型做一级域的拆分,再结合具体的业务分析,看是否需要在用户领域方向上做更细粒度的拆分。

以网约车为例,网约车业务不仅有一个乘客端app,也有一个司机端app。电商领域也是一样的,我们通过手淘app买买买(前台业务场景),商家通过后台的业务系统管理商品信息(后台业务场景)。在实际项目中通常也会将前台业务和后台业务做一个隔离,这也符合高频业务(前台)和低频业务(后台)的隔离策略。

下面我们看一看在微服务改造的过程中,需要我们去攻克的技术难点。

微服务架构广泛应用在超高并发系统中,中后台服务集群的规模着实不小。因此,服务与服务之间的调用,就成了微服务架构需要解决的第一个问题。与此同时,大规模集群中虚机的上线下线是每天的日常任务,集群的扩容缩容也很常见,我们的微服务架构需要探知到集群中各个服务节点的状态变化,这样就知道哪些节点是可以正常提供服务的。我们管这个领域叫做服务治理。

与服务治理搭档的还有负载均衡,面对茫茫多的服务器,如何将海量用户请求分发到不同的机器。考虑到有的机器性能比较弱,或者机房带宽不大,网络响应慢,如何根据实际情况动态地分发服务请求?这个领域就是负载均衡需要解决的事情。

在高并发场景下,有的服务会承担较大的访问请求,这有可能导致响应时间过慢,甚至会响应超时。那调用方在超时后经常会发起重试,这样会进一步增加下游应用的访问压力,进而导致一个恶性循环。那么面对这种情况,我们有解决方案吗?以上就是微服务领域中降级和熔断技术需要解决的问题,我们管这些叫做服务容错。

对于项目配置项的管理,我们平常都会使用配置文件,那么假如有一个业务场景,需要随时调整配置,配置文件的管理方式可能就不行了,我们总不能每次改配置的时候都要重启机器吧。

那么把配置项存到数据库里?可以倒是可以,但是访问量增加的时候也会将压力传导到数据库,数据库往往是比较弱不禁风的一环,很可能被压垮。那么放到缓存里?这一定程度上解决了性能问题,不过在某些业务场景下还是不好用,比如我希望给不同服务器配置不同属性值,指定name属性在某100台机器中的值是张三,在剩余机器中的值是李四。

以上问题在微服务领域也不是什么大问题,服务配置管理就是专门解决这类问题的利器。

我们的系统对外提供的网络访问入口只有一个,这通常就是一个域名网址。但是这套系统后面的服务器可有千千万,那么在微服务架构下,是如何将用户请求转发到每个不同的服务器上的呢?这就是服务网关需要解决的事情。

有这么一个例子,有个用户买了两只大猪蹄子,结果东西送到家变成了两只鸡爪子。店小二说没发错货啊不信自己看订单,打开一看还真是,下单的时候选的猪蹄子,下单以后就成了鸡爪子。

上面这个问题出在整个下单链路哪个环节呢?是订单中心搞错了商品ID,还是购物车页面传了错误ID给订单系统,或者说搜索页面一键下单功能没取到正确的ID?

调用链追踪,从前到后整个调用链路全景数据展现,用事实说话,从此甩锅更加精准!

上一篇: 微服务
下一篇: 微服务

继续阅读