本文转载自微信公众号 “五原路 287 点 4 弄”,原文链接https://mp.weixin.qq.com/s/Jc...。
在“千年虫”之前,那些追求“服务永不下线”的方案,比如数据库,是这样的。A、B 两台主机, 通过 SCSI 线缆连接至共享的一台磁盘阵列,运行比如 NCR lifekeeper 这样的软件向客户端呈现一个虚拟的 IP 漂移地址以接入对数据库乃至阵列的读和写请求。初始时 A 主机处于 active 状态, 所有客户的读写请求都物理上由它代为访问阵列柜来完成。B 主机处于 standby 状态, 主要负责提供情绪价值。假使 B 主机在预设的时间段内没有收到预设数量的来自 A 主机的心跳信号,就判断 A 失效了,B 主机便转为 active 状态,收发客户端的读写请求,并代为访问阵列柜 。 从客户角度看,那个漂移 IP 地址似乎从未下线过。而那台共享的磁盘阵列本身尽量硬件冗余, 反正可以卖得贵一点的: 双控,双通道 SCSI 盘并配置 RAID,双外部 SCSI 卡(当年 IBM, NCR 采用企业级 Microchannel 总线 )。这样便得以抵抗名叫“服务中断”这个丧彪了。 当时双机热备份的方案百花齐放,越做越好,A-B 切换的时间也越做越短......
后来,星转斗移,发生了很多事情。业界出现了非常优秀的 hypervisor, 硬件的虚拟化性能爆发, 以太网,3GIO (还记得这个 PCIe 最早的名字吗), RDMA, 纠删码,加上单台服务器价钱大幅下滑, 服务器部署规模惊人,大家对付“服务中断”这个丧彪越来越轻松 ,A+B HA 的方案渐渐不再为人称道了..... 这些后话将来再说。
双机备份的存储方案没有消失。双机热备份的方案其实也在悄悄地进步。超微的一款 storage superserver 就是当下的一个范例。
这是一款基于 X13SEB-TF 主板和 CSE-229TS-R000NP 机箱的双节点系统。定位为 High Availability Storage,NVMe Over Fabrics Solution 和 Artificial Intelligence (AI), 包含了 Dedicated 1GbE Private Ethernet connection for node-to-node communication (Heartbeat)和 24 Hot-swap Dual Port Gen 5 U.2 NVMe SSD bays.
以下是其 X13SEB-TF 主板和 CSE-229TS-R000NP 机箱中板的逻辑图。
右上方紫色框里高亮出了 NTB 技术和双端口 NVMe 盘是该双节点的物理冗余的实现的基础。单从物理冗余角度看, PEX89104 这款 PCIe switch 是主角。
1)其提供了 2x16 的 PCIe 上游通道去 CPU 集成的 Root Complex;
2)其提供了 2x8 的 PCIe 通道的 NTB,通过机箱中板,用来对接其对等的那个节点;
3)其提供了 48 的 PCIe 下游通道,连去中板乃至机箱的存储背板, 支持 24 片双端口 NVMe 盘。
双节点连在一起是这样的。(为了方便描述,南端仅显示了 1 片双端口 NVMe 盘。)
就让 2025 年,从 NTB 开始。
多年来,开发人员一直在使用 PCI、PCI-X 和 PCIe 互连技术的非透明桥接来设计多主机系统和智能 I/O 方案。非透明桥接(non-transparent bridging :NTB)功能实现了两个主机或内存域的隔离,同时允许两台主机或子系统之间的状态和数据交换。
透明桥 NTB 的工作原理
透明桥在多条 PCI 总线之间提供电气隔离。主机通过探索发现 PCI 桥和终端设备来枚举系统。对于透明网桥(TB),带有“Type 1”标头的配置状态寄存器(Configuration Status Register:CSR)通知处理器越过该 PCI 桥继续枚举其下游的其他设备(如图 1 中的 PCI 桥 A、B 和 C 所示)。
这些带有 Type 1 头的桥接器包含用于主总线号、次总线号和从属总线号的 CSR,当主机对 CSR 进行编程时,会定义所有下游设备的 CSR 地址。
通常,这是基于系统的总线架构和设备的连接拓扑来实现的。主机根据总线编号等信息,按照一定的地址分配规则,为每个下游设备的 CSR 分配特定的地址,从而构建起系统的地址映射关系,确保数据传输和设备控制的准确性和高效性。
端点设备的 CSR 中有一个“Type 0”标头,用于通知枚举器(BIOS 或处理器)下游没有其他设备了。这些 CSR 包括用于向主机请求内存和 I/O 孔的基址寄存器(BAR)。
*PCI bus number 的分配
非透明桥 NTB 的工作原理
NTB 提供处理器域分区,并在这些域的内存映射空间之间进行地址转换。这样一来,NTB 在电气隔离上添加了逻辑隔离。使用 NTB,网桥任一侧的设备(比如 PCIe gen5 的 SSD) 从另一侧都不可见,但为处理器域之间的数据传输和状态交换提供了一条路径。
在上图这个例子中,系统主机将通过图 2 左侧分支上的网桥 A 和 B(都是透明的)进行枚举,直到到达端点 X。在右侧分支上,主机将在网桥 D(NTB-D)停止枚举。同样,图右下角的本地 CPU 将通过网桥 E 和 F(均为交换机内的虚拟网桥)枚举并发现端点 Y,但不会尝试发现网桥 D 之外的元素。这就导致形成了两个内存域。
地址转换
在 NTB 环境中,PCI Express 系统需要将地址从一个内存空间转换到另一个内存空间。每个 NTB 端口有两组 BAR,一组用于主级侧,另一组用于次级侧。BAR 用于将地址转换窗口(address translating windows)定义为 NTB 另一侧的内存空间,并允许将事务映射到本地内存或 I/O。
*NTB 中,地址转换窗口(address translating windows)是一种关键机制,用于实现不同 PCIe 域之间的地址映射和数据通信。
地址转换窗口是 NTB 中用于定义一个地址范围的逻辑区域,这个区域建立了源地址空间和目标地址空间之间的映射关系。通过地址转换窗口,系统能够将一个 PCIe 域(源域)中的地址转换为另一个 PCIe 域(目标域)中的对应地址,从而实现两个域之间的数据传输。
不同 PCIe 域可能使用不同的地址空间,地址转换窗口提供了一种方式,将源域的地址映射到目标域的地址,使得设备能够正确地访问另一个域中的资源。
地址转换窗口限定了哪些地址范围的数据可以在两个 PCIe 域之间进行传输,只有落在地址转换窗口所定义地址范围内的事务才会被允许通过 NTB 进行跨域传输,增强了数据传输的可控性和安全性。
在系统初始化时,软件会对 NTB 进行配置,为地址转换窗口设置源地址范围和对应的目标地址范围,以及其他相关的属性(如访问权限等)。这个过程就像创建了一张地址映射表,记录了源地址和目标地址之间的对应关系。
当一个 PCIe 设备发起一个跨域的事务请求时,NTB 会检查该请求的地址是否落在某个已配置的地址转换窗口的源地址范围内。如果是,NTB 会根据预先建立的映射关系,将源地址转换为目标地址,并将事务转发到目标 PCIe 域中的相应设备。
通常通过读写 NTB 的特定配置寄存器来设置地址转换窗口的参数,包括源地址起始值、源地址范围大小、目标地址起始值等。这些寄存器可以由操作系统或设备驱动程序进行访问和配置。
假设在一个包含两个 PCIe 域(域 A 和域 B)的系统中,域 A 中的设备想要访问域 B 中的内存资源。通过配置 NTB 的地址转换窗口,将域 A 中地址范围为 0x1000 - 0x1FFF
的地址映射到域 B 中地址范围为 0x2000 - 0x2FFF
的地址。当域 A 中的设备发起一个对地址 0x1500
的访问请求时,NTB 会将该地址转换为 0x2500
,并将请求转发到域 B 中对应的内存位置。
每个 BAR 都有一个设置寄存器,用于定义窗口的大小和类型,还有一个地址转换寄存器。虽然透明网桥根据总线号转发所有 CSR,但 NTB 设备只接受发给自己的 CSR 事务。有两种转换技术:分别基于直接地址转换(Direct Address Translation)和查找表转换(lookup-table-basedTranslation)。
直接地址转换 Direct Address Translation
在直接地址转换中,所有事务的地址转换方式是,在事务终结所在的 BAR 的基地址上加上一个偏移量。也就是说,通过这种方式把事务的原始地址转换为设备实际可处理的地址。BAR 中的基本翻译寄存器 Base translation registers 用于设置这些翻译。图 3 说明了从主级侧地址映射到次级地址映射的这种转变。
*“这个事务在该 BAR 中终结” 的含义
事务是指一次完整的数据传输操作,比如一次内存读写操作、I/O 操作等。它包含发起方(请求者)和目标方(响应者),以及相关的地址、数据和控制信息。
“这个事务在该 BAR 中终结”意味着一个事务的目标地址(也就是事务要访问的最终地址)落在某个特定的基址寄存器所定义的地址范围内。当发起一个事务时,系统会检查事务的目标地址,看它是否处于某个 BAR 所指定的地址区间内。如果是,就可以说这个事务在该 BAR 中终结(terminates),因为该 BAR 所对应的设备将处理这个事务。
假设一个 PCIe 设备有两个 BAR:
- BAR0 定义的地址范围是
0x1000 - 0x1FFF
。 - BAR1 定义的地址范围是
0x2000 - 0x2FFF
。
如果发起一个内存读事务,其目标地址是 0x1500
,由于 0x1500
落在 BAR0 所定义的地址范围 0x1000 - 0x1FFF
内,那么就称这个事务在 BAR0 中终结。之后,系统会根据这个关系,将事务的地址进行转换,具体转换方式就是在 BAR0 的基地址上加上事务地址相对于 BAR0 起始地址的偏移量,从而完成地址的映射和事务的处理。
基于查表的转换 Lookup Table based Translation
在此方案中,BAR 使用一个特殊的查找表对其窗口内的事务进行地址转换。这种方法在将本地地址映射到主机总线地址方面提供了更大的灵活性,因为地址内索引字段的位置是可编程的,可以调整窗口大小。索引用于为新的内存位置提供高位。
处理器间通信
NTB 还允许网桥两侧的主机通过便签式寄存器(scratchpad registers)、门铃寄存器(doorbell registers)和心跳消息(heartbeat messages)交换有关状态的信息。
- Scratchpad Registers:这些寄存器从非透明桥的两侧都可以读可以写。它们可以在主总线设备和次总线设备之间传递控制和状态信息,也可以是通用读/写寄存器。
- Doorbell Registers:这些寄存器用于将中断从 NTB 的一侧发送到另一侧。这些是软件控制的中断请求寄存器,在非透明桥上的每个接口都有与之相关联的掩码寄存器 (masking register)。这些寄存器可以从网桥的主接口或从接口访问。
- Heartbeat Messages:心跳消息从主主机发送到从主机,以指示主主机仍然处于活动状态。从主机监视主主机的状态,并在检测到故障时采取适当的行动。门铃寄存器是可用于心跳信息的。当从主机未能接收到一定数量的所安排的周期性的心跳消息时,会宣布主主机发生故障。
NTB 中的 doorbell registers、message registers ,便签式寄存器等有相似之处,都可用于系统间通信,但也有区别。doorbell registers 主要用于发送中断事件,message registers 除了可用于信息交换外,还设有特殊的状态位,以防止信息被其他端重写,而 scratchpad registers 更侧重于提供一个简单的、可直接读写的信息交换空间。
举例:Intelligent Adapter Card
ExpressLane PEX 8114 支持 NTB 功能。图 4 显示了使用智能适配器卡的一个主机系统。
在此图中,PEX 8114 的 NTB 端口将适配器卡上的 CPU 与主机 CPU 隔离,但通过前面讨论的寄存器进行通信。
双主机环境
NTB 功能可用于双主机、主机故障转移和负载分享的应用。图 5 说明了如何使用 PEX 8532 NTB 功能隔离了两个主机 CPU 和智能卡的第三个 CPU。
在上述配置中,左侧次 CPU 通过各种 NTB 寄存器监视右侧主 CPU 的状态/心跳。如果主 CPU 发生故障,从 CPU 可以自动升级为主 CPU 并隔离故障 CPU。
多主机系统
在现代存储系统中,部署了多主机/CPU。这些 CPU 需要访问不在其地址域中的那些端点。设计人员面临的挑战是隔离这些 CPU,既使它们不会相互干扰,又允许它们能够访问所有端点,而不会丢失对其事务的跟踪。这个概念也被称为虚拟 I/O(Virtual I/O :VIO)。
PEX 8532 和 PEX 8516 中实现了 NTB 功能,使设计人员能够将这些 CPU 与多个非透明桥设备隔离开来,同时允许这些 CPU 与所有端点通信。图 6 展示了 PEX 8532 和 PEX 8516 的通用使用模型。在枚举周期中,每个端点都将与一个特定的 CPU 相关联。然而,在正常运行中,NTB 地址转换功能将允许所有 CPU 与所有端点通信。
小结:
PCIe 架构模型的一个局限性是它只允许一个根,并且根和所有端点(EP)必须共享一个公共地址空间。在许多应用中,需要将两个独立的 PCI 域互连。非透明网桥(NTB)实现了这种域间通信,促进了不同交换机分区中设备之间的通信。此功能使主机和 EP 都能向另一个交换机分区中的主机和/或 EP 发起事务。
借用 Nvidia 的例子来一睹如何建立一个 NTB 连接。
第一步:操作系统内核支持检查。
打开 Linux 内核配置文件(通常位于/usr/src/linux/.config ),检查是否包含对 NTB 功能的支持。相关配置选项可能包括 CONFIG_PCI_NTB 等,确保这些选项被正确选中。
第二步:加载驱动模块 。
引用在 ubuntu 下的 Nvidai 例子。
- modprobe ntb 是在 Linux 系统中用于加载 ntb(Non-Transparent Bridge,非透明桥接)内核模块的命令。ntb 模块实现了 NTB 协议的核心功能,包括设备的初始化、数据传输的管理等。
- modprobe switchtec:switchtec:这是一个 NV 特定的内核模块名称。switchtec 模块通常与 Mellanox Technologies 的 Switchtec 技术相关。switchtec 模块提供了与 Switchtec 设备进行交互的接口,使得 Linux 系统能够识别、配置和管理这些设备。
- modbprobe ntb_hw_switchtec:这是一个 NV 特定的内核模块名称。从名称推测,ntb_hw_switchtec 模块可能与 Non-Transparent Bridge(NTB,非透明桥接)硬件和 Mellanox Technologies 的 Switchtec 技术相关。
- Modprobe ntb_transport:ntb_transport 模块提供了 NTB 通信所需的传输层支持。
- Modprobe ntb_netdev:加载 ntb_netdev 模块来提供相应的驱动支持。
第三步:lspci , 检查 PCIe switch 是否对系统可见了。
第四步:测试 NTB 接口和对等 NTB 接口之间连接是否起来。
在很多情况下,NTB 可能会被视为网络设备。可以使用网络配置工具(如 ip
命令)为 NTB 接口分配 IP 地址,再用 ping 来测试两端设备是否可以成功相互通信。
至此,在 PCI 层面,NTB 已经成功连通了。
用户空间编程
好吧 ,我们应该能够将节点 1 的 NVMe 的 BAR 映射到 NT 端口后面的节点 2 主机了。但是,在节点 2 上将节点 1 的 NVMe 盘视为典型的 NVMe 设备(如层次结构下的 PCIe 设备)仍然是不可能的,因为 NT 只不过是两个背靠背连接的端点…...
使用 C 或其他编程语言编写用户空间应用程序,通过系统调用(如 mmap 、read、write 等)与 NTB 设备进行交互。
@唐僧_huangliang 注:最后讲一下我为什么转载这篇文章吧:)
10 年前,唐僧当时所在的公司有点想扩大业务范围,虽然最终没出产品吧,但当年跟龚总和黄总在一起还是有点愿景的。其中一个构想是研发国产集群 NAS,就是用分布式文件系统啦;还有一个是基于 ZFS 做个双控盘阵。
当时 NVMe SSD 还不普及,双控制器阵列用 SAS 共享背板即可。ZFS 本质上是单机文件系统,所以只能做到主/备 HA,有以太网心跳就够了。
相比之下,本文中讲的 SuperMicro 这机型,2 个服务器节点间还有 PCIe/NTB 互连,可以作为一款通用双控 SAN 存储系统的硬件了。如果我在 10 年前看到估计会挺喜欢的。
而在今天,传统双控形态存储阵列的市场,应该被分布式/软件定义存储吃掉了一些。简述其原因:一方面是有 Ceph 等开源软件,虽不见得很好用但至少可以作为自研的参考;另一方面,就是 HyperScale 大型互联网/云服务商的兴起,人们更倾向于用通用化而不是专用的硬件(制造批量影响着成本)。
后续我想跟大家讲讲替代方案,其实也是成熟的存储产品,先透露一点方向吧:
1、从双端口 NVMe 背板 SSD 共享访问——到 NVMe-oF Shared-Everything 驱动器共享(我在《AI 时代的高端文件存储系统:IBM、DDN、Weka 和 VAST》中谈过一些);
2、NTB 写缓存镜像——可以用 RDMA 网络来替代,以太网是更适合大规模拓扑的。
扩展阅读:《企业存储技术》文章分类索引更新(微信公众号合集标签)
END
作者:爷儿∙王
原文:企业存储技术
推荐阅读
- 在 Azure MI300X GPU 虚机上运行 DeepSeek-R1
- AI 时代的高端文件存储系统:IBM、DDN、Weka 和 VAST
- 一次无需调优的测试:SMT多线程对存储服务器IOPS的贡献
- zStorage 分布式存储系统的性能分析方法
欢迎关注企业存储技术极术专栏,欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。