IT评测·应用市场-qidao123.com技术社区
标题:
RDMA栈架构
[打印本页]
作者:
莱莱
时间:
2025-4-16 18:54
标题:
RDMA栈架构
一、RDMA基础知识
远程直接内存访问(RDMA,Remote Direct Memory Access),指可以或许访问(即读写)远程机器的内存。有多种支持 RDMA 的网络协议,包罗:Infiniband、RoCE 和 iWARP。
1.
RDMA技能架构与焦点组件
一、架构分层与焦点组件
RDMA(Remote Direct Memory Access)技能通过
绕过内核协议栈
和
零复制
机制实现高效数据传输,其架构分为
用户空间
和
内核空间
两部分,焦点组件和流程如下:
1. 用户空间组件
用户空间套接字API
:
提供类似传统Socket的编程接口,但专为RDMA优化。比方,应用程序可通过ibv_post_send()直接提交RDMA操作哀求,无需通过内核协议栈。
示例
:分布式数据库(如Redis)使用此API直接向远程节点内存写入数据,避免内核拷贝。
用户Verbs(libibverbs)
:
RDMA的焦点API库,函数名以ibv_为前缀(如ibv_create_qp创建队列对)。支持三种协议:
Infiniband
:原生RDMA协议,高性能但需专用硬件。
RoCE(RDMA over Converged Ethernet)
:通过以太网承载RDMA,兼容通例网络设备。
iWARP(Internet Wide Area RDMA Protocol)
:基于TCP/IP实现RDMA,支持广域网但耽误较高。
示例
:云计算平台(如AWS)使用RoCE在以太网中实现虚拟机间低耽误通讯。
2. 内核空间组件
内核Verbs
:
提供内核态RDMA驱动支持,管理硬件资源(如队列对QP、内存注册MR)。
示例
:当用户调用ibv_reg_mr()注册内存时,内核Verbs会锁定物理内存页供网卡直接访问。
CM(Connection Manager)
:
负责创建和维护RDMA连接,包罗互换通讯参数(如QP号、GID)。
示例
:两台服务器通过CM互换元数据后,可直接通过QP举行RDMA读写,无需TCP三次握手。
RDS(Reliable Datagram Sockets)
:
提供可靠的数据报传输服务,支持多播和原子操作。
示例
:金融生意业务体系使用RDS确保订单数据的可靠性和同等性。
可替换短框套接字
:
一种轻量级传输层协议,减少协议头开销,提拔小包传输服从。
示例
:高频生意业务场景中,短帧协议将64字节订单的传输耽误从10μs降至2μs。
3. Linux内核与用户空间交互
零复制(Zero-Copy)
:
应用程序通过ibv_reg_mr()注册内存后,网卡可直接读写用户态内存,
无需内核到场数据拷贝
。
示例
:HDFS使用RDMA零复制加速跨节点数据块传输,吞吐量提拔3倍。
CPU卸载
:
RDMA操作(如数据传输、CRC校验)由网卡硬件完成,
CPU仅负责提交哀求
。
示例
:AI训练集群中,GPU通过RDMA直接互换梯度数据,CPU使用率降低70%。
二、RDMA技能优势与实现原理
1. 高带宽
原理
:RDMA绕过内核协议栈,减少TCP/IP处置惩罚开销;支持大报文(如4KB~1MB)传输。
示例
:NVMe over Fabrics(NVMe-oF)使用RDMA实现存储网络100Gbps带宽,时延低于10μs。
2. 低耽误
原理
:
零复制
:数据不经过内核缓冲区。
硬件卸载
:网卡直接处置惩罚传输使命。
示例
:证券生意业务所的订单匹配体系接纳RDMA,端到端耽误从50μs降至5μs。
3. 跳过内核(Kernel Bypass)
原理
:用户态程序通过Verbs API直接操作网卡,无需上下文切换。
示例
:分布式内存数据库(如Memcached)通过RDMA实现内存级远程访问,QPS(每秒查询数)提拔至百万级。
4. 减少CPU负担
原理
:数据传输和协议处置惩罚由网卡完成,CPU仅初始化操作。
示例
:视频流服务器使用RDMA后,CPU占用率从80%降至20%,可同时处置惩罚更多并发哀求。
三、协议对比:RoCE vs. iWARP vs. Infiniband
特性
Infiniband
RoCE
iWARP
网络介质
专用InfiniBand网络以太网(需支持DCB/PFC)TCP/IP网络
耽误
<1μs2~5μs10~50μs
适用场景
HPC超算中央数据中央(融合网络)跨广域网企业应用
设置复杂度
高(需专用互换机)中(需优化QoS)低(兼容现有网络)
示例
:
超算中央
:使用Infiniband连接GPU集群,训练ResNet-50模型时间缩短30%。
云数据中央
:接纳RoCE v2(基于UDP)构建存储网络,兼容现有25G/100G以太网。
跨地域备份
:通过iWARP在AWS差别地区间同步数据库,使用TCP/IP确保可靠性。
四、典范应用场景
1. 分布式存储
Ceph RDMA
:通过Librados直接读写OSD节点内存,IOPS提拔至百万级。
示例
:微软Azure的存储加速服务接纳RDMA,耽误低于1ms。
2. 高性能计算(HPC)
MPI over RDMA
:MPI库(如OpenMPI)使用RDMA加速历程间通讯。
示例
:天气模拟软件WRF通过RDMA将计算节点间通讯时间减少60%。
3. 人工智能训练
GPU Direct RDMA
:NVIDIA GPUDirect技能答应GPU显存直接到场RDMA传输。
示例
:Meta训练LLaMA模型时,RDMA使GPU间梯度同步时间从20ms降至2ms。
五、挑战与限制
网络设置复杂度高
:
RoCE需启用PFC(优先级流控)和ECN(显式拥塞通知)以避免丢包。
示例
:某银行因未设置PFC导致RoCE网络拥塞,生意业务耽误飙升至100ms。
硬件依赖性强
:
需要支持RDMA的网卡(如Mellanox ConnectX-6)和互换机。
示例
:阿里云神龙服务器搭载自研RDMA智能网卡,实现虚拟化层零损耗。
安全机制不足
:
RDMA默认不加密传输,需结合TLS或IPSEC。
示例
:国防体系接纳RoCE+国密算法加密,保障数据传输安全。
2.具体数据结构以及使用
具体 API 定义包罗在内核文件如下:
头文件ib_verbs.h中包罗的函数和结构可供如下内容使用:
1.RDMA栈本身
2.RDMA设备的低级驱动程序
3.作为消耗者使用RDMA栈的内核模块
一、焦点数据结构与API解析
头文件 ib_verbs.h
是RDMA内核开发的焦点,定义了RDMA协议栈的
关键数据结构
和
操作接口
。以下结合代码片断重点解析:
1. 焦点数据结构
union ib_gid(全局标识符)
:
union ib_gid {
u8 raw[16]; // 128位GID原始数据
struct {
__be64 subnet_prefix; // 子网前缀(64位)
__be64 interface_id; // 接口标识(64位)
} global; // 结构化GID
};
复制代码
作用
:唯一标识RDMA网络中的设备,类似IP地点。比方,RoCEv2中GID与IPv6地点映射,实现以太网上的RDMA通讯。
示例
:在云计算中,虚拟机通过GID区分差别租户的RDMA资源,避免地点辩论。
工作队列(Work Queue)
:
extern struct workqueue_struct *ib_wq; // 通用工作队列
extern struct workqueue_struct *ib_comp_wq; // 完成事件工作队列
复制代码
作用
:异步处置惩罚RDMA操作(如发送/接收哀求、完成变乱通知)。
示例
:当网卡完成数据传输后,通过ib_comp_wq触发用户态回调函数。
二、使用场景与案例解析
1. RDMA栈本身
功能
:实现RDMA协议的焦点逻辑,包罗连接管理、内存注册、队列对(QP)操作等。
关键API与操作
:
ib_register_client()
:注册RDMA客户端(如存储驱动)。
ib_alloc_pd()
:分配掩护域(Protection Domain),隔离差别应用的内存访问权限。
案例:Kubernetes容器网络
场景
:容器集群需要跨节点直接访问内存,加速AI训练使命。
实现
:
RDMA栈通过ib_core模块管理容器间的QP和MR(内存地区)。
使用ibv_reg_mr()注册容器内存,答应其他节点直接读写。
效果:TensorFlow分布式训练时,梯度同步耽误从15ms降至1ms。
2. RDMA设备的低级驱动程序
功能
:驱动物理网卡(如Mellanox ConnectX系列),实现硬件与RDMA栈的交互。
关键API与操作
:
ib_register_device()
:注册网卡设备到RDMA子体系。
ib_post_send()
:将数据传输哀求提交至网卡硬件队列。
案例:Mellanox网卡驱动优化
场景
:金融高频生意业务需亚微秒级耽误。
实现
:
驱动程序通过mlx5_core模块直接操作网卡寄存器,启用“Cut-Through”模式,减少数据包处置惩罚步调。
使用ibv_create_qp()创建无状态QP(Queue Pair),跳过ACK确认。
效果:订单传输耽误从3μs降至0.8μs。
3. 作为消耗者使用RDMA栈的内核模块
功能
:其他内核模块(如存储、网络协议)调用RDMA接口实现高性能数据传输。
关键API与操作
:
rdma_bind_addr()
:绑定本地GID和端口号。
rdma_listen()
:监听远程连接哀求。
案例:NVMe over Fabrics (NVMe-oF)
场景
:企业级分布式存储需低耽误块存储访问。
实现
:
nvme-rdma内核模块调用ibv_create_cq()创建完成队列(CQ),接收IO完成变乱。
使用ibv_post_recv()预注册接收缓冲区,实现零拷贝数据存取。
效果:SSD跨节点读写带宽达100Gbps,时延低于10μs。
内核的RDMA栈全部代码位于内核树:CM(通讯管理器)、verbs(内核verbs)等等。
二、Infiniband基础
1.根本概念
InfiniBand技能不是用于我们常见的网络连接,重要目标是用于服务器端的连接,InfiniBand技能应用于服务器与服务器、服务器跟存储设备。通过InfiniBand传输数据时,数据是以数据包的方式传输,这些数据包会组合成一条一条信息。这些信息操作方式可能作为远程直接内存存取的读写程序。
一、InfiniBand 的根本概念
InfiniBand(直译是“无线带宽“”技能,”简称 IB)是一种专为高性能计算计划的网络通讯标准,焦点目标是实现
高吞吐量
和
低耽误
。它广泛应用于超级计算机、数据中央和分布式存储体系,可以或许高效连接服务器、存储设备等硬件。
二、速率优势:全双工 vs. 半双工
理论带宽对比
InfiniBand 1.x
:基础速率为
2.5 Gb/s(单通道)
,支持
全双工
模式,即双向同时传输数据。因此,理论总带宽为
5 Gb/s(2.5 Gb/s × 2)
。
PCI 总线
:
32 位、33 MHz PCI 总线:单方向理论带宽
1 Gb/s
(半双工,同一时间只能单向传输)。
64 位、133 MHz PCI-X 总线:单方向理论带宽
8.5 Gb/s
(仍为半双工)。
关键差异
:
全双工 vs. 半双工:InfiniBand 的双向同步传输明显提拔了实际可用带宽。
实际性能:固然理论值 PCI-X 更高,但由于协议开销和半双工限制,InfiniBand 的实际吞吐量更优。
后续版本升级
InfiniBand 已迭代至更高版本(如 HDR、NDR),单通道速率可达
200 Gb/s 乃至 400 Gb/s
,远超早期标准。
三、虚拟高速公路与虚拟通道
虚拟通道(Virtual Lanes, VL)
功能
:类似于高速公路的“多车道”,通过逻辑划分物理链路,为差别优先级的流量分配独立通道。
优势
:
服务质量(QoS)
:保障高优先级流量(如及时数据)的带宽和低耽误。
避免拥塞
:低优先级流量(如备份数据)不会阻塞关键使命。
实现原理
字节位元组(Credit-Based Flow Control)
:
通过“名誉机制”控制数据传输速率,确保接收端有足够缓冲空间,避免丢包。
结合优先级标记(Priority Tagging),动态分配虚拟通道资源。
物理链路复用
:同一对物理线缆可承载多个虚拟通道的流量,提拔资源使用率。
子网管理器(Subnet Manager, SM)
焦点脚色
:负责设置和管理虚拟通道,包罗:
分配带宽和优先级。
监控网络状态,动态调解资源。
确保网络拓扑的稳定性和高效性。
四、InfiniBand 的焦点优势总结
特性
InfiniBand
传统 PCI/PCI-X
传输模式
全双工(双向同步)半双工(单向瓜代)
耽误
极低(微秒级)较高
扩展性
支持大规模集群互连限于本地总线连接
适用场景
高性能计算、分布式存储传统服务器内部设备连接
2.InfiniBand硬件组件_编址
InfiniBand根其他互联技能一样,它的规范页描述多种硬件组件,其中一些事数据包端点(数据的始发站大概目标地),有些会在子网或子网之间转发数据包。
常见组件 :主机信道适配器(HCA)、互换机、路由器。
Infiniband编址:组件唯一是GUID,全球唯一的64位值。GID用于表示端点端口或组播组。LID是一个16位值,子网管理器给每个子网端口都分配一个LID。
一、GUID(全局唯一标识符)
GUID(Global Unique Identifier)是 InfiniBand 网络中用于标识硬件组件的基础唯一标识符,具有全局唯一性和永世性。
1.
分类与功能
结点GUID(Node GUID)
定义
:每个 InfiniBand 结点(如服务器、存储设备)的全局唯一标识符,与硬件绑定,永不改变。
示例
:一台服务器的结点GUID可能是 0x0002c9030020abcd。
端口GUID(Port GUID)
定义
:每个物理端口(如主机通道适配器 HCA、互换机端口)的唯一标识符,同样永世不变。
示例
:一台互换机的第 1 个端口GUID可能是 0x0002c9030020abce,第 2 个端口为 0x0002c9030020abcf。
体系GUID(System GUID)
定义
:由多个组件(如刀片服务器中的多个结点)组成的体系共享的统一标识符。
示例
:一个刀片机箱内全部刀片服务器共享同一个体系GUID 0x0002c9030020abcc。
2.
作用
唯一性
:确保网络中每个结点和端口可被唯一识别。
硬件绑定
:GUID 固化在硬件中,即使设备更换子网,标识符仍不变。
二、GID(全局标识符)
GID(Global Identifier)是端口的逻辑标识符,用于在全局范围内寻址端口。它与子网相关,可动态生成。
1.
生成规则
基础 GID(索引0)
:每个端口至少有一个 GID,位于 GID 表的索引0处,由以下两部分组成:
子网前缀(Subnet Prefix)
:子网的唯一标识符(如 0xfe80::)。
端口GUID
:通过算法将端口GUID转换为 IPv6 格式的后缀。
示例
:
子网前缀:fe80::
端口GUID:0002c9030020abce
完备 GID:fe80::0002:c903:0020:abce
2.
应用场景
跨子网通讯
:GID 支持全局路由,答应差别子网中的设备直接通讯。
IPv6 兼容性
:GID 格式与 IPv6 兼容,便于与 IP 网络集成。
三、LID(本地标识符)
LID(Local Identifier)是子网内的本地地点,由子网管理器动态分配,仅在同一子网内有用。
1.
分配规则
单播 LID
:范围 0x001 至 0xbfff(共 14,335 个地点),用于一对一通讯。
组播 LID
:范围 0xc000 至 0xfffe(共 16,383 个地点),用于一对多通讯。
互换机特殊性
:互换机仅管理端口(用于控制)分配 LID,数据端口不分配。
2.
示例场景
单播示例
:
服务器 A 的 HCA 端口分配 LID 0x001。
服务器 B 的 HCA 端口分配 LID 0x002。
两者通过单播 LID 直接通讯。
组播示例
:
组播组分配 LID 0xc001。
服务器 A、B、C 加入该组,数据包发送到 0xc001 时,全部成员同时接收。
四、GUID、GID、LID 的关系与区别
标识符
作用范围
唯一性
生成方式
示例
GUID
全局硬件唯一,永世硬件固化结点GUID: 0x0002c9030020abcd
GID
全局子网相关,动态子网前缀 + 端口GUIDfe80::0002:c903:0020:abce
LID
子网内子网内唯一,动态子网管理器分配单播 LID: 0x001
五、实际应用案例
场景:高性能计算集群
硬件连接
:
10 台服务器通过 InfiniBand 互换机互连,组成一个子网。
每台服务器的 HCA 端口有唯一的端口GUID,如 0x0002c9030020abce 至 0x0002c9030020abd7。
子网管理器设置
:
子网管理器为每个 HCA 端口分配单播 LID(如 0x001 至 0x00A)。
互换机管理端口分配 LID 0x100。
通讯过程
:
服务器 A(LID 0x001)向服务器 B(LID 0x002)发送数据时,使用单播 LID 直接寻址。
若需广播计算效果,发送到组播 LID 0xc001,全部加入该组的服务器同时接收。
3.InfiniBand功能_数据包
InfiniBand 协议功能:
答应设置 HCA、互换机和路由器的端口所属的分区,从而在物理子网内实现虚拟隔离;
涉及队列键(Queue Key)、虚拟通道(Virtual lanes VL);
包罗服务等级(Service Level SL)、故障切换。
一、队列键(Q_Key)
Q_Key(Queue Key)
是 InfiniBand 中用于验证不可靠通讯的密钥,确保只有授权的队列对(QP)可以接收数据。
1.
焦点作用
验证通讯权限
:两个不可靠的 QP 必须设置相同的 Q_Key 才能相互收发单播或组播消息。
防止未授权访问
:类似于密码机制,避免非目标 QP 接收数据包。
2.
应用场景
不可靠通讯(Unreliable Datagram, UD)
:
适用于容忍丢包的场景(如广播通知、及时流媒体)。
示例:集群中多个节点接收同一组播消息时,需全部节点 QP 设置相同的 Q_Key。
3.
设置示例
节点 A 的 QP 设置 Q_Key 0x1234,节点 B 的 QP 也设置 0x1234,两者可相互通讯。
若节点 C 的 QP 设置 0x5678,则无法接收 A/B 的消息。
二、虚拟通道(Virtual Lanes, VL)
虚拟通道(VL)
是一种在物理链路上划分逻辑通道的机制,用于隔离差别优先级的流量并分配资源。
1.
焦点功能
流量隔离
:将物理链路划分为多个虚拟通道(类似高速公路的车道),每个 VL 对应独立的缓冲区。
资源分配
:每个端口支持的 VL 数量是硬件属性(如支持 4 个 VL)。
2.
实现原理
缓冲区管理
:每个 VL 有独立的发送和接收缓冲区,避免高低优先级流量相互阻塞。
物理链路复用
:同一对物理线缆可承载多个 VL 的数据(如 VL0 传输高优先级控制信令,VL1 传输平常数据)。
3.
应用示例
高性能计算集群
:
VL0:用于 MPI 历程间同步消息(高优先级,低耽误)。
VL1:用于文件传输(低优先级,答应耽误)。
三、服务等级(Service Level, SL)
服务等级(SL)
是 InfiniBand 中定义流量优先级的参数,支持 16 个等级(0~15),通过映射到 VL 实现服务质量(QoS)。
1.
QoS 实现机制
SL 到 VL 的映射
:子网管理器将差别 SL 的流量分配到差别 VL,并为每个 VL 分配带宽和缓冲区资源。
示例:SL15 映射到 VL0(最高优先级),SL0 映射到 VL3(最低优先级)。
资源分配策略
:
高优先级 VL 分配更多带宽和缓冲区,确保低耽误和高吞吐。
2.
实际应用
混合负载场景
:
SL15:用于及时数据库查询(毫秒级耽误要求)。
SL5:用于批量数据备份(答应秒级耽误)。
四、故障切换(Failover)
故障切换
是 InfiniBand 中实现路径冗余的机制,答应为连接的 QP 定义主路径和备用路径。
1.
工作原理
主路径与备用路径
:
主路径:默认通讯路径(如通过互换机 A)。
备用路径:备用路由(如通过互换机 B)。
自动切换
:当主路径故障(如链路停止),流量自动切换到备用路径,无需人工干预。
2.
实现优势
高可用性
:避免单点故障导致通讯停止。
无缝切换
:应用层无感知,不报告错误。
3.
示例场景
金融生意业务体系
:
主路径:通过焦点互换机,耽误 1μs。
备用路径:通过边缘互换机,耽误 2μs。
若焦点互换机宕机,流量立即切换到边缘互换机,生意业务不绝止。
五、关键机制对比与协同
机制
焦点功能
协同关系
Q_Key
验证不可靠通讯权限确保组播/单播消息的安全性
VL
隔离优先级流量,分配物理资源通过 SL 映射实现 QoS
SL
定义流量优先级依赖 VL 实现资源分配
故障切换
提供路径冗余,保障通讯连续性依赖子网管理器动态调解路径
4.使用RDMA和InfiniBand的两台主机的通讯流程
一、场景描述
假设有两台主机
A
和
B
,通过 InfiniBand 网络互连,目标是实现
主机 A 直接向主机 B 的内存写入数据
(RDMA Write 操作)。以下是具体通讯流程:
二、通讯流程步调
1. 初始化网络环境
硬件预备
:
主机 A 和 B 均安装 InfiniBand 主机通道适配器(HCA)。
通过 InfiniBand 互换机连接两台主机,形成子网。
软件设置
:
安装 InfiniBand 驱动和 RDMA 库(如 libibverbs、librdmacm)。
启动子网管理器(Subnet Manager, SM),完成子网初始化(分配 LID、设置路由表)。
2. 注册内存地区(Memory Region, MR)
主机 B 预备接收数据
:
主机 B 在本地内存中分配一块缓冲区(比方 1MB),用于接收数据。
调用 ibv_reg_mr() 注册该内存地区,生成
内存地区描述符(MR)
,包罗以下信息:
虚拟地点(Virtual Address, VA)
物理地点(Physical Address, PA)
访问权限(如本地写、远程读/写)
内存密钥(Memory Key, rkey/lkey)
示例
:
// 主机 B 注册内存区域
struct ibv_mr *mr = ibv_reg_mr(pd, buffer, size, IBV_ACCESS_REMOTE_WRITE);
复制代码
3. 创建通讯队列对(Queue Pair, QP)
创建 QP
:
主机 A 和 B 分别创建
队列对(QP)
,包罗:
发送队列(Send Queue, SQ)
:存储待发送的哀求。
接收队列(Receive Queue, RQ)
:存储待接收的哀求。
QP 类型选择
RC(Reliable Connected)
,支持可靠传输。
QP 状态转换
:
RESET → INIT
:初始化 QP 参数(如最大传输单位 MTU、服务等级 SL)。
INIT → RTR(Ready to Receive)
:设置接收端参数(如目标 LID、Q_Key)。
RTR → RTS(Ready to Send)
:设置发送端参数,QP 进入可通讯状态。
互换 QP 信息
:
主机 A 和 B 通过带外通讯(如 TCP/IP)互换以下信息:
QP 号(QP Number)
LID
(本地标识符)
GID
(全局标识符,用于跨子网通讯)
rkey
(远程内存密钥,来自主机 B 的 MR)
4. 主机 A 发起 RDMA Write 操作
构造工作哀求(Work Request, WR)
:
主机 A 在发送队列(SQ)中提交一个 RDMA Write 哀求,包罗:
目标内存地点(主机 B 的 MR 虚拟地点 + 偏移)。
数据长度(如 1MB)。
远程密钥(rkey,由主机 B 提供)。
目标 QP 号(主机 B 的 QP)。
触发硬件实行
:
HCA 直接从主机 A 的内存中读取数据,封装为 InfiniBand 数据包,通过物理链路发送。
数据包结构
:
BTH(Base Transport Header)
:包罗目标 LID、QP 号、操作码(RDMA Write)。
RETH(RDMA Extended Transport Header)
:包罗远程地点、长度、rkey。
Payload
:实际数据。
5. 数据通过 InfiniBand 网络传输
路由过程
:
互换机根据目标 LID 查找路由表,将数据包转发到主机 B 的 HCA。
虚拟通道(VL)与服务质量(SL)
:
数据包的 SL 映射到特定 VL(如 VL0),确保高优先级流量低耽误传输。
6. 主机 B 接收数据
直接内存写入(Zero-Copy)
:
主机 B 的 HCA 解析数据包,验证 rkey 权限。
数据直接写入主机 B 预先注册的内存地区,
无需 CPU 到场
。
完成通知(Completion Queue, CQ)
:
主机 A 的发送队列和主机 B 的接收队列各生成一个
完成队列元素(CQE)
,标志操作完成。
应用程序可通过轮询或变乱驱动方式获取完成状态。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/)
Powered by Discuz! X3.4