FIFO的工作原理及其设计

news2024/10/6 10:42:49

1.简介

        FIFO( First Input First Output)简单说就是指先进先出。FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个口是存储器的输入口,另一个口是存储器的输出口。

        对于单片FIFO来说,主要有两种结构:触发导向结构和零导向传输结构。触发导向传输结构的FIFO是由寄存器阵列构成的,零导向传输结构的FIFO是由具有读和写地址指针的双口RAM构成。

        FIFO与普通RAM存储器的区别是没有外部读写地址线(指针),使用方便,但缺点是只能顺序写入数据和读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

1.1.功能

        FIFO存储器是系统的缓冲环节,主要有几方面的功能:

                1)对连续的数据流进行缓存,防止在进机和存储操作时丢失数据;

                2)数据集中起来进行进栈和存储,可避免频繁的总线操作,减轻CPU的负担;

                3)允许系统进行DMA操作,提高数据的传输速度。这是至关重要的一点,如果不采用DMA操作,数据传输将达不到传输要求,而且大大增加CPU的负担,无法同时完成数据的存储工作。

1.2.用途

1.2.1.跨时钟域多bit数据传输

        解决一个系统多个时钟所带来的问题:异步时钟之间的接口电路。异步FIFO是解决这个问题的一种便捷简单的方案,使用异步FIFO可以在两个不同时钟系统之间快速方便地传输实时数据。

1.2.2.达到数据匹配问题(读写位宽不一致)

        对于不同宽度的数据接口也可以使用FIFO,例如单片机的8位输出而DSP可能是16位输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

1.3.主要参数

  • 宽度(WIDTH):FIFO每个地址的数据位宽(W);
  • 深度(DEEPTH):FIFO可以存储多少个W位的数据;
  • 满(full)标志:FIFO已满或将满时,会输出一个对写操作的反压信号,以阻止被继续写入数据而溢出;
  • 空(empty)标志:FIFO已空或将空时,会输出一个对读操作的反压信号,以避免被继续读出无效数据;
  • 读/写时钟:读/写操作所遵循的时钟,每个时钟沿触发。

        根据FIFO工作的时钟域分为同步/异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟在时钟沿来临时同时发生读写。异步FIFO读写时钟不一致,读写相互独立。

        读写指针即读写地址,当前读/写操作完成后,指针自动加一指向下一个地址(连续递增)。

  • 写指针:总是指向下一个将要被写入的地址,复位时指向编号0的地址;
  • 读指针:总是指向下一个将要被读出的数据地址,复位时也指向编号0的地址且此时数据无效;

2.工作原理

2.1.空满标志

2.1.1.读空信号(rd_empty)

        一般情况下当读写指针相等时,表明FIFO已空,这种情况发生在复位操作时或当读指针读出FIFO中最后一个有效数据时(即读指针追赶上写指针),此时读空信号有效,如下左图:

在这里插入图片描述在这里插入图片描述

2.1.2.写满信号(wr_full)

        当读写指针再次相等时,即写指针转了一圈又折回来(wrapped around)从起始低位追上了读指针(写比读快),此时表明FIFO已满,如上右图:

2.2.空满判断机制

2.2.1.同步fifo空满判断

  • 方案一:extra bit

                深度为N=2^{n}的FIFO其地址位宽为n,若数据位宽为W则该FIFO的容量为N*W bits。

                现在在指针添加1个extra bit即地址的MSB,使其变为n+1 bits,该extra bit用来指示读/写指针是否连续递增并越过了FIFO的最后一个地址,若越过则该MSB加1,其他位清零。例如深度为8的fifo,需要采用1+3bits的地址位宽,MSB作为指针折回标志,低3bits作为地址。

                那么判断机制读指针读出FIFO最后一个有效数据后即会停止递增)为:

                ①如果两个指针的MSB不同,就说明写指针比读指针多折回一次,此时若除开MSB以外的地址位相等,则表示FIFO已满;

                ②如果两个指针的MSB相同,就说明读写指针的折回次数相同,若其他地址位相等,则表示读写指针完全相等,FIFO已空。

  • 方案二:设置数据计数器

                设置一个data_counter,当写使能有效时数据计数器加1,每读出一个数据时该计数器又减1。如此,当data_counter=0时FIFO为空,data_counter=FIFO深度时表明已满。

                缺点:计数器会占用额外资源,当FIFO较大时,可能会降低FIFO的读写速度。

2.2.2.异步fifo空满判断

  • 判断步骤如下:

                ①地址指针采用二进制(binary)+extra bit

                ②二进制指针转gray码后跨时钟域同步做比较

        当读写指针采用二进制表示且读写操作属于异步时钟时,读写指针做比较前需要先将其中一个指针同步到另一个指针的时钟域后再操作,直接同步这样容易产生亚稳态问题。

        可以使用一个二进制转gray码的转换电路,将地址转换为对应的gray码后再同步到另一个时钟域,进行对比产生空满指示,如左下图:

在这里插入图片描述

                例如1+3bits的二进制地址完全转换为gray后如右上图所示,此时空满标志不能按照原来二进制的方法来判断,gary码指针的空满判断标准如下:

                空标志:gray码地址完全相等(包括MSB)。

                满标志:高两位(MSB+次高位)不同,其余各位相同。

                PS:二进制与格雷码互相转换 。

  • 补充:

                ①同步方向产生保守的空满机制:

                        读指针同步到写时钟域:经过一定的同步时间后,此时同步后(写时钟域的)读指针小于或等于真实的(读时钟域)的读指针,而写指针是即时且真实的,空满判断机制可产生保守的“假写满”(正确且安全设计)和错误的“读空”。

                        反之同理,总结:写时钟域产生正确的“假写满”,读时钟域产生正确的“假读空”

                ②由于读写异步快时钟域同步慢时钟域指针可能会漏采,不会影响空满判断逻辑:

                        举例读慢写快:写指针同步到读时钟域发生漏采,即读时钟域采样到的写指针小于真实的(写时钟域的)写指针,此时不会导致“读空判断逻辑”错误,也是保守且正确的。反之亦然。

3.FIFO代码设计示例

3.1.同步FIFO代码

        同步FIFO由于没有跨时钟的操作,所以只需要使用二进制即可,不用格雷码操作。根据上面的分析,有两种方法进行表示full/empty状态,代码如下:

//1、generate full/empty signal by addr
assign full = (waddr_ptr == {~raddr_ptr[ADDR_WIDTH-1],
                              radde_ptr[ADDR_WIDTH-2:0]});
assign empty = (waddr_ptr == raddr_ptr);
//2、generate full/empty signal by conuter
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		data_cnt <= {ADDR_WIDTH{1'b0}};
	end
	else if(wen && ren && !full && !empty)begin
		data_cnt <= data_cnt;
	end
	else if(wen && !full)begin
		data_cnt <= data_cnt + 1'b1;
	end
	else if(ren && !empty)begin
		data_cnt <= data_cnt - 1'b1;
	end
end

assign full = (data_cnt == FIFO_DEPTH);
assign empty = (data_cnt == 0);

3.2.异步FIFO代码

        由于存在读写时钟不同步的问题,采用的解决方法是:加两级寄存器同步 + 格雷码(目的都是消除亚稳态),代码示例如下: 

`timescale 1ns/1ps
module async_fifo #(
	parameter	DATA_WIDTH	= 32,
	parameter	DATA_DEPTH	=  8,
	parameter	PTR_WIDTH	= $clog2(DATA_DEPTH)
)(
	//write interface	
	input  wire					 clk_wr_i,
	input  wire					 rst_n_wr_i,	
	input  wire					 wr_en_i,
	input  wire [DATA_WIDTH-1:0] wr_data_i ,
	output wire					 wr_full_o,
	
	//read interface
	input  wire					 clk_rd_i,
	input  wire					 rst_n_rd_i,
	input  wire					 rd_en_i,
	output reg  [DATA_WIDTH-1:0] rd_data_o,
	output wire					 rd_empty_o
);
	reg  [DATA_WIDTH-1:0]	fifo[DATA_DEPTH-1:0];

    reg                     wr_ptr_ext;
	reg	 [ PTR_WIDTH-1:0]	wr_ptr;
	wire [ PTR_WIDTH  :0]	wr_ptr_gray;
	reg	 [ PTR_WIDTH  :0]	wr_ptr_gray_d1;
	reg	 [ PTR_WIDTH  :0]	wr_ptr_gray_d2;

	reg                     rd_ptr_ext;
	reg  [ PTR_WIDTH-1:0]	rd_ptr;
	wire [ PTR_WIDTH  :0]	rd_ptr_gray;
	reg	 [ PTR_WIDTH  :0]	rd_ptr_gray_d1;
	reg  [ PTR_WIDTH  :0]	rd_ptr_gray_d2;
	
//------------- ptr++ and data inout--------------
always @(posedge clk_wr_i or negedge rst_n_wr_i) begin
	if(!rst_n_wr_i)begin
		{wr_ptr_ext, wr_ptr} <= {(PTR_WIDTH+1){1'b0}};
        fifo[wr_ptr]         <= { (DATA_WIDTH){1'b0}};
    end
	else if(wr_en_i && !wr_full_o)begin
		{wr_ptr_ext, wr_ptr} <= {wr_ptr_ext, wr_ptr} + 1'b1;
        fifo[wr_ptr]         <= wr_data_i;
    end
end

always @(posedge clk_rd_i or negedge rst_n_rd_i) begin
	if(!rst_n_rd_i)begin
		{rd_ptr_ext, rd_ptr} <= {(PTR_WIDTH+1){1'b0}};
		rd_data_o            <= { (DATA_WIDTH){1'b0}};
    end
	else if(rd_en_i && !rd_empty_o)begin
		{rd_ptr_ext, rd_ptr} <= {rd_ptr_ext, rd_ptr} + 1'b1;
		rd_data_o            <= fifo[rd_ptr];
    end
end
	
//--------- binary to gray ---------
assign rd_ptr_gray = {rd_ptr_ext, rd_ptr} ^ ({rd_ptr_ext, rd_ptr}>>1);
assign wr_ptr_gray = {wr_ptr_ext, wr_ptr} ^ ({wr_ptr_ext, wr_ptr}>>1);

//--------- pointer sync -----------
always @(posedge clk_wr_i or negedge rst_n_wr_i) begin
	if(!rst_n_rd_i) begin
		rd_ptr_gray_d1 <= {(PTR_WIDTH+1){1'b0}};
		rd_ptr_gray_d2 <= {(PTR_WIDTH+1){1'b0}};
	end
	else begin
		rd_ptr_gray_d1 <= rd_ptr_gray;
		rd_ptr_gray_d2 <= rd_ptr_gray_d1;
	end
end

always @(posedge clk_rd_i or negedge rst_n_rd_i) begin
	if(!rst_n_rd_i) begin
		wr_ptr_gray_d1 <= {(PTR_WIDTH+1){1'b0}};
		wr_ptr_gray_d2 <= {(PTR_WIDTH+1){1'b0}};
	end
	else begin
		wr_ptr_gray_d1 <= wr_ptr_gray;
		wr_ptr_gray_d2 <= wr_ptr_gray_d1;
	end
end

//------------ full_o and empty_o ------------------
assign wr_full_o  = (wr_ptr_gray=={~rd_ptr_gray_d2[PTR_WIDTH:PTR_WIDTH-1],
                     rd_ptr_gray_d2[PTR_WIDTH-2:0]}) ? 1'b1 : 1'b0;
assign rd_empty_o = (rd_ptr_gray==wr_ptr_gray_d2) ? 1'b1 : 1'b0;

endmodule

4.FIFO的深度计算

4.1.概念

        突发(burst)传输:In telecommunication, a burst transmission or data burst is the broadcast of a relatively high-bandwidth transmission over a short period。某个短时间内相对高带宽的数据传输。

        假如模块A不间断地往FIFO中写数据,模块B同样不间断地从FIFO中读数据,不同的是模块A写数据的时钟频率要大于模块B读数据的时钟频率,那么在一段时间内总是有一些数据没来得及被读走,如果系统一直在工作,那么那些没有被读走的数据会越累积越多,那么FIFO的深度需要是无穷大的,因此只有在突发数据传输过程中讨论FIFO深度才是有意义的。一次传递一包数据完成后再去传递下一包数据,一段时间内传递的数据个数称为burst length

        FIFO的最小深度与burst rate, burst size, read and write frequency等因素有关。要确定FIFO的深度,关键在于计算出在突发读写这段时间内有多少个数据没有被读走,即FIFO的最小深度就等于没有被读走的数据个数。

4.2.深度计算示例

        假定模块A向FIFO写数据的时钟频率为fa,模块B从FIFO读数据的时钟频率为fb。

场景1:idle cycles in both write and(or) read

假设:

  • 写数据时钟频率fa=80MHz,读数据时钟频率fb=50MHz;
  • 突发长度= number of data to be transferred = 120;
  • 每隔1个cycle写一次,每隔3个cycle读一次。

那么:

  • 每隔1个cycle写一次,意味着2个cycle才写一个数据;每隔3个cycle读一次,意味着4个cycle才读一个数据。
  • 写一个数据所需要的时间 = 2*1/80MHz = 25ns。突发传输中,写完所有数据所需要的时间 = 120*25ns = 3000ns。
  • 读一个数据所需要的时间 = 4*1/50MHz = 80ns。在3000ns内能够读走的数据个数 = 3000ns/80ns = 37.5。
  • 所以在3000ns内还没有被读走的数据个数 = 120-37.5 = 82.5,因此FIFO的最小深度为83。

场景2fa ≤ fb with no idle cycles in both write and read

假设:

  • 写数据时钟频率fa=40MHz,读数据时钟频率fb≥40MHz
  • 突发长度= number of data to be transferred = 120
  • 在突发传输过程中,数据都是连续读写的

由于读数据比写数据要快,因此FIFO只起到跨时钟域的作用,FIFO的最小深度为1即可。

场景3:Data rates are given,read and write random

        在工程设计中还存在一种情形,只给出数据在一段时间内的读写速率,怎么读写完全随机,这种情况需要考虑最坏的一种情况避免数据丢失。在最坏的情形中,读写的速率应该相差最大,也就是说需要找出最大的写速率和最小的读速率。

假设:

  • 写数据时钟频率fa=80MHz,读数据时钟频率fb=50MHz
  • 在写时钟周期内,每100个周期就有40个数据写入FIFO
  • 在读时钟周期内,每10个周期可以有8个数据读出FIFO

那么:

  • 首先没有给出数据的突发长度,从假设中可以得出每100个周期就有40个数据写入FIFO,因为数据是随机写入FIFO的,需要考虑做坏的情形,即写速率最大的情形,只有如下图背靠背的情形才是写速率最高的情形,burst length为80。

  • 注意:这里需要验证一下是否有解即写入burst数据时间必须大于等于读出burst数据时间,不然数据就会越累积越多,使得FIFO的深度必须为无穷大。首先写入80个数据需要的时间 = 1/80MHz*(80*100/40)=2500ns,读出80个数据需要的时间 = 1/50MHz*(80*10/8)=2000ns,由于写入burst数据时间大于对出burst数据时间,因此有解。
  • 下面来计算FIFO最小深度,连续写入80个数据最快所需要时间 = 1/80MHz * 80 = 1000ns。
  • 从FIFO中读出一个数据至少所需时间 = (1/50MHz) * (10/8) = 25ns。那么在1000ns内能够读出的数据 = 1000ns/25ns = 40。
  • 在1000ns内没有读出的数据 = 80 - 40 = 40,因此FIFO的最小深度为40。

         参考FIFO深度计算。

4.3.异步FIFO的深度不为2的正整数次幂

4.3.1.FIFO的深度为1

        方案一:将深度加1变为2,这样地址指针用1bit表示即可,且不用添加extra bit。

         方案二:采用脉冲同步读写信号,参考深度为1的异步FIFO设计。

        方案三:采用握手机制去跨时钟,不属于FIFO类型。

4.3.2.FIFO的深度为其他任意数

        无论FIFO的深度为奇数或偶数,都需要对地址指针扩展1bit来作为标志位,这样产生的地址指针循环一定为偶数,再利用格雷码的环回对称性,采用“掐头去尾+地址偏移”的方法。

        地址同步后不能采用原来2的整数次幂的gray判断空满机制来做判断,此时可以将格雷码再转回二进制后再做空满判断。

        参考任意深度异步FIFO设计。

5.读写位宽不一致问题

        对于异步fifo,由于地址不能跳变,fifo的位宽可以选择输入输出位宽的最小公倍数,会有一定的保守性。

        参考FPGA之FIFO详解,读写位宽不同。

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

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

相关文章

文字转语音软件的优缺点及如何选择最适合的工具

随着科技的进步&#xff0c;文字转语音技术已经越来越成熟&#xff0c;越来越多的人开始使用文字转语音软件来转换文本为语音。这种技术可以帮助人们在许多方面&#xff0c;例如改善阅读体验、方便学习、提高生产效率等。然而&#xff0c;文字转语音软件有其优缺点&#xff0c;…

一文读懂推荐系统用户画像

1.推荐系统用户画像 用户画像这个词具有广泛性。 它被应用于推荐&#xff0c;广告&#xff0c;搜索&#xff0c;个性化营销等各个领域。任何时候&#xff0c;不管出于什么目的&#xff0c;我们想描述我们的用户是谁的时候&#xff0c;大家都会用到用户画像这个词。 比如&…

VUE_学习笔记

一、 xx 二、模板语法 1.模板语法之差值语法 &#xff1a;{{ }} 主要研究&#xff1a;{{ 这里可以写什么}} 在data中声明的变量、函数等都可以。常量只要是合法的javascript表达式&#xff0c;都可以。模板表达式都被放在沙盒中&#xff0c;只能访问全局变量的一个白名单&a…

精准关键词获取-行业搜索词分析

SEO关键词的收集通常可以通过以下几种方法&#xff1a; 根据市场价值、搜索词竞争性和企业实际产品特征进行筛选&#xff1a;确定您的关键词列表之前&#xff0c;建议先进行市场分析&#xff0c;了解您的竞争对手、行业状况和目标受众等信息&#xff0c;以更好的了解所需的特定…

MySQL日志

MySQL日志 错误日志 错误日志是MySQL中最重要的日志之一&#xff0c;它记录了当mysqld启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 使用如下命令&#xff0c;可…

ChatGPT宝藏插件丨装上之后,上网、语音聊天、一键分享对话……简直让你爽到起飞!

今天分享4个让你的 ChatGPT 功能更强大的浏览器插件&#xff0c;装上就能用&#xff0c;每一个都是精挑细选。 1. WebChatGPT 很多小伙伴在用 ChatGPT查阅信息时&#xff0c;发现它有一个致命的问题&#xff1a; ChatGPT的知识库全部截止到 2021年9月&#xff0c;正常情况下…

航拍构图方法

目录 简介 对比构图 重复对比 明暗对比 颜色对比 空间错位 点构图 中心点构图 九宫格构图 线构图 二分线&#xff08;水平、对称&#xff09;构图 三分线构图 平行线构图 对角线构图 引导线构图 面构图 前景构图 简化构图 总结 简介 最近接触了无人机&#xf…

MySQL数据库备份(导出导入)的命令详解mysqldump

![在这里插入图片描述](https://img-blog.csdnimg.cn/174ee9e5170445b7acab94c5d97684ea.png [options] 参数参数说明-A, --all-databases导出所有数据库-B, --databases导出指定数据库-h, --hostname指定ip&#xff0c;默认本机-P, --port#指定端口&#xff0c;默认3306-u, …

【Java面试八股文宝典之MySQL篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day21

大家好&#xff0c;我是陶然同学&#xff0c;软件工程大三即将实习。认识我的朋友们知道&#xff0c;我是科班出身&#xff0c;学的还行&#xff0c;但是对面试掌握不够&#xff0c;所以我将用这100多天更新Java面试题&#x1f643;&#x1f643;。 不敢苟同&#xff0c;相信大…

JavaEE——文件操作与IO操作

目录 文件路径 文件类型 File类 文件的创建 文件流 File类文件读写操作 通过PrintWriter写或Scanner读 PrintWriter写 Scanner读 文件路径 计算机中的文件是以树形结构进行存储的。要找一个文件&#xff0c;需要通过根目录一层一层找&#xff0c;直到找到&#xff0c;…

不敲代码用ChatGPT开发一个App

先说下背景&#xff0c;有一天我在想 ChatGPT 对于成熟的开发者来说已经是一个非常靠谱的助手了&#xff0c;身边也确实有很多同事把它作为一个离不开的助理担当。 但是如果我只是略微懂一点前端知识的新人&#xff0c;了解 HTML、CSS、JS 相关的知识&#xff0c;想开发一个安…

华为进军ERP,北用友南金蝶格局或将生变?用户:No!我们选择它

目录 华为搅局ERP市场 用友金蝶如何应对 我们另有选择 那么这款软件是什么&#xff1f; 小结 华为搅局ERP市场 任正非表示4月份将上线MetaERP&#xff01;受此消息影响&#xff0c;ERP市场的两大巨头用友、金蝶股价纷纷跳水。 在机构的定价逻辑里&#xff0c;用友网络、金…

主机发现和端口扫描基本原理和工具选择

发现主机 扫描端口指令sudo nmap -sn ip 实则是封装ping指令 可以找目标靶机 sudo nmap --min-rate 10000 -p- 192.168.10.191 -p端口号 -p-从一开始扫 设置最小速度扫描 -p-指定靶机 10000是较好的速度 在工作中最好扫两遍 UDP扫描 sudo nmap -sU --min-rate 10000 …

10 kafka生产者发送消息的原理

1.发送原理&#xff1a; 在消息发送的过程中&#xff0c;涉及到了两个线程——main 线程和 Sender 线程。在 main 线程 中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator&#xff0c; Sender 线程不断从 RecordAccumulator 中拉取消息发送到…

大数据自我进阶(数据仓库)-暂未完全完成

什么时候需要数据仓库&#xff1f; 1.当决策者要进行战略分析或者展示统计的需求。 2.并且数据量非常庞大&#xff0c;而且各个都是数据孤岛。 当满足这2个条件后&#xff0c;就需要搭建数据仓库。 数据仓库的第一步&#xff08;数据清洗&#xff09; 为了能准确的分析&am…

python编辑工具PyCharm下载安装步骤

开发python程序的途径还是不少的 用解释器一行行执行代码 或者 通过解释器程序执行一个python代码文件 但这两种方式 其实都只是测试场景下的使用 就好像古代打仗&#xff0c;光有英雄好汉没用&#xff0c;他还有有一件趁手的兵器&#xff0c;大部分python程序都是在PyCharm上开…

MIPI 打怪升级之DPI篇

目录1 Overview2 Display Architectures2.1 Type 1 Display Architecture Block Diagram2.2 Type 2 Display Architecture Block Diagram2.3 Type 3 Display Architecture Block Diagram2.4 Type 4 Display Architecture Block Diagram3 Interface Signal Description3.1 Power…

逆波兰表达式求值(力扣刷题代码随想录刷题)

给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。 每个操作数&#xff08;运算对象&#xff09;都可以是一个整数或者另一个表达式。 两…

4月9日第壹简报,星期日,农历闰二月十九

4月9日第壹简报&#xff0c;星期日&#xff0c;农历闰二月十九坚持阅读&#xff0c;静待花开1. “2023中国品牌女性500强”榜单揭晓&#xff0c;屠呦呦、张桂梅、董明珠、刘洋、孟晚舟、谷爱凌等入选。2. 京东集团副总裁&#xff1a;将在今年发布“京东版”ChatGPT。3. 以冒名顶…

壹-prometheus安装

https://blog.csdn.net/hancoder/article/details/121703904 安装 壹&#xff0c; prometheus server 安装 github 1,上传安装包 # 解压到/opt/module 目录下&#xff1a; mkdir /opt/module tar -zxvf prometheus-2.29.1.linux-amd64.tar.gz -C /opt/module # 修改目录…