请求量太大扛不住怎么办?进来学一招

news2024/11/18 5:44:34

hello,大家好呀,我是小楼。

上篇文章《一言不合就重构》 说了我最近重构的一个系统,虽然重构完了,但还在灰度,这不,在灰度过程中又发现了一个问题。

背景

这个问题简单说一下背景,如果不明白可以看上篇文章 ,不想看也没关系,这是个通用的解法,后面我会总结抽象下。

在上篇文章的最后提到对每个摘除的地址做决策时,需要顺序执行,且每一个要摘除的地址都要实时获取该集群的地址信息,以便做出是否需要兜底的决策。

当被摘除的机器非常多时,获取地址信息的请求量就会非常大,对注册中心造成了不小的压力。

请求数据源的接口如下所示(其中 cuuid 是集群的 id)

type Read interface {
	ListClusterEndpoints(ctx context.Context, cuuid string) ([]ptypes.Endpoint, error)
}

相信大家也能理解这个非常简单的背景并且能想到一些解法。每次决策需要按 cuuid 获取集群,也就是单个单个地获取实时集群地址信息,由于是实时信息,缓存首先排除,其次自然而然地能想到如果能将请求合并一下,是不是就能解决请求量大的问题?

难点

如果只是改逻辑合并一下请求,吭哧吭哧改代码就完了,也不值得写这篇文章了,如何改最少的代码来实现合并请求才是最难的。

解法

那天遇到这个问题,晚上辗转反侧想到了这个解法,其实主要也是参考 Go http client 的实现,都说看源码没用,这不就是用处么?

Read 数据源接口定义保持不变,也就是上层的业务代码完全不用改,只需要把 ListClusterEndpoints 的实现换掉。

我们可以用一个队列把每个请求入队,入队列以后,调用方阻塞,然后起一些协程去队列里取一批请求参数,发起批量请求,响应之后唤醒阻塞的调用方。

为此,我们实现一个可以阻塞并被其他协程唤醒的工具:

type token struct {
	value interface{}
	err   error
}

type Token chan token

func NewToken() Token {
	return make(Token, 1)
}

func (t Token) Done(value interface{}, err error) {
	t <- token{value: value, err: err}
}

func (t Token) Wait(timeout time.Duration) (value interface{}, err error) {
	if timeout <= 0 {
		tk := <-t
		return tk.value, tk.err
	}

	select {
	case tk := <-t:
		return tk.value, tk.err
	case <-time.After(timeout):
		return nil, ErrTokenTimeout
	}
}

其次,定义队列和其他参数:

type DataSource struct {
	paramCh chan param
	readTimeout time.Duration
	concurrency int
	step int
}

type param struct {
	cuuid string
	token Token
}

替换掉原来 ListClusterEndpoints 的实现:

func (p *DataSource) ListClusterEndpoints(ctx context.Context, cuuid string) ([]ptypes.Endpoint, error) {
	req := param{
		cuuid: cuuid,
		token: NewToken(),
	}

	select {
	case p.paramCh <- req:
	default:
		return nil, fmt.Errorf("list cluster endpoints write channel failed")
	}

	value, err := req.token.Wait(p.readTimeout)
	if err != nil {
		return nil, err
	}
	eps, ok := value.([]ptypes.Endpoint)
	if !ok {
		return nil, fmt.Errorf("value is not endpoints")
	}
	return endpoints, nil
}

再起几个协程来处理任务:

func (p *DataSource) startListClusterEndpointsLoop() {
	for i := 0; i < p.concurrency; i++ {
		go func() {
			for {
				reqs := p.getListClusterEndpointsReqFromChan()
				p.doBatchListClusterEndpoints(reqs)
			}
		}()
	}
}

最关键的是 getListClusterEndpointsReqFromChan 的实现,既不能让协程空跑,这样太消耗cpu,又要能及时地取到一批参数,我们采取的方法是先阻塞地获取一个参数,如果没数据则阻塞,如果有数据,继续取,直到数量达到上限或者取不到数据为止,此时这一批数据就可以批量地进行调用了。

func (p *DataSource) getListClusterEndpointsReqFromChan() []param {
	reqs := make([]param, 0)
	select {
	case req := <-p.paramCh:
		reqs = append(reqs, req)
		for i := 1; i < p.step; i++ {
			select {
			case reqNext := <-p.paramCh:
				reqs = append(reqs, reqNext)
			default:
				break
			}
		}
	}
	return reqs
}

最后

这个方法很简单,但是有一些要注意的地方,得做好监控,比如调用方单个请求的QPS、RT,实际批量请求的QPS、RT,这样才好计算出处理协程开多少个合适,还有队列写入失败、队列长度等等监控,当容量不足时及时做出调整。

推荐阅读

与本文相关的文章也顺便推荐给你,如果觉得还不错,记得关注点赞在看分享

  • 《一言不合就重构》
  • 《如何给注册中心锦上添花?》
  • 《如何组装一个注册中心?》
  • 《服务探活的五种方式》
  • 《4个实验,彻底搞懂TCP连接的断开》

  • 搜索关注微信公众号"捉虫大师",后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践;
  • 加微信MrRoshi拉你进技术交流群,各路大佬带你飞。

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

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

相关文章

数据结构之排序【直接插入排序和希尔排序的实现及分析】

引言&#xff1a; 今天天气还是依然的冷&#xff0c;码字越来越不容易了&#xff0c;本来上次写了一个比较好的引言&#xff0c;但是因为电脑第二天没电&#xff0c;并且我没有保存&#xff0c;现在找不到了&#xff0c;所以今天我们的引言就这样吧&#xff01;今天给大家介绍…

Zookeeper 4 Zookeeper JavaAPI 操作 4.3 Curator API 常用操作【添加节点】

Zookeeper 【黑马程序员Zookeeper视频教程&#xff0c;快速入门zookeeper技术】 文章目录Zookeeper4 Zookeeper JavaAPI 操作4.3 Curator API 常用操作4.3.1 添加节点4 Zookeeper JavaAPI 操作 4.3 Curator API 常用操作 4.3.1 添加节点 直接开始编写 测试方法 先写一下&a…

Web入门开发【五】- 线上部署

欢迎来到霍大侠的小院&#xff0c;我们来学习Web入门开发的系列课程。 首先我们来了解下这个课程能学到什么&#xff1f; 1、你将可以掌握Web网站的开发全过程。 2、了解基础的HTML&#xff0c;CSS&#xff0c;JavaScript语言。 3、开发自己的第一个网站。 4、认识很多对编…

南卡与JBL蓝牙耳机哪款比较好?数码资深玩家带你深度评测了解

马上到来2023新的一年&#xff0c;不会还有人使用传统有线耳机吧&#xff1f;那你就属最落后的那位了&#xff0c;随着生活水平的提高&#xff0c;科技的快速发展&#xff0c;有线耳机逐渐被真无线蓝牙耳机所取代。现在走在马路上都能看见许多人佩戴着耳机&#xff0c;然而&…

机器学习 | 朴素贝叶斯

一.基本原理 基于条件独立的假设&#xff0c;先计算输入和输出的联合概率密度&#xff0c;然后根据所输入的x计算y的概率&#xff0c;然后选择具有最大后验概率的类作为它的类别 二.优缺点 优点 小规模数据集表现好&#xff0c;适合多分类对于在小数据集上有显著特征的相关对…

Scikit-network-02:载图

载图 在Scikit网络中&#xff0c;图形由其scipy的压缩稀疏行格式中的邻接矩阵&#xff08;或二部图矩阵&#xff09;表示。在本教程中&#xff0c;我们提供了一些方法来实例化此格式的图。 from IPython.display import SVGimport numpy as np from scipy import sparse impo…

SQL注入渗透与攻防(九)之布尔盲注

目录 1.什么是布尔盲注&#xff1f; 2.如何进行布尔盲注&#xff1f; 案列演示&#xff1a; 1.什么是布尔盲注&#xff1f; Web的页面的仅仅会返回True和False。那么布尔盲注就是进行SQL注入之后然后根据页面返回的True或者是False来得到数据库中的相关信息。 我们这里拿sql…

15Python文件操作

文件处理 01. 文件的概念 1.1 文件的概念和作用 计算机的 文件&#xff0c;就是存储在某种 长期储存设备 上的一段 数据长期存储设备包括&#xff1a;硬盘、U 盘、移动硬盘、光盘… 1.2 文件的存储方式 在计算机中&#xff0c;文件是以 二进制 的方式保存在磁盘上的 文本…

论文理解--DEEP COMPRESSION

原文链接&#xff1a; https://github.com/mit-han-lab/amc/security https://zhuanlan.zhihu.com/p/108096347 https://zhuanlan.zhihu.com/p/510905067 摘要 结论&#xff1a; 1、deep compression:由三阶段pipeline组成&#xff1a;pruning(剪枝)、 trained quantilization…

452页24万字智慧城市顶层设计及智慧应用解决方案

智慧城市总体设计 2.1 智慧城市核心技术 2.1.1 物联网 智慧城市是一个有机结合的大系统&#xff0c;涵盖了更透切的感知、更全面的互连&#xff0c;更深入的智能。物联网是智慧城市中非常重要的元素&#xff0c;它侧重于底层感知信息的采集与传输&#xff0c;城市范围内泛在网方…

无需调用Tecplot,PFC后处理技巧为你plot精美科研图

导读&#xff1a;PFC提供了非常美观的可视化处理的窗口—plot&#xff0c;用户可以在这里对模型的运行状态进行检查&#xff0c;也可以将Plot中的视图输出进行处理。一般来说plot中的图片质量足够用于常规的论文配图&#xff0c;当然用户也可以导出数据到tecplot中进行后处理&a…

【UE4 第一人称射击游戏】08-使用“AK47”发射子弹

上一篇&#xff1a; 【UE4 第一人称射击游戏】07-添加“AK47”武器 本节效果&#xff1a; 步骤&#xff1a; 1.在“Blueprints”文件夹内添加一个Actor蓝图&#xff0c;命名为“Projectile_Base”&#xff0c;该蓝图用于表示子弹 双击打开“Projectile_Base”&#xff0c;添加…

期货开户的身份识别验证

无论你是开通商品期货、原油期货还是股指期货以及期权&#xff0c;现在都支持网上办理&#xff01;原油期货和股指期货以及期权品种都是在商品期货账户的基础上满足条件后再另外开通交易权限。叁格期权小编在这里为各位投资者详细介绍商品期货网上开户流程。 一、开户前准备 …

文件透明加密,保护重要数据的安全性

各种泄露事件使人们对信息安全问题的高度关注&#xff0c;随着加密技术的不断完善&#xff0c;主流透明加密技术被广泛应用于企业加密软件中。那么&#xff0c;这个技术如何保护电脑&#xff1f;有什么优点&#xff1f; 文件透明加密是最近几年发展出来的一种文件加解密技术。所…

RK3568平台开发系列讲解(工具命令篇)vim 编辑器的使用

🚀返回专栏总目录 文章目录 一、vim 编辑器有三种模式二、vim 编辑器移动光标三、vim 编辑器支持快速定位四、vim 编辑器的文本的复制和粘贴五、vim 编辑器使用快捷键来复制六、vim 编辑器的删除七、vim 编辑器的撤销八、vim 编辑器的查找九、vim 编辑器的替换十、vim 编辑器…

四、GradCAM可解释性分析——可解释性机器学习(DataWhale组队学习)

目录CAM算法回顾CAM算法流程CAM算法的精妙之处CAM算法的缺点GradCAMGrad-CAM算法的优点&#xff1a;Grad-CAM算法的缺点&#xff1a;Grad-CAM算法的改进Grad-CAM算法Score-CAM算法LayerCAM算法总结CAM算法回顾 CAM算法流程 输入原始图像&#xff0c;经过多层无池化的全卷积神经…

23种设计模式:单例设计模式(饿汉式 VS 懒汉式)

23种设计模式&#xff1a;单例设计模式&#xff08;饿汉式 VS 懒汉式&#xff09; 每博一文案 世事浮沉&#xff0c;有太多的责任需要我们担当&#xff0c;生活中总有些挫折和磨难&#xff0c;让我们觉得快要杠不住了。 但当我们咬牙坚持过那段难熬的时光后&#xff0c;发现并…

居家防护类设备的智能化解决方案

疫情防控政策优化后&#xff0c;你期待的消费暴涨如期而至了吗&#xff1f;近期&#xff0c;继自带“玄学”光环的黄桃罐头被疯抢之后&#xff0c;橘子水、葱姜水、古法掐喉咙消肿等缓解疼痛的“东方神秘法宝”再现各大视频平台。 面对此次居家隔离&#xff0c;哪些产品将再次…

(Java)欢乐的跳

欢乐的跳一、题目描述二、输入格式三、输出格式四、样例&#xff08;1&#xff09;样例输入1&#xff08;2&#xff09;样例输出1&#xff08;3&#xff09;样例输入2&#xff08;4&#xff09;样例输出2五、提示六、正确代码七、注意点以及思路&#xff08;1&#xff09;注意点…

【万字长文】从Linux零拷贝深入了解Linux I/O

前言 存储器是计算机的核心部件之一&#xff0c;在完全理想的状态下&#xff0c;存储器应该要同时具备以下三种特性&#xff1a; 速度足够快&#xff1a;存储器的存取速度应当快于 CPU 执行一条指令&#xff0c;这样 CPU 的效率才不会受限于存储器容量足够大&#xff1a;容量…