微服务的幂等性

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

一、相关概念

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)
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电磁兼容(EMC):传导骚扰差模频段超标机理及解决方案

目录 1 家用电器传导发射限值要求 2 传导测量等效电路 3 传导测试数据差、共模干扰分段 4 差模干扰源分析及解决方案 电子产品需要满足电磁兼容EMC要求,EMC包括抗扰度试验(EMS)和辐射类试验(EMI),发射类…

如何编写接口测试用例

作为测试人,我们经常要对项目中的接口进行接口测试,那么在做接口测试的时候,如何写接口测试用例呢? 什么是接口测试 首先我们要了解一下,什么是接口测试? 那么首先要搞清楚,我们一般说的接口…

<设计模式>单例模式懒汉和饿汉

目录 一、单例模式概述 二、懒汉模式和饿汉模式 1.饿汉模式 1.1代码实现 1.2实现细节 1.3模式优劣 2.懒汉模式 2.1代码实现 2.2实现细节 2.3模式优劣 三、多线程下的线程安全问题 1.懒汉和饿汉线程安全问题分析 1.1安全的饿汉模式 1.2不安全的懒汉模式 2.懒汉线程…

Jenkins(三):自动化部署SpringBoot项目

前言 在软件开发过程中,自动化部署已经成为不可或缺的一环。Jenkins是一个广泛使用的开源自动化部署工具,它提供了强大的功能和灵活的配置选项,可以帮助开发团队实现高效的持续集成和持续部署。本文将详细介绍如何使用Jenkins自动化部署Spri…

爬取58二手房并用SVR模型拟合

目录 一、前言 二、爬虫与数据处理 三、模型 一、前言 爬取数据仅用于练习和学习。本文运用二手房规格sepc(如3室2厅1卫)和二手房面积area预测二手房价格price,只是练习和学习,不代表如何实际意义。 二、爬虫与数据处理 import requests import cha…

EasyX图形库学习(二、文字输出)

目录 一、文字绘制函数 字体属性结构体:logfont 文字输出 outtextxy 在指定位置输出字符串。 ​编辑 但如果直接使用,可能有以下报错: 三种解决方案: 将一个int类型的分数,输出到图形界面上 如果直接使用: 会把score输入进去根据A…

【Vue.js设计与实现】第二篇:响应系统-阅读笔记(持续更新)

从高层设计的角度去探讨框架需要关注的问题。 系列目录: 标题博客第一篇:框架设计概览【Vue.js设计与实现】第一篇:框架设计概览-阅读笔记第二篇:响应系统【Vue.js设计与实现】第二篇:响应系统-阅读笔记第三篇&#x…

洗地机哪个品牌质量好?盘点当下最值得买的4款洗地机型号推荐

随着生活节奏的加快,人们对于家庭清洁的需求也越来越迫切。而洗地机作为家庭清洁利器备受青睐,但洗地机也分为很多款式,每一个款式都具备不同的清洁效果,可以节省不少时间。接下来,就由笔者为大家详细介绍一下洗地机哪…

如何去除图片水印?三个简单实用方法

随着数字时代的来临,我们每天都会接触到大量的图片,然而,许多图片却因为水印而影响了美观。为了解决这个问题,我们需要图片去水印的方法。今天,我们就来为大家介绍几个简单实用的方法,可以轻松去除水印&…

备战蓝桥杯---搜索(优化1)

显然&#xff0c;我们可以用BFS解决&#xff0c;具体实现与八数码类似&#xff1a; 下面是代码&#xff1a; #include<bits/stdc.h> using namespace std; #define N 3000000 string a,b; int hh,dis[N],cnt; struct node{string u,v; }bian[7]; map<string,int>…

Flutter 和 Android原生(Activity、Fragment)相互跳转、传参

前言 本文主要讲解 Flutter 和 Android原生之间&#xff0c;页面相互跳转、传参&#xff0c; 但其中用到了两端相互通信的知识&#xff0c;非常建议先看完这篇 讲解通信的文章&#xff1a; Flutter 与 Android原生 相互通信&#xff1a;BasicMessageChannel、MethodChannel、…

MongoDB复制集实战及原理分析

文章目录 MongoDB复制集复制集架构三节点复制集模式PSS模式&#xff08;官方推荐模式&#xff09;PSA模式 典型三节点复制集环境搭建复制集注意事项环境准备配置复制集复制集状态查询使用mtools创建复制集安全认证复制集连接方式 复制集成员角色属性一&#xff1a;Priority 0属…

match-case与if/elif/else(python)

if/elif/else语句应对一般场景&#xff0c;match-case主打复杂条件分支语句。 (笔记模板由python脚本于2024年01月28日 18:27:37创建&#xff0c;本篇笔记适合有一定编程基础&#xff0c;对python基础已比较扎实的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1…

uniapp使用u-popup组件弹窗出现页面还可滑动

*1、问题所在&#xff1a; 弹窗遮罩层出现了页面依旧可以上下滑动 2、要求: 为了用户更好交互体验&#xff0c;弹窗出现后应禁止页面往下滑动 3、实现思路&#xff1a; 在弹窗盒子外层添加个阻止触摸冒泡事件&#xff0c;使用touchmove.stop.prevent 4、代码如下&#xff…

eosio.token 智能合约介绍

一、目的 eosio.token系统合约定义了允许用户为基于EOSIO的区块链创建、发行和管理代币的结构和操作&#xff0c;它演示了一种实现允许创建和管理代币的智能合约的方法。本文详细介绍了eosio.token系统合约并在本地测试链上实际发行了代币进行演示&#xff0c;适用于EOS智能合…

OJ刷题:《剑指offer》之单身狗1、2 !(巧用位操作符,超详细讲解!)

目录 1.单身狗1 1.1 题目描述 1.2排序寻找 1.3巧用位操作符 2.单身狗2 1.1 题目描述 1.2排序寻找 1.3巧用位操作符 不是每个人都能做自己想做的事&#xff0c;成为自己想成为的人。 克心守己&#xff0c;律己则安&#xff01; 创作不易&#xff0c;宝子们&#xff01;如…

homework day3

第三章 类与构造函数 一&#xff0e;选择题 1、下列不能作为类的成员的是&#xff08;B&#xff09; A. 自身类对象的指针 B. 自身类对象 C. 自身类对象的引用 D. 另一个类的对象 2、假定AA为一个类&#xff0c;a()为该类公有的函数成员&#xff0c;x为该类的一个对象&am…

如何在一台MacBook上构建大模型知识库?

▼最近直播超级多&#xff0c;预约保你有收获 今晚直播&#xff1a;《构建大模型知识库案例实战》 —1— 如何在一台 MacBook 上构建企业知识库&#xff1f; 最核心最重要的是我们手上的文档资料出于安全要求&#xff0c;不能随便上传到云服务&#xff0c;也就无法实际验证知识…

单链表的经典题目练习

哈喽&#xff0c;小伙伴们&#xff0c;上一次我们学习了单链表的知识&#xff0c;这次我们就要运用学到的知识来做一些相关的题目。我们都知道&#xff0c;要学好数据结构与算法&#xff0c;一定要多刷相关的题目才能有所提高。所以我们一起来学习一些单链表的经典题目算法题。…

操作系统透视:从历史沿革到现代应用,剖析Linux与网站服务架构

目录 操作系统 windows macos Linux 服务器搭建网站 关于解释器的流程 curl -I命令 名词解释 dos bash/terminal&#xff0c;(终端) nginx/apache&#xff08;Linux平台下的&#xff09; iis&#xff08;Windows平台下的&#xff09; GUI(图形化管理接口&#xff…