news 2026/10/18 10:08:22

RDMA Queue Pair(QP)状态机详解:从Reset到RTS的配置与故障排查

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RDMA Queue Pair(QP)状态机详解:从Reset到RTS的配置与故障排查

RDMA这个技术,特别是Queue Pair(QP)这一块,很多做网络、存储和高性能计算的同学,最初都会被两个概念卡住:为什么网卡收包非要搞出一对队列?状态机又是什么鬼?我当年第一次从Reset状态一步步把QP调到RTS,成功跑通RDMA读写时,才真正搞明白这套设计不是故意增加复杂度,而是可靠传输、资源复用和硬件卸载三者互相妥协出来的结果。这篇我打算把QP的细节知识点和状态转换一次讲透,尽量配合真实操作顺序,让你看完能直接上手。

1. 先把QP的定位搞清楚:从一根网线到两个工作队列

1.1 为什么RDMA非要把发送和接收做成“一对队列”

传统网络收发包,驱动从协议栈拿到数据,交给网卡去处理,数据的收发路径是分散的,软件需要参与每一个包的分发、校验、时序管理。而RDMA的核心思路是把“发送意图”和“接收意图”直接下沉到网卡硬件,内核和CPU尽量不碰数据路径。要做到这一点,必须把软件之间的交流抽象成“队列”:发送方把任务扔进队列,接收方把自己的接收缓冲区挂到另一个队列,网卡自己从这两个队列里取任务、做地址翻译、搬运数据、发回应。

这对队列就叫做QP(Queue Pair),它天然体现了一对一的通信关系:一个QP就是一条逻辑连接的两端虚拟化接口。正因为QP是成对出现的,RDMA网卡才知道哪个发送请求对应哪个接收缓冲区,不需要每包都走一遍路由查找,这就是为什么QP又被叫做“通信端点”而不是“普通网卡的收发队列”。

1.2 三类主流QP:RC、UC、UD横向对比

QP不是只有一种,不同的QP类型对应不同的可靠性、连接性和负载能力,选择错误会直接导致建链失败或性能不达标。最常见的三种是RC、UC、UD。

RC(Reliable Connection)是最常用的可靠连接类型,面向连接,提供确认、重传、丢包恢复、顺序保证,类似于TCP的语义,但实现在网卡硬件里。RC支持RDMA Read、Write、Atomic等一整套操作,适合存储、HPC、分布式训练这类不容错失数据的场景。

UC(Unreliable Connection)也是面向连接的,同样有顺序保证,但它没有ACK、没有重传,数据丢了就是丢了。UC比RC少了确认开销,延迟更低,适合对丢包不敏感、但需要消息顺序的实时流场景,比如低频同步信号。

UD(Unreliable Datagram)类似于UDP,不面向连接,一个QP可以往多个目的QP发数据,也支持多播。UD无法使用RDMA Read/Write/Atomic,只能使用Send/Receive原语,每次报文都要带全局路由头(GRH)和目的QPN。UD适用于广播、多播、服务发现和控制面信令。

从实现负载看,RC的QP消耗最多硬件资源,因为要维护发送窗口、重传缓存、PSN状态;UC次之;UD最轻。选择QP类型时一定要明确负载语义,否则后面调参全是在弥补方向性错误。

1.3 QP不是孤立存在的:SQ、RQ、CQ、EQ的关系

调用库创建QP时,实际上创建了一组相互关联的对象:发送队列(SQ)、接收队列(RQ)是QP内部的两个工作队列,完成队列(CQ)记录操作结果,事件队列(EQ)上报异步错误。

SQ和RQ并不是独立设备,它们属于同一个QP,由同一个QPN(Queue Pair Number)索引。软件通过Post Send把发送请求(WR)投递到SQ,通过Post Receive把接收请求(WR)投递到RQ。网卡完成某个WR后,会生成WC(Work Completion)写进CQ;如果出现异步异常(比如QP进入Error状态),网卡会把事件投递到EQ。

实际经验里最常见的认知误区是:以为CQ是和QP一对一绑定的。CQ可以被多个QP共享,比如我可以在一个CQ上服务几百个QP的完成事件,这样中断和轮询的开销会小很多。QP、QPN、CQ、EQ这套关系搞明白,排查问题时才不至于把“完成事件丢失”误判成“QP状态异常”。

1.4 一个容易被忽略的全局视角:QP与内存注册

QP描述的是“怎么发、发给谁”,但数据从哪里来、放到哪里去,还要靠Memory Region(MR)和lkey/rkey解决。网卡访问主机内存之前,必须先把内存区域注册成MR,拿到local key(lkey)和remote key(rkey),并在WQE的SGE里告诉网卡“用哪块内存、长度多少”。

QP和MR是同一个问题里不可分割的两面。RC里的RDMA Write目标地址,就是由接收端QP的RTR配置以及MR暴露的远程访问权限共同决定的。如果对端QP配置了允许Remote Write,但你注册MR时没有给远端访问的权限位,请求照样会失败。所以每次查QP状态异常,同时要查MR是否还活着、lkey/rkey是否过期,这两个对象经常一起出问题。

2. 拆开一个QP看内部:字段、属性与对象的真实含义

2.1 QP的关键标识和属性字段

QP属性字段非常多,但真正决定连接能否建立、传输是否符合预期的核心字段,可以整理成一张速查表。大家配置时不一定要全懂,但必须知道每一个字段的作用。

字段作用典型设置时机
qp_state当前状态Modify QP每次迁移时设置
qp_type类型:RC/UC/UD等创建QP时确定,不可改
qpn本地QP编号自动分配,连接握手时交换
dest_qp_num对端QP编号RTR迁移时设置
sq_psn本端发送队列的初始包序号RTS迁移时设置
rq_psn期望收到的对端初始包序号RTR迁移时设置
rq_pkey_index分区键索引Init和RTR迁移时设置
port_num使用的物理端口Init迁移时设置
ah_attr地址信息:LID、GID、SL等RTR迁移时设置
qp_access_flags允许对端执行的远程操作权限Init和RTR迁移时设置
max_rd_atomic本端可发起的RDMA Read/Atomic请求个数上限RTS迁移时设置
max_dest_rd_atomic对端允许到达的RDMA Read/Atomic请求个数上限RTR迁移时设置
timeout重传超时基数,单位为2的指数RTS迁移时设置
retry_cnt传输重试次数上限RTS迁移时设置
rnr_retry接收端未就绪时的重试次数上限RTS迁移时设置
min_rnr_timer接收端空闲时反馈的RNR最短等待时间RTR迁移时设置
path_mtu路径最大传输单元RTR迁移时设置

这个表里最容易忽略的是max_rd_atomic和max_dest_rd_atomic这一对。很多人把QP调通后,跑大块RDMA Read总挂在超时上,最后发现是对端max_dest_rd_atomic配得太小,网卡接收侧积压了大量读请求,无法及时回应。这两个值的含义是分方向的:本端能发多少个并发读,对端能容忍多少个未完成的读,两边必须配合规划。

2.2 发送队列与接收队列:WQE、SGE、WR之间的层级关系

QP内部的SQ和RQ各自是一个环形队列,队列里的每个元素叫WQE(Work Queue Entry),是由软件调用Post Send/Post Receive填充的。WQE内部包含一个或者多个SGE(Scatter/Gather Element),SGE描述了本地内存的地址、长度和lkey。软件接口层通常叫WR(Work Request),内核/用户态驱动负责把WR转换成硬件的WQE格式。

操作的类型由WR中的opcode定义,常见的有:

  • Send:发送报文,需要接收端Post Receive才能接收。
  • Send With Immediate Data:Send的基础带上4字节立即数。
  • RDMA Write:网卡直接读取本端内存写到对端内存,接收端无需Post Receive。
  • RDMA Write With Immediate:写数据同时携带立即数,接收端需要Post Receive来接收立即数。
  • RDMA Read:网卡从对端内存读数据到本端内存,接收端无需Post Receive。
  • Atomic Compare And Swap / Fetch And Add:原子操作,依赖远程MR支持原子权限。

理解WQE和SGE层级很重要:一个SEND请求可能跨越多段不连续内存,SGE把这些内存拼在一起,网卡会按顺序发出;一个RECV请求可能有多段SGE,收到的数据会按SGE顺序被散布到这些缓冲区里。这是RDMA效率高的一个关键点,它把“收集/分散I/O”也卸载到网卡侧了。

2.3 可选的辅助机制:SRQ、XRC、原子操作与多播

真实项目里,单靠一个QP往往不够,还要配合共享接收队列(SRQ)和XRC这样的机制。

SRQ解决的是“接收缓冲区预分配浪费”的问题。多个QP可以共享同一组接收WQE,网卡有数据到达时从SRQ取一个接收缓冲区,用完归还。适合连接数多、但每个连接请求频率低的模型。代价是一个QP的接收操作不再独占缓冲区,接收资源变少,需要监控SRQ的耗尽情况。

XRC(扩展可靠连接)是为了解决RC连接数爆炸的问题。RC需要每对节点维护一个QP,N个节点全互联就要N*(N-1)个QP,内存和QPN空间压力很大。XRC允许接收端共享,多个发端可以复用同一个接收端QP号,配合SRQ可以大幅减少QP数量。

原子操作则是在网卡上直接对远端内存做互斥修改,避免数据来回搬移。支持CAW和FAA两类原子操作,但要同时满足硬件、QP类型、MR权限和MTU对齐四个条件,缺一个都会返回失败。

2.4 资源占用与QP规模设计

QP不是凭空生成的,每个QP都会占用网卡的QPN空间、硬件内存、异常处理资源。常见网卡的QP数上限从几万到几十万不等,但实际能跑满的资源还受CPU、RDMA缓存、CQ深度等限制。

我负责任地提醒一句:QP数量规划要从并发模型出发。无状态服务可以几十个连接共享一个QP?不行,QP本质上是连接实体,不能像socket一样多路复用给任意远端。但可以让每个CPU核绑定一个QP,避免多线程抢同一个QP队列;也可以用多个QP并行发送到同一个对端,利用多路径提高带宽利用率。具体做法是:

  • 每个线程尽量独享QP,减少锁竞争。
  • 对端同一服务可以建立几个QP对应不同优先级流量。
  • 根据MTU、延迟、带宽测试结果反推QP深度,而不是盲目给SQ、RQ都开很大的深度。

硬件资源是有限且珍贵的,QP深度不是越大越好。SQ太深会占用内存、增加缓存压力;RQ太深能缓解RNR,但会挤占其他QP的资源。

3. 状态机完全拆解:从Reset到RTS再到错误恢复

3.1 七个状态的完整语义

QP状态机是RDMA里最绕但也最重要的部分。它本质上是一个安全模型:严格控制什么时候能收、什么时候能发、什么时候能修改参数,防止QP在半配置状态下被误操作污染带内数据流。

规范里主要存在这七个状态:

  • Reset:初始状态。QP刚创建或重置后处于Reset,所有收发资源未生效,任何数据都不能收发。
  • Init:初始化状态。QP的接收路径可以进行配置,比如绑定端口、pkey、访问权限,但还不能收发数据。
  • RTR(Ready to Receive):接收就绪状态。QP知道对端的QPN、PSN、路径信息,可以接收来自对端的数据。
  • RTS(Ready to Send):发送就绪状态。QP可以正常发送请求和接收请求,这是正常工作状态。
  • SQD(Send Queue Draining):发送队列排空状态。从RTS迁移到SQD后,新的发送WR不允许追加,已进入SQ的WR继续处理,直到全部完成,用于不停机修改路径等属性。
  • SQE(Send Queue Error):发送队列错误状态。SQ出现错误,但RQ还能继续接收,等待软件进一步处理。
  • Error:错误状态。QP发生致命错误,所有未完成WQE会被flush到CQ,必须Reset后重新配置才能恢复。

从业务角度看,只有RTS才是真正能满负荷工作的状态。其它状态都是过渡态或异常态。

3.2 合法迁移矩阵与动词配置解析

修改QP状态是通过 verbs 的ibv_modify_qp完成的。每次迁移必须携带合法的属性掩码,不能凭运气乱填。

当前状态可迁移到通常需要设置的属性
ResetInitstate、port、pkey_index、access_flags
InitRTRstate、path_mtu、dest_qp_num、rq_psn、ah_attr、max_dest_rd_atomic、min_rnr_timer
InitResetstate
RTRRTSstate、sq_psn、timeout、retry_cnt、rnr_retry、max_rd_atomic
RTRErrorstate
RTSSQDstate
RTSErrorstate
SQDRTS视具体修改内容带相关属性
SQDErrorstate
SQEErrorstate
ErrorResetstate

一个常见错误是试图从Init直接跳到RTS,这在规范里不允许,因为发送路径还没有拿到足够的路径和可靠性参数。也有同学漏了RTR阶段必须设置的min_rnr_timer,导致后续RNR重试行为不符合预期。

每个状态迁移背后都有明确语义:RTR是配置“我被别人发数据时怎么接”,RTS是配置“我怎么向别人发数据”。所以从Init到RTR,必须先交换对端信息;从RTR到RTS,才能设置本端的发送PSN和重传参数。

3.3 典型建链实操序列:两端如何配合走过状态机

下面这套流程是RC连接最常见的握手过程,我做过很多次,可以直接照着抄:

  1. 双方创建QP,QP初始状态是Reset。
  2. 双方各自Modify到Init,设置本端端口、pkey index、允许远端访问的权限。
  3. 双方通过带外通道(比如TCP控制连接)交换信息:本端QPN、本端选择的初始PSN、本端GID/LID。
  4. 双方Modify到RTR,填上对端的QPN、对端PSN、路径MTU、地址属性、允许远端读/原子操作的并发上限。
  5. 双方Modify到RTS,填上本端将要使用的初始发送PSN、超时、重传次数、RNR重试次数。
  6. 完成状态迁移后,开始Post Receive和Post Send,正常的RDMA通信就建立了。

为什么第3步必须交换信息?因为RC是面向连接的,QP并不知道对端的存在。dest_qp_num必须填对端的QPN,rq_psn必须填对端下一个要发送的包序号,这些数据只能通过对端告知。如果两端都盲目地填0,建立出来的连接要么无法匹配,要么会直接因为包序号不匹配被打入Error状态。

注意,步骤4和5中间不需要强制要求对端先做同样的迁移。但应用层应该设计一个二次握手,确保双方都进入RTS后再投递业务请求,否则先发起数据的一端会收到RNR,导致不必要的重试。

3.4 关键时间点:为什么需要交换信息后再往RTR推进

有读者会问:为什么不能创建QP后直接设成RTS?因为RTS之前必须完成RTR阶段的地址解析和路径选择,否则网卡根本不知道该把数据发到哪个端口、走哪条路径,更不知道接收缓冲区在哪。

还有一个核心原因是防错。状态机保证了在连接配置完整前,数据不会错发。比如链路切换、对端QP重建、GID变化,在Reset/Init阶段可以直接废弃,在RTR阶段可以拒绝接收异常包,到RTS阶段才真正“上膛”。这种渐进式上膛设计,与高速硬件里的流水线处理是一致的。

另外,修改QP属性也要依赖状态机:RTR阶段可以安全地改路径参数,但在RTS阶段改路径参数,就要先迁移到SQD,让硬件把正在传输的包处理完,再改参数,然后迁回RTS。如果不这么做,新的路径信息和在路上的包混杂在一起,接收端会得到乱序或不可确认的包,RC连接直接掉链子。

4. 状态转换的异常世界:错误码、超时与恢复策略

4.1 状态转换失败的常见表现

Modify QP失败时的行为有两种:要么函数直接返回非零错误码,要么迁移显示成功但后面传输一直报错。前者相对好查,检查属性掩码和字段值;后者才是真正难缠的。

常见的前者原因包括:

  • 从Reset跳到RTR缺了Init阶段,直接报“invalid state”。
  • 对端QPN填了一个未激活的QPN,报“invalid destination QP number”。
  • rq_psn或者sq_psn超出了24位允许范围。
  • 路径MTU设置得比底层实际传输MTU大,导致分片参数非法。
  • ah_attr里GID Index或者LID没有有效值。

常见“表面成功、实际异常”的原因包括:

  • 本端和对端的初始PSN约定不一致,导致RC的ACK永远匹配不上。
  • 对端没有及时进入RTR状态,本端已RTS并发出请求,收到RNR。
  • max_dest_rd_atomic太小,RDMA Read被对端硬件限制。
  • 两端pkey不一致,报文在分区校验阶段被丢弃。

处理思路是先看Modify返回码,再抓取计数器。不要盲目重建QP,因为90%的问题出在参数没对齐,而不是硬件坏了。

4.2 可靠连接状态下PSN、重试与超时机制如何工作

RC状态机真正跑起来后,可靠性由PSN、重传、超时和重试计数器共同保证。

PSN是包序号,长度24位。每个发送出的请求都带一个PSN,接收端检查PSN的连续性,不连续就认为是包丢失或乱序,发送ACK时会携带下一个期望的PSN。发送端靠ACK滑动发送窗口,若超时未收到ACK,就从最早的未确认包开始重传。

超时值是timeout,它不是一个直接秒数,而是以2为底的指数,实际超时时间大概等于4.096微秒乘以2的timeout次方。这个设计是为了硬件表项紧凑,也为了支持从微秒到秒级的跨度。

retry_cnt是重试计数器,当超时重发次数超过它,QP没有收到ACK,就会进入错误状态,对应的WR状态码是IBV_WC_RETRY_EXC_ERR。RNR则不同,它表示对端收到请求但接收队列没有可用的Receive WQE,于是回一个RNR Nak。如果rnr_retry用尽,还是会进Error状态,但错误码是IBV_WC_RNR_RETRY_EXC_ERR。

生产环境里,RNR多发生在瞬时压力下,可以适当增加RQ深度、用SRQ提前挂好缓冲区、调大rnr_retry。而retry超时要结合网络时延来算,设置太短会导致大量不必要的重传,太长又会让故障发现变慢。

4.3 错误处理的标准流程与WC错误码速查

QP一旦进入Error状态,软件不能继续在这个QP上收发。标准恢复流程是:

  1. 从CQ中Drain所有WC,直到拿到错误WC或空轮询返回。
  2. 关闭应用层业务,在控制面通知对端“本端QP异常”。
  3. 把QP从Error迁移到Reset,清空内部状态。
  4. 重新从Init开始走建链流程:重新交换QPN、PSN,重新Modify到RTR/RTS。
  5. 恢复之前的内存注册、Receive缓冲区和业务逻辑状态。

不要试图从Error状态直接改回RTS,规范不允许,也没有网卡会支持。一定是Error -> Reset -> Init -> RTR -> RTS的完整复位。

WC中的错误码是最直接的排查线索,整理一个速查表:

WC状态含义常见原因
IBV_WC_LOC_LEN_ERR本地长度错误SGE长度配置不正确
IBV_WC_LOC_QP_OP_ERR本地QP操作非法对SEND/READ/ATOMIC等操作的方式不对
IBV_WC_REM_ACCESS_ERR远端访问错误rkey错误、远端权限不够、内存未注册
IBV_WC_REM_INV_REQ_ERR远端请求非法对端发了当前QP不允许的操作
IBV_WC_RETRY_EXC_ERR重传超限路径不通、对端未在监听、超时设置过短
IBV_WC_RNR_RETRY_EXC_ERRRNR重试超限接收端长期没有Post Receive或RQ耗尽
IBV_WC_WR_FLUSH_ERR工作请求被刷新因为QP进入错误状态而导致WR被强制清理

实际调RDMA时,第一次跑RCremote read失败,多半能在WC里看到REM_ACCESS_ERR。这个错误的原因通常非常直白:对端MR注册时没有给远程写/读权限,或者自己填了错误的rkey。排查时先确认两端读写方向和权限是否都对齐。

4.4 实际排查技巧:用工具和日志定位状态机问题

裸调RDMA程序时没有太多内置日志,我习惯在每步Modify之前打印目标属性,在Modify之后立即查询QP的实际状态,用ibv_query_qp对比是否真的到达了目标状态。

还可以通过计数器判断:查看QP被丢弃的包数、RNR数、重传数。网卡工具一般会暴露port级别的port_xmit_discards、port_rcv_errors等计数,在IB/RoCE环境都能拿到。如果发现port_rcv_errors不断增长,八成是报文到了网卡但QP层对不上,比如pkey、QPN、GID不匹配。

另外一个排查方向是抓包。RoCEv2的报文在以太网层是带UDP头的,可以在交换机的镜像端口抓包分析。重点看BTH里的目的QPN和PSN是否和配置一致。如果目的QPN是对的,但PSN对不上,问题基本出在握手信息没有同步;如果QPN都不对,说明交换信息逻辑有bug。

排查过程中,尽量把状态机和相关属性打印成结构化日志。我自己的习惯是每次Modify后用一行文本记录:旧状态、新状态、目标QPN、dest_qpn、PSN、路径信息。这样一旦出问题,交流日志就能秒回放到哪一步断了。

5. 多场景实践中的QP调优与经验

5.1 高性能场景的QP数量规划

高性能场景下,QP数量规划是个平衡题。一个CPU核一个QP,或者一对核共享一个QP,是常见的经验值。因为SQ和RQ的并发访问如果被多个线程共享,势必引入锁和cacheline竞争,直接抵消RDMA的低延迟优势。

QP数量也不是越多越好。假如一个节点需要连2000个远端,用RC就是2000个QP,每QP都要维护发送窗口、重传缓存、PSN状态,硬件资源占用会非常大。此时考虑XRC或者SRQ能显著降低资源压力。实际项目中,我曾经把全互联RC改成XRC加SRQ,QP数量从几万降到几千,网卡缓存命中率明显提升。

容量规划时建议先做压测:在目标硬件上建立1000个QP,看延迟和吞吐的拐点在哪里;再逐个加SQ/RQ深度,找到内存和性能的平衡点。硬件规格说明书上的QP上限只是理论值,实际可用的“有效并发带宽”往往低很多。

5.2 常见误区和避坑建议

我在这块踩过的坑很多,说几个印象深刻的:

第一,不要忽略 RTR→RTS 之前的Post Receive。就算QP已经RTS,接收端没有预先挂Receive缓冲区,发端的Send或者带立即数的写依然会触发RNR。RNR重试用尽后,QP直接进入Error状态。建立连接的测试代码,先Post Receive再切换RTS更稳。

第二,不要随意修改PSN。有些库允许指定PSN,但你如果没有理解PSN的双向语义,修改后很容易踩到“连接建立成功但数据包全丢”的坑。默认用随机或0也是一种选择,但一定要保证两端对得上。

第三,修改QP状态时attr_mask少一位都可能导致隐性问题。比如到了RTR却没带IBV_QP_MIN_RNR_TIMER,网卡会用默认值,通常不是你想要的值。最好把该阶段的mask完整拼好,不要偷懒。

第四,错误恢复不要盲目重建QP。重建前先分析WC错误码、计数器、抓包记录。如果只是RNR瞬时超限,恢复时把接收队列深度调大比换一个QP更有效。

5.3 我习惯的初始化与健康检查代码骨架

下面这段代码逻辑不是某个具体厂家SDK,而是通用verbs流程,可以作为参考模板。关键点是每个阶段检查返回值并打印状态。

struct ibv_qp_attr attr; int mask = IBV_QP_STATE; // Reset -> Init memset(&attr, 0, sizeof(attr)); attr.qp_state = IBV_QPS_INIT; attr.pkey_index = 0; attr.port_num = 1; attr.qp_access_flags = IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_REMOTE_ATOMIC; mask |= IBV_QP_PKEY_INDEX | IBV_QP_PORT | IBV_QP_ACCESS_FLAGS; ret = ibv_modify_qp(qp, &attr, mask); // 交换对端QPN、PSN、GID等信息后 // Init -> RTR memset(&attr, 0, sizeof(attr)); attr.qp_state = IBV_QPS_RTR; attr.path_mtu = IBV_MTU_4096; attr.dest_qp_num = peer_qpn; attr.rq_psn = peer_psn; attr.max_dest_rd_atomic = 16; attr.min_rnr_timer = 0x10; attr.ah_attr.is_global = 0; attr.ah_attr.dlid = peer_lid; attr.ah_attr.sl = 0; attr.ah_attr.port_num = 1; mask |= IBV_QP_PATH_MTU | IBV_QP_DEST_QPN | IBV_QP_RQ_PSN | IBV_QP_MAX_DEST_RD_ATOMIC | IBV_QP_MIN_RNR_TIMER | IBV_QP_AV; ret = ibv_modify_qp(qp, &attr, mask); // RTR -> RTS memset(&attr, 0, sizeof(attr)); attr.qp_state = IBV_QPS_RTS; attr.sq_psn = my_psn; attr.timeout = 14; attr.retry_cnt = 7; attr.rnr_retry = 7; attr.max_rd_atomic = 16; mask |= IBV_QP_SQ_PSN | IBV_QP_TIMEOUT | IBV_QP_RETRY_CNT | IBV_QP_RNR_RETRY | IBV_QP_MAX_RD_ATOMIC; ret = ibv_modify_qp(qp, &attr, mask);

注意这段只是RC连接的核心步骤,实际工程还要加异常处理和重连逻辑。重连逻辑里我会单独封装一个rebuild_qp函数,步骤固定为Error -> Reset -> Init -> RTR -> RTS,并且每一阶段都记录日志。这套骨架在很多项目里都很好用,能很快定位问题。

最后再分享一个小技巧:在测试环境里把QP的错误恢复路径也纳入自动化用例。很多同学只测正常建链,不测错误路径,结果一上生产遇到链路抖动,QP进入Error状态后恢复流程完全不敢动。提前写一个脚本模拟RNR超时、错误WR、对端QP销毁,确认恢复路径稳定,生产环境遇到故障时就会从容很多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 10:07:54

俯拍航拍森林火灾检测数据集:VOC转YOLO与YOLO训练避坑全流程

简介:俯拍航拍森林火灾检测数据集配套文档,面向目标检测算法开发者与森林火灾监测系统设计者,系统介绍一套可用于模型训练和测试的VOCYOLO双格式数据集,解决俯拍场景下火与烟雾的检测定位问题。文档共1个docx文件,压缩…

作者头像 李华
网站建设 2026/10/18 10:06:44

云端订阅、云服务器自建与远程桌面:个人算力环境怎么选?

前两天有朋友在群里抛了个问题,原话是“预算有限,我想搞一台能随时随地用的‘电脑’,到底是直接买云端订阅,还是自己租台服务器折腾,或者干脆买台好电脑放家里、人在外面远程连回来?”这个问题太典型了&…

作者头像 李华
网站建设 2026/10/18 10:06:37

中国电信计算机岗笔试备考全攻略:题型拆解与突击策略

简介:中国电信笔试(计算机岗)资料包,围绕计算机网络高频考点展开,适合备考中国电信及运营商技术岗笔试的应届生与求职者。内容以题库形式呈现,覆盖网络分类、电路交换与分组交换、因特网边缘与核心、客户服…

作者头像 李华
网站建设 2026/10/18 10:03:16

Hadoop+Django+强化学习轨迹数据可视化分析系统实战

1. 选题背景与整体设计思路拆解1.1 这个选题到底在做什么先把标题拆开看:Hadoop Django 强化学习智能体轨迹数据可视化分析系统。这里面其实混了四样东西——大数据存储与计算(Hadoop)、Web 后端与前端展示(Django)、…

作者头像 李华
网站建设 2026/10/18 10:02:36

Python批量提取Word文档图片与嵌入文件实战

简介:这份资源面向需要用Python自动化处理Word文档的开发者与办公自动化爱好者,聚焦于从.docx文件中批量导出内嵌图片与OLE嵌入文件这一具体问题。包内共2033个文件,以908个py源码、880个pyc字节码为主,辅以C扩展头文件、pyd动态库…

作者头像 李华