当前位置: 首页 > news >正文

微服务的幂等性

  微服务架构设计的中心思想是将服务进行拆分,但是在这个过程中,如果被依赖的服务发生奔溃,就会引起一系列问题。为了解决这个问题,就会引入重试的机制,重试又会引入幂等性的问题,下面我们就分析这个过程,然后探讨一下常见的解决方案。

一、相关概念

1、雪崩

  • 定义
    服务雪崩效应是一种因“服务提供者的不可用”导致“服务调用者不可用”,并将不可用逐步放大的现象。如下图所示:
    在这里插入图片描述
    上图中,A为服务提供者,B为A的服务调用者,C和D是服务B的调用者。当A不可用,引起B的不可用,并将不可用逐渐放大到C和D,服务雪崩就形成了。
  • 形成原因:
    服务雪崩的过程可以分为三个阶段:
    • 1、服务提供者不可用
    • 2、重试加大请求流量
    • 3、服务调用者不可用
      服务雪崩的每个阶段都有可能由不同的原因造成,总结如下:
      在这里插入图片描述
  • 应对策略
    在这里插入图片描述
    在高并发项目中,如何提高并发量是主要的目标,当然也要考虑成本,如果为了解决可能会突然出现的高并发或者因为网络环境的问题,导致的被调用者反应很慢,这种情况如果还是加入很多的机器作为后备,就很不经济,在这个过程中,要防止服务雪崩,一般的情况就是给调用增加超时,如果超过一定的时间,就重试调用,这也可以提高用户体验,不至于因为一点网络问题,就给客户返回不可用。

2、超时和重试

  • 超时
    超时是为了保护服务,避免调用服务因为响应慢而也变得特别慢,这样调用服务就可以尽量保持原有的性能。
  • 重试
    如果被调用服务只是偶尔的抖动,那么超时后直接放弃,不做后续处理,就会导致当前服务请求错误,也会带来业务方面的损失。对于这种偶尔的抖动,可以在超时后重试一下,重试如果可以正常返回,那么这次请求就被拯救了,能够正常给前端返回数据。只不过要比原来的响应慢一点。在负载均衡中的重试也可以换一台机器进行调用,因为原来机器可能由于临时负载高而性能下降,重试会增加其想能问题,而换一台机器,得到更快返回的概率也会更大一点。

3、幂等性

  • 幂等性概念
    在编程中,一个幂等的操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数或者幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
    总的来说:迷瞪就是一个操作,不论执行多少次,产生的效果和返回的结果都是一样的
  • 满足restful的http请求类型的幂等性分析
    • get
      get请求是获取操作,只是查询,天生支持幂等性
    • post
      post请求用于新增数据,多次执行会产生多条数据,这种接口需要考虑幂等性
    • put
      put请求有两种情况,如果是简单的更改,比如将一个商品的数量数据改成一个确定的值,多次执行还是同样的值,只是消耗了计算机的性能,对最终的数据没有影响,这样的接口是满足幂等性的。
      但是如果是类似于累加修改这种操作,多次执行会产生不同的结果,就需要考虑幂等性。
      所以put请求要补考考虑幂等性,是需要具体问题具体分析的。
    • delete
      delete请求和put请求一样,如果是简单的删除操作(大多数情况),多次删除的结果一致,那就不需要考虑幂等性。如果不一致,还是要考虑幂等性的。

二、幂等性常见的解决方案

1、唯一索引,防止新增脏数据

比如:新建用户的时候,用手机号作为唯一索引,那么即使重试,也会只新建一个用户,不会因为多次重试导致当前用户被注册了很多次。

2、token机制,防止页面重复提交

在前端提交之前,生成一个token,在提交以后,可以判断该token是否已经进行了处理,这样可以防止数据的重复提交。token的特点:要申请,一次有效性,可以限流
注意:如果要用redis校验token,建议使用redis删除来判断token,删除成功代表token校验通过,如果采用select + delete来校验token,由于操作redis的次数多,存在并发问题,所以不建议使用。

3、悲观锁

获取数据时加锁,其他数据会被阻塞在这里,执行完成后再判断是否已经提交过,这样可以防止多次提交,但是性能不太好,数据锁定的时间可能会很长,根据实际情况选用。

4、乐观锁

根据数据库数据增加版本号的方式或者通过限制条件增加乐观锁,和悲观锁的原理一样,但是不会锁住表。

5、分布式锁

用redis等中间件做分布式锁,可以防止并发操作,如果已经存在这个数据,其他提交就可以不用再进行操作了。

6、select + insert

对于并发不太高的系统,可以采用先查询一下,如果存在,就不用再操作的方式,实现幂等性,但是并发高的核心系统不能这样做,因为没有加锁,insert操作可能会被多次执行。

7、对外提供的接口实现幂等性

如银联提供的付款接口,需要接入商户提交付款请求时附带source来源,seq序列号等,用source + seq在数据库中做唯一的索引,防止多次付款。

三、grpc实现超时和重试的调用

在grpc中,可以在调用时增加grpc.DialOption的方式,来实现超时重试的机制。
在用proto生成的接口中,调用的时候,可以增加grpc.CallOption的调用参数,我们可以在这里增加重试的功能:

type UserClient interface {GetUserList(ctx context.Context, in *PageInfo, opts ...grpc.CallOption) (*UserListResponse, error)GetUserByMobile(ctx context.Context, in *MobileRequest, opts ...grpc.CallOption) (*UserInfoResponse, error)GetUserById(ctx context.Context, in *IdRequest, opts ...grpc.CallOption) (*UserInfoResponse, error)CreateUser(ctx context.Context, in *CreateUserInfo, opts ...grpc.CallOption) (*UserInfoResponse, error)UpdateUser(ctx context.Context, in *UpdateUserInfo, opts ...grpc.CallOption) (*emptypb.Empty, error)CheckPassWord(ctx context.Context, in *PasswordCheckInfo, opts ...grpc.CallOption) (*CheckResponse, error)
}

在接口中给定的参数,只是对这个接口起作用,要想让所有的调用都起作用,我们可以在进行连接的时候,就指定grpc.DialOption,这样对这个连接中的接口,都会起作用。
Dial方法的声明如下:

func Dial(target string, opts ...DialOption) (*ClientConn, error) {return DialContext(context.Background(), target, opts...)
}

下面是我们在连接时指定重试的示例代码实现:

import ("context""fmt""time""google.golang.org/grpc/codes"grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry""google.golang.org/grpc""OldPackageTest/grpc_test/proto"
)func main() {// 增加一个耗时打印的interceptor interceptor := func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {start := time.Now()err := invoker(ctx, method, req, reply, cc, opts...)fmt.Printf("耗时:%s\n", time.Since(start))return err}var opts []grpc.DialOptionopts = append(opts, grpc.WithInsecure())retryOpts := []grpc_retry.CallOption{grpc_retry.WithMax(3),// 最大的重试次数grpc_retry.WithPerRetryTimeout(13 * time.Second),//超时时间grpc_retry.WithCodes(codes.Unknown, codes.DeadlineExceeded, codes.Unavailable),// 对于哪些返回状态进行重试}opts = append(opts, grpc.WithUnaryInterceptor(interceptor))//这个请求应该多长时间超时, 这个重试应该几次、当服务器返回什么状态码的时候重试opts = append(opts, grpc.WithUnaryInterceptor(grpc_retry.UnaryClientInterceptor(retryOpts...)))conn, err := grpc.Dial("127.0.0.1:50051", opts...)if err != nil {panic(err)}defer conn.Close()c := proto.NewGreeterClient(conn)r, err := c.SayHello(context.Background(), &proto.HelloRequest{Name: "bobby"})if err != nil {panic(err)}fmt.Println(r.Message)
}

后记
  个人总结,欢迎转载、评论、批评指正

相关文章:

微服务的幂等性

微服务架构设计的中心思想是将服务进行拆分,但是在这个过程中,如果被依赖的服务发生奔溃,就会引起一系列问题。为了解决这个问题,就会引入重试的机制,重试又会引入幂等性的问题,下面我们就分析这个过程&…...

Redis之基础篇

Redis简介 Redis是一种基于键值对(Key-Value)的NoSQL数据库,它支持string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集…...

靶机实战bwapp亲测xxe漏洞攻击及自动化XXE注射工具分析利用

靶机实战bwapp亲测xxe漏洞攻击及自动化XXE注射工具分析利用。 1|0介绍 xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤,从而可以造成命令执行,目录遍历等.首先存在漏洞的web服务一定是存在xml传输数据的,可以在http头的content-type中查…...

openGauss学习笔记-216 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-CPU

文章目录 openGauss学习笔记-216 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-CPU216.1 CPU216.2 查看CPU状况216.3 性能参数分析 openGauss学习笔记-216 openGauss性能调优-确定性能调优范围-硬件瓶颈点分析-CPU 获取openGauss节点的CPU、内存、I/O和网络资源使用情况…...

【教程】Linux使用git自动备份和使用支持文件恢复的rm命令

转载请注明出处:小锋学长生活大爆炸[xfxuezhang.cn] 背景介绍 首先非常不幸地告诉你:Linux 系统的标准 rm 命令不支持文件恢复功能。一旦使用 rm 删除了文件或目录,它们就会从文件系统中永久删除,除非你使用专门的文件恢复工具尝试…...

记录使用M1 Mac开发LVGL嵌入式项目

技术流 使用Gui Guider进行UI设计,生成lvgl code将lvgl code移植到esp32s3开发板 Gui Guider的安装 安装下面流程一步一步进行 LVGL的移植 硬件:esp32-8048s043开发板 开发环境:PlatformIO M1芯片安装ESP32驱动 从https://www.wch.cn…...

【SpringBoot】JWT令牌

📝个人主页:五敷有你 🔥系列专栏:SpringBoot ⛺️稳重求进,晒太阳 什么是JWT JWT简称JSON Web Token,也就是通过JSON形式作为Web应用的令牌,用于各方面之间安全的将信息作为JSON对象传输…...

Python爬虫 Beautiful Soup库详解#4

爬虫专栏:http://t.csdnimg.cn/WfCSx 使用 Beautiful Soup 前面介绍了正则表达式的相关用法,但是一旦正则表达式写的有问题,得到的可能就不是我们想要的结果了。而且对于一个网页来说,都有一定的特殊结构和层级关系,…...

Tkinter教程21:Listbox列表框+OptionMenu选项菜单+Combobox下拉列表框控件的使用+绑定事件

------------★Tkinter系列教程★------------ Tkinter教程21:Listbox列表框OptionMenu选项菜单Combobox下拉列表框控件的使用绑定事件 Tkinter教程20:treeview树视图组件,表格数据的插入与表头排序 Python教程57:tkinter中如何…...

Django中的SQL注入攻击防御策略

Django中的SQL注入攻击防御策略 SQL注入是一种常见的网络安全威胁,可以导致数据库被非法访问和数据泄露。本文将介绍在Django框架中防止SQL注入攻击的关键方法,包括使用参数化查询、使用ORM、进行输入验证和使用安全的编码实践。 SQL注入是一种利用应用程…...

ORM模型类

模型 创建两个表 创建模型类 from django.db import models# Create your models here. class BookInfo(models.Model):name models.CharField(max_length10, uniqueTrue) # 书名pub_date models.DateField(nullTrue) # 发布时间read_count models.IntegerField(default…...

Java强训day14(选择题编程题)

选择题 编程题 题目1 import java.util.Scanner;public class Main {public static void main(String[] args) {//读入年月日(字符串形式读入)Scanner sc new Scanner(System.in);String s sc.nextLine();String[] ss s.split(" ");i…...

Redis核心技术与实战【学习笔记】 - 31.番外篇:Redis客户端如何与服务器端交换命令和数据

简述 Redis 使用 RESP 协议(Redis Serialzation Protocol)协议定义了客户端和服务器端交互的命令、数据的编码格式。在 Redis 2.0 版本中,RESP 协议正式称为客户端和服务器端的标准通信协议。从 Redis 2.0 到 Redis 5.0 ,RESP 协…...

电缆线的阻抗50Ω,真正含义是什么?

当我们提到电缆线的阻抗时,它到底是什么意思?RG58电缆通常指的是50Ω的电缆线。它的真正含义是什么?假如取一段3英尺(0.9144米)长的RG58电缆线,并且在前端测量信号路径与返回路径之间的阻抗。那么测得的阻抗是多少?当然…...

校园团餐SAAS系统源码

## 项目介绍 校园团餐SAAS系统,是全新推出的一款轻量级、高性能、前后端分离的团餐系统,支持微信小程序 。 技术特点 > * 前后端完全分离 (互不依赖 开发效率高) > * 采用PHP8 (强类型严格模式) > * ThinkPHP8.0(轻量级PHP开发框…...

图数据库neo4j入门

neo4j 一、安装二、简单操作<一>、创建<二>、查询<三>、关系<四>、修改<五>、删除 三、常见报错<一>、默认的数据库密码是neo4j,打开浏览器http://localhost:7474登录不上,报错: Neo.ClientError.Security.Unauthorized: The client is un…...

Multisim14.0仿真(五十五)汽车转向灯设计

一、功能描述&#xff1a; 左转向&#xff1a;左侧指示灯循环依次闪亮&#xff1b; 右转向&#xff1a;右侧指示灯循环依次闪亮&#xff1b; 刹车&#xff1a; 所有灯常亮&#xff1b; 正常&#xff1a; 所有灯熄灭。 二、主要芯片&#xff1a; 74LS161D 74LS04D 74…...

2402C++,C++的反向代理

原文 cinatra支持反向代理很简单,5行代码就可以了.先看一个简单的示例: #include "cinatra/coro_http_reverse_proxy.hpp" using namespace cinatra; int main() {reverse_proxy proxy_rr(10, 8091);proxy_rr.add_dest_host("127.0.0.1:9001");proxy_rr.a…...

[职场] 服务行业个人简历 #笔记#笔记

服务行业个人简历 服务员个人简历范文1 姓名: XXX国籍:中国 目前所在地:天河区民族:汉族 户口所在地:阳江身材: 160cm43kg 婚姻状况:未婚年龄: 21岁 培训认证:诚信徽章: 求职意向及工作经历 人才类型:普通求职 应聘职位: 工作年限:职称:初级 求职类型:全职可到职日期:随时 月薪…...

代码随想录算法训练营|day30

第七章 回溯算法 332.重新安排行程51.N皇后37.解数独代码随想录文章详解 332.重新安排行程 (1)参考 创建map存储src&#xff0c;[]dest映射关系&#xff0c;并对[]dest排序 每次取map中第一个dest访问&#xff0c;将其作为新的src&#xff0c;每访问一条src->dest&#xff…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

华硕a豆14 Air香氛版,美学与科技的馨香融合

在快节奏的现代生活中&#xff0c;我们渴望一个能激发创想、愉悦感官的工作与生活伙伴&#xff0c;它不仅是冰冷的科技工具&#xff0c;更能触动我们内心深处的细腻情感。正是在这样的期许下&#xff0c;华硕a豆14 Air香氛版翩然而至&#xff0c;它以一种前所未有的方式&#x…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》

&#x1f9e0; LangChain 中 TextSplitter 的使用详解&#xff1a;从基础到进阶&#xff08;附代码&#xff09; 一、前言 在处理大规模文本数据时&#xff0c;特别是在构建知识库或进行大模型训练与推理时&#xff0c;文本切分&#xff08;Text Splitting&#xff09; 是一个…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...

从实验室到产业:IndexTTS 在六大核心场景的落地实践

一、内容创作&#xff1a;重构数字内容生产范式 在短视频创作领域&#xff0c;IndexTTS 的语音克隆技术彻底改变了配音流程。B 站 UP 主通过 5 秒参考音频即可克隆出郭老师音色&#xff0c;生成的 “各位吴彦祖们大家好” 语音相似度达 97%&#xff0c;单条视频播放量突破百万…...

前端工具库lodash与lodash-es区别详解

lodash 和 lodash-es 是同一工具库的两个不同版本&#xff0c;核心功能完全一致&#xff0c;主要区别在于模块化格式和优化方式&#xff0c;适合不同的开发环境。以下是详细对比&#xff1a; 1. 模块化格式 lodash 使用 CommonJS 模块格式&#xff08;require/module.exports&a…...

深入理解 React 样式方案

React 的样式方案较多,在应用开发初期,开发者需要根据项目业务具体情况选择对应样式方案。React 样式方案主要有: 1. 内联样式 2. module css 3. css in js 4. tailwind css 这些方案中,均有各自的优势和缺点。 1. 方案优劣势 1. 内联样式: 简单直观,适合动态样式和…...