微服务架构及幂等性

微服务架构

微服务架构是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦。它的主要作用是将功能分解到离散的各个服务当中,从而降低系统的耦合性,并提供更加灵活的服务支持。

微服务 相对应的,这种方式一般被称为 单体式开发(Monolithic)。既所有的功能打包在一个 WAR 包里,基本没有外部依赖(除了容器),部署在一个 JavaEE 容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI 等所有逻辑。

单体应用的优缺点:

优点:

  • 开发简单,集中式管理
  • 基本不会重复开发
  • 功能都在本地,没有分布式的管理和调用消耗

缺点:

  • 效率低:开发都在同一个项目改代码,相互等待,冲突不断
  • 维护难:代码功能耦合在一起,新人不知道何从下手
  • 不灵活:构建时间长,任何小修改都要重构整个项目,耗时
  • 稳定性差:一个微小的问题,都可能导致整个应用挂掉
  • 扩展性不够:无法满足高并发下的业务需

微服务的优缺点:

优点:

  • 它解决了复杂问题。它把可能会变得庞大的单体应用程序分解成一套服务
  • 这种架构使得每个服务都可以由一个团队独立专注开发
  • 微服务架构模式可以实现每个微服务独立部署
  • 微服务架构模式使得每个服务能够独立扩展

缺点(挑战):

  • 微服务是一个分布式系统,其使得整体变得复杂。开发人员需要基于RPC或者消息实现微服务之间的调用和通信,而这就使得服务之间的发现、服务调用链的跟踪和质量问题变得的相当棘手。
  • 分区的数据库体系和分布式事务。更新多个业务实体的业务交易相当普遍。这些类型的事务在单体应用中实现非常简单,因为单体应用往往只存在一个数据库。但在微服务架构下,不同服务可能拥有不同的数据库。CAP原理的约束,使得我们不得不放弃传统的强一致性,而转而追求最终一致性,这个对开发人员来说是一个挑战。
  • 跨越多服务变更。在单体应用程序中,您可以简单地修改相应的模块、整合变更并一次性部署他们。相反,在微服务中您需要仔细规划和协调出现的变更至每个服务。
  • 部署基于微服务的应用程序也是相当复杂的
  • 测试

以上问题和挑战可大体概括为:

  • API Gateway
  • 服务间调用
  • 服务发现
  • 服务容错
  • 服务部署
  • 数据调用

目前流行的两种微服务框架解决方案(可以解决以上问题)

  • SpringBoot + SpringCloud

    • SpringBoot是 Spring 的一套快速配置框架,可以基于spring boot 快速开发单个微服务
    • Spring Cloud基于Spring Boot,为微服务体系开发中的架构问题提供了一整套的解决方案——服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等路由网关
  • Dubbo + ZooKeeper
    • Dubbo是一个阿里巴巴开源出来的一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
    • ZooKeeper用来实现服务的注册与发现和进行负载均衡

基于微服务架构的应用是分布式系统,增加了系统设计和实现的难度,主要有以下方面:

  • 运行环境中,微服务实例的网络地址是动态分配的,微服务运行的实例是动态变化的,需要一套发现机制,使服务调用者可以获取正确的服务地址。
  • 服务之间存在着复杂的依赖关系,在高并发访问下,依赖的稳定性影响系统的可用性及性能,因此需要提供容错机制,当依赖的服务发生故障时,不会使调用方线程被长时间占用不释放,避免故障在系统中蔓延。
  • 需要一个高效的进程间通信机制支持微服务之间的交互
  • 服务实例的启停及流量的调度和分配需要一套负载监控和负载均衡组件来管理。

微服务架构的基本组件

  • 可持续交付的平台
  • 服务注册与发现组件(ZooKeeper)
  • 服务网关

一般微服务在系统内部,通常是无状态的,用户登入信息和权限管理最好有一个统一的地方维护管理(OAuth)。(类似SSO单点登入)

API网关 + 服务间通信

  • 一般在后台 N 个服务和 UI 之间一般会一个代理或者叫 API Gateway

    • 提供统一服务入口,让微服务对前台透明
    • 聚合后台的服务,节省流量,提升性能(PC、Android/IOS端只需记住API网关的IP,API网关会有一个后台服务IP列表)
    • 提供安全,过滤,流控等API管理功能
    • 其实这个 API Gateway 可以有很多广义的实现办法,可以是一个软硬一体的盒子,也可以是一个简单的 MVC 框架,甚至是一个 Node.js 的服务端

所有的微服务都是独立的 Java 进程跑在独立的虚拟机上,所以服务间的通信就是 IPC(Inter Process Communication),已经有很多成熟的方案。现在基本最通用的有两种方式

服务间通信

同步调用(阻塞)

服务间通信:网络中只有字符串可以穿透防火墙

  • REST(JAX-RS,Spring Boot):Http通信
REST
    api
     String json = /users/list;
     USer user = new USer();
     user.setId(json.getId());
  • RPC(Thrift, Dubbo):远程过程调用 User user = new RPCUser();

同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。一般 REST 基于 HTTP,更容易实现,更容易被接受,服务端实现技术也更灵活些,各个语言都能支持,同时能跨客户端,对客户端没有特殊的要求,只要封装了 HTTP 的 SDK 就能调用,所以相对使用的广一些。RPC 也有自己的优点,传输协议更高效,安全更可控,特别在一个公司内部,如果有统一个的开发规范和统一的服务框架时,他的开发效率优势更明显些。就看各自的技术积累实际条件,自己的选择了。
(对外REST,对内RPC)

异步消息调用
  • Kafka
  • Notify
  • MessageQueue

异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据 最终一致性;还有就是后台服务一般要实现 幂等性,因为消息送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验);最后就是必须引入一个独立的 Broker(消息队列的中间服务器)

服务发现

在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互感知?服务如何管理?

这就是服务发现的问题了。一般有两类做法,也各有优缺点。基本都是通过 Zookeeper 等类似技术做服务注册信息的分布式管理。当服务上线时,服务提供者将自己的服务信息注册到 ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过 ZK 寻址,根据可定制算法,找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK 会发通知给服务客户端。

ZooKeeper实现了分布式锁,解决单点故障问题

服务注册

Dubbo是一个RPC通信框架;ZooKeeper服务注册与发现。此处两者结合使用。

  • 基于客户端的服务注册与发现

优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支持,比如 Dubbo。
此处调用可以是Dubbo,服务注册为ZooKeeper

  • 基于服务端的服务注册与发现

优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多。

LB为负载均衡服务器,由LB去查询注册中心,再去调用对应指定的服务

微服务需要考虑的问题:

  • API Gateway
  • 服务间调用
  • 服务发现
  • 服务容错
  • 服务部署
  • 数据调用

微服务幂等性

分布式系统中的幂等性概念:用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。

幂等场景:

可能会发生重复请求或消费的场景,在微服务架构中是随处可见的。

  • 网络波动:因网络波动,可能会引起重复请求
  • 分布式消息消费:任务发布后,使用分布式消息服务来进行消费
  • 用户重复操作:用户在使用产品时,可能无意地触发多笔交易,甚至没有响应而有意触发多笔交易
  • 未关闭的重试机制:因开发人员、测试人员或运维人员没有检查出来,而开启的重试机制(如Nginx重试、RPC通信重试或业务层重试等)

CRUD操作分析

  • 新增类请求:不具备幂等性
  • 查询类动作:重复查询不会产生或变更新的数据,查询具有天然幂等性
  • 更新类请求:
    • 基于主键的计算式Update,不具备幂等性,即UPDATE goods SET number=number-1 WHERE id=1
    • 基于主键的非计算式Update:具备幂等性,即UPDATE goods SET number=newNumber WHERE id=1
    • 基于条件查询的更新,不一定具备幂等性(需要根据实际情况进行分析判断)
  • 删除类请求:
    • 基于主键的Delete具备幂等性
    • 一般业务层面都是逻辑删除(即update操作),而基于主键的逻辑删除操作也是具有幂等性的

幂等性的重要性

针对一个微服务架构,如果不支持幂等操作,那将会出现以下情况:

  • 电商超卖现象
  • 重复转账、扣款或付款
  • 重复增加金币、积分或优惠券

超卖现象
? 比如某商品的库存为1,此时用户1和用户2并发购买该商品,用户1提交订单后该商品的库存被修改为0,而此时用户2并不知道的情况下提交订单,该商品的库存再次被修改为-1这就是超卖现象。

? 究其深层原因,是因为数据库底层的写操作和读操作可以同时进行,虽然写操作默认带有隐式锁(即对同一数据不能同时进行写操作)但是读操作默认是不带锁的,所以当用户1去修改库存的时候,用户2依然可以都到库存为1,所以出现了超卖现象。

? 解决方案A:可以对读操作加上显式锁(即在select …语句最后加上for update)这样一来用户1在进行读操作时用户2就需要排队等待了。但问题来了,如果该商品很热门并发量很高那么效率就会大大的下降,如何解决呢?(解决方案B)

? 解决方案B:我们可以有条件有选择的在读操作上加锁,比如可以对库存做一个判断,当库存小于一个量时开始加锁,让购买者排队,这样一来就解决了超卖现象。

解决方案

  • 全局唯一ID

如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局ID,存储到存储系统中,比如数据库、Redis等。如果存在则表示该方法已经执行。

使用全局唯一ID是一个通用方案,可以支持插入、更新、删除业务操作。但是这个方案看起来很美但是实现起来比较麻烦,下面的方案适用于特定的场景,但是实现起来比较简单。

  • 去重表

这种方法适用于在业务中有唯一标识的插入场景中,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据写入去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。

  • 插入或更新

这种方法插入并且有唯一索引的情况,比如我们要关联商品品类,其中商品的ID和品类的ID可以构成唯一索引,并且在数据表中也增加了唯一索引。这时就可以使用InsertOrUpdate操作。

  • 多版本控制

这种方法适合在更新的场景中,比如我们要更新商品的名字,这时我们就可以在更新的接口中增加一个版本号,来做幂等:boolean updateGoodsName(int id,String newName,int version);

在实现时可以如下:update goods set name=#{newName},version=#{version} where id=#{id} and version<${version}

  • 状态机控制

这种方法适合在有状态机流转的情况下,比如就会订单的创建和付款,订单的付款肯定是在之前,这时我们可以通过在设计状态字段时,使用int类型,并且通过值类型的大小来做幂等,比如订单的创建为0,付款成功为100,付款失败为99。在做状态机更新时,我们就这可以这样控制:update goods_order set status=#{status} where id=#{id} and status<#{status}

以上就是保证接口幂等性的一些方法。

总结

幂等性设计不能脱离业务来讨论,一般情况下,去重表同时也是业务数据表,而针对分布式的去重ID,可以参考以下几种方式:

  • UUID
  • Snowflake
  • 数据库自增ID
  • 业务本身的唯一约束
  • 业务字段+时间戳拼接

原文地址:https://www.cnblogs.com/dear_diary/p/10328161.html

时间: 2024-10-08 02:31:35

微服务架构及幂等性的相关文章

微服务架构之幂等性问题及设计思想,你不得不知的一些幂等方案

前言 小伙伴们有没有遇到过生产环境经常出现过重复的数据?在排查问题的时候,数据又是正常的.这个是何解呢?怎么会出现这种情况,而且还很难排查问题.今天我给大家分享一下这里的原因,以及解决方案. 大家觉得还不错的可以关注我的主页[点击进入],每天都会更新一下技术干货.电子书.架构资料等免费领取! 罪魁祸首 产生重复数据或数据不一致(假定程序业务代码没问题),绝大部分就是发生了重复的请求,重复请求是指同一个请求因为某些原因被多次提交.导致这个情况会有几种场景: 1)微服务场景,在我们传统应用架构中调用

分布式系统(微服务架构)的一致性和幂等性问题相关概念解析

目录 前言 1. 分布式系统的数据一致性 1.1 分布式存储系统中的一致性问题 1.2 微服务应用的分布式一致性问题 1.3 对于一致性的正确理解 2.分布式一致性模型 3. 追求强一致性的约束--CAP定理 3.1 如何理解CAP三要素不可兼得 3.2 如何正确理解CAP定理 4. 一致性的妥协--最终一致性和Base原则 4.1 CAP,BASE以及ACID的关系 5. 分布式系统的幂等性 6.微服务架构的分布式一致性和幂等性问题 6.1 微服务架构下的分布式一致性问题 6.2 微服务架构下

微服务架构(Microservice Architecture)

之前一段时间,有听部门架构说起接下来公司要使用微服务架构来研发系统,当时没怎么在意,因为是第一次听说微服务这个名词(果然无知者无畏啊):正好赶上五一假, 我自告奋勇的,接了编写微服务架构培训文档这个任务(也许因为我是文科生,文笔稍微好点).五一假期三天,基本都是在看资料,梳理思路以及编写接下来的培训文档中度过. 下面,就说说我这几天的一些收获吧:先说说资料来源吧:有架构给我的一些资料,以及自己百度和论坛.社区找来的一些资料,权当做一个总结式的简介... 目录如下: 一.微服务架构介绍 二.出现和

微服务架构下的数据一致性:可靠事件模式

主页:http://www.howardliu.cn/ 博客:微服务架构下的数据一致性:可靠事件模式 在<微服务架构下的数据一致性:概念及相关模式>中介绍了在微服务中实现数据一致性的三种方式,包括可靠事件模式.业务补偿模式.TCC模式.本文重点说一下可靠事件投递. 1. 可靠事件模式 可靠事件模式属于事件驱动架构,微服务完成操作后向消息代理发布事件,关联的微服务从消息代理订阅到该事件从而完成相应的业务操作,关键在于可靠事件投递和避免事件重复消费. 可靠事件投递有两个特性:1)每个服务原子性的完

微服务架构设计

微服务 软件架构是一个包含各种组织的系统组织,这些组件包括 Web服务器, 应用服务器, 数据库,存储, 通讯层), 它们彼此或和环境存在关系.系统架构的目标是解决利益相关者的关注点. Conway’s law: Organizations which design systems[...] are constrained to produce designs which are copies of the communication structures of these organizati

Re:从 0 开始的微服务架构--(四)如何保障微服务架构下的数据一致性--转

原文地址:http://mp.weixin.qq.com/s/eXvoJew3bjFKzLLJpS0Otg 随着微服务架构的推广,越来越多的公司采用微服务架构来构建自己的业务平台.就像前边的文章说的,微服务架构为业务开发带来了诸多好处的同时,例如单一职责.独立开发部署.功能复用和系统容错等等,也带来一些问题. 例如上手难度变大,运维变得更复杂,模块之间的依赖关系更复杂,数据一致性难以保证,等等.但是办法总是比问题多,本篇文章就来介绍一下我们是如何保障微服务架构的数据一致性的. 微服务架构的数据一

微服务架构与实践及云原生等相关概念

微服务架构与实践 笔记:<微服务架构与实践> 王磊 著 一 单块架构 1 定义:对于这种功能集中.代码和数据中心化.一个发布包.部署后运行在同一进程的应用程序,我们通常称之为单块架构应用,并非物理上的分层. 2 单层架构:数据 逻辑 页面 混合 3 三层架构: 1)表示层:数据显示和用户交互 2)业务逻辑层:业务逻辑处理 3)数据访问层:数据存储访问 4 优势: 比较适合小项目 易于开发:开发简单直接,集中式管理,基本不会重复开发,集成工具适合 易于测试:单进程 易于部署:单项目包,功能都在本

java微服务架构的分布式事务解决方案

java微服务架构的分布式事务解决方案 课程目录如下: 1.课程介绍20分钟2.解决方案的效果演示(结合支付系统真实应用场景)45分钟3.常用的分布式事务解决方案介绍47分钟4.消息发送一致性(可靠消息的前提保障)20分钟5.消息发送一致性的异常流程处理16分钟6.常规MQ队列消息的处理流程和特点12分钟7.消息重复发送问题及业务接口的幂等性设计18分钟8.可靠消息最终一致性方案1(本地消息服务)的设计19分钟9.可靠消息最终一致性方案2(独立消息服务)的设计24分钟10.可靠消息服务的设计与实

微服务架构下的数据一致性:概念及相关模式

主页:http://www.howardliu.cn/ 博客:微服务架构下的数据一致性:概念及相关模式 从2014年开始,微服务逐渐进入大家的实现,被认为是下一代实现信息化的有效手段.设计到系统,其中绕不开的就是数据一致性,从本地事务,到后来的分布式事务,都能够有效的保证数据一致性.但是在微服务架构中,这两种方式都不是最好的选择. 1. 使用本地事务和分布式事务保证一致性 在传统的单击应用中,最简单.最直接.最普遍的会使用一个关系型数据库,通过关系型数据库的事务保证数据的一致性.这种事务有四个基