微服务的幂等性

news2024/11/14 13:58:57

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

一、相关概念

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.DialOption
	opts = 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)
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1431575.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试150 颠倒二进制位 位运算分治 逻辑右移

Problem: 190. 颠倒二进制位 文章目录 思路复杂度位运算分治法 思路 👨‍🏫 参考题解 >>>:逻辑右移(符号位一起移动,高位补零) 复杂度 时间复杂度: O ( log ⁡ n ) O(\log{n}) O(logn) 空间…

Quartus IP学习之ISSP(In-System Sources Probes)

一、ISSP IP概要: ISSP:In-System Sources & Probes Intel FPGA IP 作用: 分为In-System Sources与In-System Probesn-System Sources,输入端,等价于拨码开关,通过输入板载FPGA上的拨码开关状态改变…

如何结合ChatGPT生成个人魔法咒语词库

3.6.1 ChatGPT辅助力AI绘画 3.6.1.1 给定主题让ChatGPT直接描述 上面给了一个简易主题演示一下,这是完全我没有细化的提问,然后把直接把这些关键词组合在一起。 关键词: 黄山的美景,生机勃勃,湛蓝天空,青…

鲜花销售|鲜花销售小程序|基于微信小程序的鲜花销售系统设计与实现(源码+数据库+文档)

鲜花销售小程序目录 目录 基于微信小程序的鲜花销售系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、前台功能模块 2、后台功能模块 (1) 后台登录 (2) 管理员功能模块 用户管理 商家管理 鲜花信息管理 鲜花分类管理 管理员管理 系统管理 (3) 商家功…

SerDes PoC 电感网络工作原理详解

如下图所示,PoC的工作原理可以描述如下: 1. 直流状态时,电感处于短路状态,电容处于开路状态,因此,接收端的电源能够通过电感注入到信号传输系统中,并在另一端通过电感为本地电路供电,而不会透过电容影响到两端的高速收发器; 2. 交流状态时,即高频信号注入时,电容器是…

华为机考入门python3--(5)牛客5-进制转换

分类:数字 知识点: 十六进制转int num int(hex_num, 16) int转十六进制 hex_num hex(num) 题目来自【牛客】 hex_num input().strip() dec_num int(hex_num, 16) print(dec_num) by 软件工程小施同学

【OpenCV学习笔记28】- OpenCV 中的直方图 - 直方图 - 2:直方图均衡

这是对于 OpenCV 官方文档中 图像处理 的学习笔记。学习笔记中会记录官方给出的例子,也会给出自己根据官方的例子完成的更改代码,同样彩蛋的实现也会结合多个知识点一起实现一些小功能,来帮助我们对学会的知识点进行结合应用。 如果有喜欢我笔…

【Java并发】聊聊Disruptor背后高性能的原理

为什么需要Disruptor 对于单机生产者消费者来说,JUC本身提供了阻塞队列,ArrayBlockingQueue、LinkedBlockingQueue 等,但是为了保证数据安全,使用了reentrantLock进行加锁操作会影响性能,另一方面,本身如果…

Kafka相关内容复习

为什么要用消息队列 解耦 允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。 可恢复性 系统的一部分组件失效时,不会影响到整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队…

XCTF:3-1[WriteUP]

从题目中获取文件 使用file命令查看文件类型 修改后缀为.rar后进行解压缩 再次使用file命令查询该文件的类型 再次修改后缀为.pcap或者.pcapng 使用wireshark打开,直接搜索flag字样 在多个数据包里发现了flag.rar、flag.txt等文件 尝试使用http导出文件 有一个fl…

小程序<scroll-view/>组件详解及使用指南

目录 引言小程序的流行和重要性scroll-view 组件在小程序中的作用和优势什么是 scroll-view 组件scroll-view 组件的基本概念scroll-view 组件的基本功能scroll-view 组件的属性与用法scroll-view 组件的常用属性参考代码scroll-view 组件的滚动事件scrolltoupper

【开源】SpringBoot框架开发大学计算机课程管理平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 实验课程档案模块2.2 实验资源模块2.3 学生实验模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 实验课程档案表3.2.2 实验资源表3.2.3 学生实验表 四、系统展示五、核心代码5.1 一键生成实验5.2 提交实验5.3 批阅实…

ESU毅速丨为什么增材制造广受关注?

随着科技的飞速发展,增材制造3D打印技术逐渐成为制造业的新宠。包括航空航天、汽车、家电、电子等各行业都在积极拥抱3D打印,为什么3D打印能引起制造业广泛关注与应用?它的主要优势有哪些? 首先,3D打印减少浪费。3D打印…

私有化部署的局域网即时通讯工具

在当今快节奏的企业环境中,高效的内部通信成为提高团队协作和工作效率的关键。而企业内部通信软件作为实现实时协作和快速沟通的利器,WorkPlus以其领先的功能和卓越的性能,助力企业打造高效团队沟通协作的新时代。 为何选择WorkPlus作为企业内…

简单说说-docker网络类型

概述 容器网络是指容器之间或非 Docker 工作负载之间连接和通信的能力。容器默认启用网络,并且可以建立传出连接。容器不知道它所连接的网络类型,容器只能看到带有 IP 地址、网关、路由表、DNS 服务和其他网络详细信息的网络接口。也就是说,…

【Docker与微服务】基础篇

1 Docker简介 1.1 docker是什么 1.1.1 问题:为什么会有docker出现? 假定您在开发一个项目,您使用的是一台笔记本电脑而且您的开发环境具有特定的配置。其他开发人员身处的环境配置也各有不同。您正在开发的应用依赖于您当前的配置且还要依…

ElementUI Data:Table 表格

ElementUI安装与使用指南 Table 表格 点击下载learnelementuispringboot项目源码 效果图 el-table.vue&#xff08;Table表格&#xff09;页面效果图 项目里el-table.vue代码 <script> export default {name: el_table,data() {return {tableData: …

基于微信小程序的医保行政执法案件管理系统

本系统设计的是一个医保行政执法的网站&#xff0c;此网站使用户实现了不需出门就可以在手机或电脑前进行网上查询需求信息等。 用户在注册登陆后&#xff0c;在客户端可以实现&#xff1b;案件信息、结案归档、我的等。然而管理员则可以在服务端直接管理&#xff1b;个人中心、…

学成在线:采用XXL-JOB任务调度方案使用FFmpeg处理视频转码业务

分片技术方案 概述 XXL-JOB并不直接提供数据处理的功能&#xff0c;它只会给所有注册的执行器分配好分片序号&#xff0c;在向执行器下发任务调度的同时携带分片总数和当前分片序号等参数 设计作业分片方案保证多个执行器之间不会查询到重复的任务,保证任务不会重复执行 任…

如何标准化地快速编辑文档

介绍个公文类的文档技巧吧&#xff0c;尤其在国企、机关、有ISO管理体系内控要求的会议记录、公文写作等&#xff0c;要求大同小异&#xff0c;一般都是中规中矩的【GB/T 9704—2012】&#xff0c;其实国标本身就是经过长期检验&#xff0c;证明是最规范合理&#xff0c;阅读效…