抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

最近运维同事提出了一个需求:
在上层,我们目前有一个中央配置中心(依托于我们内部的CMDB)用于管理DHCP服务器和PXE相关的的配置和策略(运维平台),以便在需要时可以动态调整;
在下层一个大型数据中心网络中,需要设计一个能够支持十万级节点的DHCP服务器系统,同时还需要兼具PXEServer用于提供PXE启动服务(包括:裸金属装机、无盘启动)。
这个系统需要具备高可用性、可扩展性和负载均衡能力,以确保在高并发环境下能够稳定运行。

在这个量级,传统的单体架构已经无法满足需求,因此需要采用分布式架构来实现dhcp服务的可扩展性和高可用性。

目前,有两类ip分配:纯动态:在地址池中随机分配;纯静态:根据mac地址分配固定ip。

Pxe server:对于特定mac+来自pxe client的请求,我们还需要修改本机的配置文件(grub)用于实现特定配置(如ubuntu,windows,centos)pxe启动,这又涉及到了文件的并发读写。

整体系统实现思路很简单,但要保证一致性还是有一定难度的,下面我将详细描述这个系统的设计思路。

架构

graph TB
    subgraph Center[中心管理服务]
        direction TB
        A[统一IP地址池管理] --> B[动态/静态IP分配引擎]
        B --> C[gRPC服务端]
        D[(IP地址池数据库)]
        A -.-> D
    end

    subgraph Room1[机房A]
        direction LR
        S1[DHCP Server Agent 1] --> G1[gRPC客户端]
    end

    subgraph Room2[机房B]
        direction LR
        S2[DHCP Server Agent 2] --> G2[gRPC客户端]
    end

    subgraph RoomN[机房N]
        direction LR
        S3[DHCP Server Agent N] --> G3[gRPC客户端]
    end

    C <-->|双向流式gRPC| G1
    C <-->|双向流式gRPC| G2
    C <-->|双向流式gRPC| G3

    classDef center fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    classDef room fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    classDef agent fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px

    class Center center
    class Room1,Room2,RoomN room
    class S1,S2,S3 agent

中心管理(我们内部的运维平台):作为大脑,维护全局IP地址池数据库,并内置动态/静态IP分配引擎。所有分配决策均由中心服务做出。

通信机制:通过双向流式gRPC连接,支持中心服务实时推送配置变更,同时各机房Agent可上报状态与请求。

机房集群:每个机房内可部署多个DHCP Server Agent实例,形成高可用集群。所有Agent均以客户端身份与中心建立长连接。

需求核心策略

在接到一个需求时,我们首先要想的是这个需求的目的是什么:很明显,各业务节点都需要从dhcp server获取IP地址用于上网(当前,
有的节点在系统上配置了静态ip,但绝大多数仍然需要动态分配,无论是mac-ip静态绑定还是从地址池中随机分配,都是为了让节点能够上网)。

那很显然,系统要是崩了(含超时、故障等),节点就无法上网了,这就是我们要解决的核心问题 -> 稳定性问题。

如果ip分配冲突了,那么节点受路由,arp策略自然也无法上网了。
这个问题会出现的时机:agent与配置中心配置版本不一致、本地dhcp ippool分配逻辑错误,这就是我们要解决的第二个核心问题 -> 配置一致性问题(边缘节点与配置中心)。

Grub配置文件读写竞态:有的节点正在开机->读取grub配置;此时若云端下发其它节点的pxe配置 -> 并发读写问题。

约束点:配置都放在配置中心,所有的dhcp server agent都从配置中心拉取配置,这基本能够保证一致性,不需要担心传统分布式系统去中心化共识带来的一系列问题,
在纯分布式架构中,各dhcp server节点 需要抢锁选举leader作为事实来源。但在中心-边缘架构中,中央服务是唯一的事实来源。

性能在这个系统里不是主要的考虑点,毕竟请求是很轻量的,对请求响应耗时要求也不高。


好,现在我们开始解决 需求核心策略 提到的关注点。

稳定性问题:

服务自动拉起

这个很好办,搭建一个dhcp 多节点server集群,每节点只负责特定mac段段处理请求,避免冲突。每个节点都可以独立处理请求,互不干扰。
dhcpserver交由systemd托管,宿主机开机、服务挂掉可以自动拉起重试。

断网时网络分区自保

网络断连时,agent无法与中心服务通信,但仍然可以继续提供dhcp服务。
因为agent在本地维护了静态mac-ip映射表和dhcp ip池,能够独立处理请求,但是这有一个期限:在配置中心不可用期间,agent只能基于本地配置提供服务
(时长为2分钟),直到配置中心恢复;如若两分钟内配置中心恢复,agent会立即与中心服务重新建立连接,并同步最新配置;若未恢复,则停止服务并重启。

配置中心:检测到 agent grpc流断开,中央服务立即回收之前授予该 agent 的 ip token池,将其标记为“待分配”,并在 120 秒后授权给其他存活 agent。

配置一致性问题:

配置中心管理 静态macip映射、dhcp ip池、pxe参数,GRUB 模板。由于是双向流,下发必须保证幂等性和顺序性。

静态策略

同步机制:agent启动建立连接时,会携带本地配置版本号,
中心服务会根据版本号判断是否需要下发最新配置。若版本不一致,中心服务会将最新配置推送给agent,确保所有agent的配置保持一致(配置分为全量下发和增量下发)。

双向ack:agent收到配置后,会返回ack给中心服务,中心服务在收到ack后才会认为该agent的配置已更新成功。若未收到ack,中心服务会重试下发,直到成功为止
(对于网络抖动,下发重复配置,agent 依据配置版本号进行幂等忽略)。

直至配置同步完成,agent才会正式对外提供dhcp服务,避免配置不一致导致的ip冲突。

pxe参数与grub

pxe策略:pxe策略不存储于本地,毕竟数十万节点中,pxe dchp请求是少数,我这里采用的策略是收到请求后再去同步拉取响应。

当agent收到请求时,会携带请求的mac地址和pxe请求类型(如uefi/legacy等),
中心服务会根据mac地址查询pxe策略,并将对应的grub配置下发给agent,agent再将配置写入本地grub文件中(需要加文件锁),
确保pxe启动的正确性(读修复)。

动态ip dhcp地址池分配

虽然只有少部分节点是这种分配方式:比如我们有的客户,他们自己管自己虚拟机,没有报mac给我们,但要我们提供分配:即未知mac->动态分配

如果每个请求都同步阻塞等待中央服务,性能虽不至于雪崩,但也绝对不高效。我才用的策略是双向流异步批量仲裁。

在agent启动时,服务端会下发特定ip段(你可以理解为访客段)IP租赁许可证。{Agent_ID: AgentA, 授权IP段: 10.0.1.1~10.0.1.100, 排除: [10.0.1.7], 有效期: 120s, 版本号: 5}
IP 冲突彻底消失,因为中央服务将 IP 段切成互不重叠的“时间片”分配给不同 Agent。
若 Agent A 宕机,其持有的 Token 在 60s 后过期,中央服务可立即将该 IP 段授权给 Agent B(故障转移),且绝不重叠。

agent 会在 pool 内存中做快速fifo分配,毫秒级响应,然后再上报ip-mac分配.
配置中心收到后,会将该分配结果写入数据库,并在下次配置下发时同步给所有agent,确保全局一致性。

当时设计时询问了AI,AI说还有一种极少数情况:若中央服务发现批量日志中的某个 ip 已被其它 agent 的 token 占用
(极少数时钟/逻辑 BUG 导致), 中央服务会立即在 gRPC 流中下发 Force_Revoke(IP, MAC)
指令给当前 Agent。Agent 收到后,必须对该 MAC 主动发送 DHCP FORCERENEW 或拒绝续租,强制纠错(最终一致性兜底),不过我感觉这是不必要的。

并发读写:

PXE启动时,grub配置文件的读写是并发的。为了解决这个问题,我们在agent中实现了文件锁机制。
这样,就算同时收到dhcp请求、grub请求和配置下发,所有操作依然是串行化的,避免了并发读写导致的配置文件损坏或不一致问题。
毕竟,就算pxe dhcp请求再怎么多,量级也不会特别大;而且pxe dhcp请求的bios中设置的超时往往特别长,所以只要加了锁,这个问题的影响是可控的。




本站总访问量:0