接上期
3.2.3 PolarCtrl
PolarCtrl 是一个PolarFS 集群的控制面板,它至少需要部署在三台以上的机器上提供高可用的服务,PolarCtrl 的工作职责是什么:
1 提供集群控制服务,节点管理,容量管理,资源管理, 元数据同步管理,监控等等,Polarctrl 是一个对chunkserver 存活和跟踪其中成员关系的功能模块,同时针对当chunkserver 过载或者由于超时服务等故障后的发起的chunk复制中的从一个服务器中到另一个服务器发生融合。
2 维护数据库中元数据的卷和本地chunk的位置信息。
3 创建卷和访问 chunk server中的卷
4 使用推或拉的方式同步元数据到polarswitch
5 监控卷中的延迟状态和IOPS指标,沿着I/O路径收集跟踪数据
6 定期调度副本内部和副本之间的数据校验
Polarctrl 需要定期同步集群中的元数据信息,如通过控制平面命令使用polarswitch ,通过polarswitch 将元数据保存到本地缓存中,当接受到来自libpfs的 I/O请求时,Polarswitch 根据本地缓存将请求路由到响应的chunkserver中。如本地缓存失效,PolarSwitch会从polarctrl 中获取元数据。
在设计中,Polarctrl是一个控制面板,所以本身不在I/O 核心的路径上,他的高可用的技术可能会比较传统,因为即使polarctrl崩溃的话到在此恢复的过程中,也不会对系统有太多影响,主要基于chunkserver 自我对缓存元数据的管理,同时PolarFS中的I/O的工作也不会受到太大影响。
4 I/O Execution model
在POLARDB 被访问的时候,访问他的数据是通过POLARFS 中的接口将文件的IO请求提交给libpfs,通过PFS read 或者 write 线程来访问,对于写请求,是不需要修改文件系统中的元数据的,主要的原因是设备的块早就使用预分配的方式通过pfs_fallocate 预分配给文件了。所以避免了写入和读取节点之间的昂贵的元数据同步。
在大多数常见情况下,libpfs只是根据挂载时已经构建的索引表将文件偏移量映射到块偏移量,并将文件I/O请求切成一个或多个较小的固定大小的块I/O请求。转换完成后,块I/O请求由libpfs发送到通过它们之间的共享内存进行PolarSwitch。
在共享内存这面,共享内存被构造为多个环形buffer,libpfs 的IO请求是以排队的形式在环形的缓冲区中进行任务的选取,然后等待其完成,在另一端Polarswitch 不断轮询所有环形缓冲区,有一个线程专门用于环形缓冲区。一旦发现了新的请求,PolarSwitch就会从环形缓冲区中将请求从队列中解出,并将它们与从PolarCtrl传播的路由信息一起转发给chunkserver。
Chunkserver使用预写日志(write ahead logging, WAL)技术来确保原子性和持久性,在这种技术中,I/O请求在提交和应用之前被写入日志。日志被复制到一个副本集合中,并使用名为ParallelRaft的共识协议(下一节将详细介绍)来保证副本之间的数据一致性。除非I/O请求被持久地记录到大多数副本的日志中,否则不会被识别为已提交。只有在此之后,此请求才能响应到客户机并应用到数据块上。
图四中展示出了一个写I/O 如何是在内部进行运转的,
1 Polardb 发送了一个写IO需求给polarswitch 在polarswitch和libpfs之间,通过 ring buffer 缓冲。
2 根据本地传输需求PolarSwitch将相应的请求传输到对应的lead节点。
3 当新的写请求到达时,leader节点中的RDMA网卡将把写请求放入预注册的缓冲区中,并在请求队列中添加一个请求条目。I/O循环线程持续轮询请求队列。一旦它看到一个新的请求到达,它就会立即开始处理这个请求。
4 通过SPDK将请求写入磁盘上的日志块,通过RDMA传播到从动节点。这两个操作都是异步调用,实际的数据传输将并行触发。
5 当复制请求到达跟随节点时,跟随节点中的RDMA NIC也将把复制请求放入预注册的缓冲区中并将其添加到复制队列中。
6 此时I/O 在 follower上的LOOP 线程被触发了。写的需求异步通过 SPDK写入到磁盘上。
7 当写操作成功后,通过RDMA 网络将写入成功的信号返回给 leader 节点。
8 当写成功收到大部分从库的信号并被传回到leader节点后,数据通过SPDK写入到主节点的数据块中。
9 在数据写入后,leader 通过RDMA 来回复 polarswitch
10 Polarswitch 标记工作已经完成,并通知发起请求的客户端。
读I/O请求主要由leader单独处理。在ChunkServer中有一个名为IO Scheduler的子模块,它负责仲裁通过并发I/O请求发出的磁盘I/O操作的顺序,在ChunkServer上进行执行。IO Scheduler保证读操作总是可以检索最新提交的数据。
ChunkServer使用轮询模式和事件驱动的有限状态机作为并发模型。I/O线程保持来自RDMA和NVMe队列的轮询事件,在同一个线程中处理传入的请求。当发出一个或多个异步I/O操作并需要处理其他请求时,I/O线程将暂停处理当前请求并将上下文保存到状态机中,然后切换到处理下一个传入事件。这里单个I/O线程会使用一个专用的核心,并使用分离RDMA和NVMe队列。因此,实现一个I/O线程没有锁定开销,因为I/O线程之间没有共享数据结构,即使在单个ChunkServer上有多个I/O线程。