zoukankan      html  css  js  c++  java
  • 浅谈微服务落地实践

    随着架构设计的发展,微服务架构可以说是目前架构领域炙手可热的设计理念。在公司,个人也一直在负责系统的服务化设计和开发工作。

    今天就来谈谈微服务落地实践中的一些问题。希望对微服务设计无从下手的朋友,起到一些参考作用;另外也希望把自己的观点分享出来,期待与大家一起交流,能够认识到不足之处。

    一、服务拆分

    在落地微服务之前,我们遇到的第一个问题就是:应该如何拆分服务?

    大家知道,关于如何拆分服务,并没有一个完全通用的法则。不过有以下几点要素,我们可以参考。

    1、业务独立性

    一般情况下,我们第一时间都会考虑到这点。将系统中的业务模块,按照职责标识出来,每个单独的模块拆分成一个独立的服务。

    这样拆分之后,我们的服务要满足一个原则:高内聚,低耦合。

    比如,我们把一个系统拆分为商品服务、订单服务、物流服务。一般情况下,我们修改物流服务的时候,并不会影响商品服务,这就是低耦合的体现;那么订单服务里面的功能和逻辑,都是围绕着订单这个核心业务流程的,就可以说它是高内聚的。

    2、业务稳定性

    我们可以把系统中的业务按照稳定性进行区分。比如,用户注册、登录部分,这一块的代码只要写完,基本就不再会发生变动,那么我就将他们拆为用户服务。

    同理,还有日志服务、监控服务,这些模块基本上也都是很稳定的业务,可以考虑单独拆分。

    3、业务可靠性

    这里讲究的是,将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用。

    避免由于非核心服务故障,而影响核心服务。

    4、业务性能

    基于业务性能拆分,考虑的是将性能压力大的模块拆分出来。对于这一点,有两点想法:

    • 避免性能压力大的服务影响其他服务。
    • 将高流量的业务独立出来,扛不住的情况下,方便水平扩展。

    比如,在笔者参与的一个系统中,曾通过 RocketMQ 对接来自多家厂商的大量数据。

    当时,就独立出来一个消息服务,专门用来消费消息。然后有的是在本地处理,有的通过 RPC 接口转发到其他服务处理,有的直接通过 WebSocket 推送到前端展示。

    这样的话,即便流量激增,考虑给消息服务增加机器,提高消费能力就好了。

    当了解到上面这几种拆分方式之后,我们就可以根据自己的业务范围和技术团队规模,来考虑自己系统的服务拆分了。

    不过在这里,尤为值得注意的是,微服务切忌拆分的过细,一定要结合业务规模和技术团队的规模。

    二、服务健壮性

    拆分了服务,还需要考虑细节问题,为可能出现的场景做好准备。

    1、超时和容错

    服务化之后,不同服务之间的调用就是远程调用。远程调用有个最基本的设置,即超时时间。

    比如,在Dubbo中,默认的超时时间是1秒。我们不能单纯的使用默认值或者统一设置成另外的值,为Dubbo设置超时时间最好是有针对性的。

    比如,比较简单的业务可以设置的短一些;但对于复杂业务而言,则需要适当的加长这个时间。因为,这里还涉及到一个集群容错的问题。

    Dubbo中,集群容错的默认策略是失败重试,次数为2。假如有的业务本身就需要耗费较长的时间来执行,因为超时时间太短就会触发容错机制,来重试。大量的并发重试请求,很可能会占满Dubbo的线程池,甚至影响后端数据库系统,导致连接被耗尽。

    2、容错和幂等性

    我们上面说,如果超时时间设置太短,有可能会导致大量请求会不断重试,而导致异常。

    这里还隐瞒着另外一个细节,即读请求和写请求。如果是读请求,那么重试无所谓;如果是写请求,我们的接口是否也支持自动重试呢 ? 这就会涉及到接口幂等性问题。

    如果写请求的接口,不支持幂等性,那么集群容错就得改为 failfast,即快速失败。

    3、分布式事务

    分布式事务在业界是一个没有彻底解决的技术难题。 没有通用的解决方案,也没有既高效又简便的手段。虽然如此,但我们也得事先考虑到这一点,不然数据肯定会变成脏乱差。在考虑解决方案之前,我们需要先看看自己的系统是不是真的追求强一致性;按照BASE理论,在分布式系统中,允许不同节点在同步的过程存在延时,但是经过一段时间的修复后,能够达到数据的最终一致性。

    基于这两个思路,我们才好制定自己的分布式事务方案。

    • 对于要求强一致性的场景,或许可以考虑XA协议,通过二阶段提交或者三阶段提交来保证。
    • 对于要求最终一致性的场景,可以考虑采用 TCC 模式,补偿模式,或者基于消息队列的模式。

    比如基于消息队列模式,可以采用 RocketMQ。它支持事务消息,那么这时候整个流程大概是这样的:

    • 通过 RocketMQ 发送事务消息到消息队列;
    • 消息发送成功,则执行本地事务;
    • 如果本地事务执行成功,则提交RocketMQ事务消息,提交后对消费者可见;
    • 如果本地事务执行失败,则删除RocketMQ事务消息,消费者不会看到这条消息。

    另外,在这里安利下阿里开源的Seata,它支持多种事务模式,比如 AT、TCC、SAGA 和 XA 事务模式。

    4、消息队列

    在分布式系统架构中,为了系统间的解耦和异步处理,应对高并发和大流量,消息队列绝对是一大利器。

    在使用这一利器前,我们也得考虑下有可能因为消息队列带来的烦恼。

    首先需要考虑的就是可用性,如果消息队列不可用,会不会对系统本身造成大量的不可用;

    然后,消息会不会丢失呢 ? 如何保证消息可靠性传输呢?比如要考虑消息队列本身的刷盘机制、同步机制;数据发送时的确认和消费后的提交;

    然后就是重复消费,如果保证了消息不会丢失,多多少少都可能会有重复消息的问题,这时候就要考虑重复消费有没有问题,即消息幂等性;

    还有,消息顺序性问题,你们的业务场景里,是否有消息顺序性问题,如果有这个问题,要么在设计时规避它,要么在消费时保证它的顺序。

    5、统一日志

    随着微服务的拆分,日志系统也可能会演变为独立的模块。为了查看日志,我们可能需要登录到不同的服务器去一个个查看。因此,搭建统一的日志处理平台是必然的。我们可以采用 ELK 的解决方案进行日志聚合。

    在这里,还需要链路追踪问题。在微服务复杂的链式调用中,会比单体应用更难以定位和追踪问题。对于这个问题,我们考虑引入分布式调用链,生成一个全局唯一的 TraceID ,通过它把整个调用链串联起来。结合Dubbo框架的话,我们实现自己的Filter,用来透传这个TraceID

    总结

    本文简单总结了微服务设计和开发过程中,可能会涉及到的一些问题。以上观点只是一家之言,仅仅是个人在过去时间里的经验总结。

  • 相关阅读:
    document.getElementById()使用方法
    Delphi XE7 发布时间
    JavaScript动态更改页面元素
    TCP/IP-协议族----17、应用层简单
    查看员工信息每个部门的最低工资
    VB6.0“挑衅”.NET!
    MapReduce计数器
    Linux学习记录--命名管道通信
    cocos2d-x V3.0 呼叫加速度计 Acceleration
    Linux Kernel(Android) 加密算法汇总(四)-应用程序调用OpenSSL加密演算法
  • 原文地址:https://www.cnblogs.com/johnvwan/p/15571361.html
Copyright © 2011-2022 走看看