Longhorn 是一个轻量级、可靠且易于使用的 Kubernetes 分布式块存储系统,100%开源,可在任何地方运行。
介绍
Longhorn 是一个轻量级且功能强大的云原生 Kubernetes 分布式存储平台,可以在任意基础设施上运行。Longhorn 与 Rancher 结合使用,将帮助您在 Kubernetes 环境中轻松、快速和可靠地部署高可用性持久化块存储。
架构总览:控制面与数据面分离
Longhorn 的设计核心在于微控制器模式(Micro-controller pattern)。
- 控制面 (Control Plane):由
longhorn-manager 负责,处理全局调度、API 响应。
- 数据面 (Data Plane):由
longhorn-instance-manager 及其内部运行的 longhorn-engine 进程负责,直接处理 I/O。
核心服务组件详细解析
以下是核心服务的详细使用总结和底层逻辑:
Longhorn Manager (longhorn-manager) —— 大脑
`longhorn-manager 是指挥官,负责逻辑调度,它的生死不影响现有数据的读写。
- 部署形态:DaemonSet(每个节点运行一个)。
- 功能:
- 它不直接处理数据读写。
- 它监听 Kubernetes API (CRD changes)。
- 它负责调度:决定 Replica 放在哪个节点,决定 Volume 挂载在哪个节点。
- 它通过 gRPC 指挥
longhorn-instance-manager 启动或停止 Engine/Replica 进程。
- 关键点:如果
longhorn-manager 挂了,正在运行的 Volume 不会中断(因为数据面是独立的),但无法执行 Attach/Detach 或创建快照等操作。
Longhorn Instance Manager (longhorn-instance-manager) —— 进程管家
longhorn-instance-manager 是数据面的核心载体。所有的 Engine 和 Replica 都是它肚子里的子进程。运维 Longhorn 最关键的就是保障 Instance Manager 的资源充足且稳定。
- 部署形态:DaemonSet(每个节点运行一个,Pod 名字通常带
instance-manager-xxx 或 e-xxx,新版本已合并)。
- 核心逻辑:
- 这是一个中介服务。Longhorn 为了避免为每个 Volume 启动单独的 Pod(那样太重了,且 IP 资源浪费),选择在一个 Pod 内部通过
spawn 进程的方式来运行 Engine 和 Replica。
- Instance Manager 就像是一个
专用的 Docker 守护进程,负责在其 Pod 内部启动、监控、停止 longhorn-engine 二进制进程。
- 资源消耗:这是排查性能问题的核心。 所有的 I/O 流量最终都流经这个 Pod。如果节点上 Volume 很多且 I/O 很大,该 Pod 的 CPU 会飙升。
- 日志排查:查看 Volume 崩溃原因时,不要只看 Manager 日志,必须看 Instance Manager 的日志,因为 Engine 的标准输出(stdout/stderr)会被重定向到这里。
在生产环境中,给 longhorn-instance-manager 预留足够的 CPU Request/Limit,并监控其日志,因为它是整个存储系统最繁忙的地方。
Longhorn Engine (longhorn-engine) —— 逻辑核心
longhorn-engine 是业务逻辑,它实现了数据的复制算法、快照合并和重建逻辑。
- 形态:并非独立的 Pod,而是运行在
instance-manager Pod 内部的进程。
- 角色分为两种:
- Engine Controller (Volume Head):
- 对应 Volume,一个 Volume 只有一个活跃的 Controller。
- 通常运行在 挂载了该 Volume 的节点 上(为了本地读写性能)。
- 作用:接收来自文件系统的读写请求,将写请求同步分发给所有健康的 Replicas。
- Engine Replica (Data Store):
- 对应后端存储文件。
- 运行在存储数据的节点上。
- 作用:接收 Controller 发来的数据并写入底层磁盘(
/var/lib/longhorn/replicas/...),并利用 Linux sparse file 特性存储。
- 高可用机制:当 Controller 发现某个 Replica 写入失败,会将其标记为 Error,并不影响 I/O,稍后 Manager 会启动重建流程。
Longhorn CSI Plugin —— 桥梁
- 包含:
csi-attacher, csi-provisioner, csi-resizer, longhorn-csi-plugin。
- 作用:Kubernetes 的 kubelet 调用 CSI 接口来 Mount 磁盘。CSI Plugin 收到请求后,调用 Longhorn Manager 的 API 说:
请把这个 Volume 挂载到本节点。
服务交互流程(数据路径)
为了理解这些服务如何协作,我们看一个写入操作的流程:
- Pod 发起写入:业务 Pod 向挂载路径写入数据。
- 内核块设备:数据进入
/dev/longhorn/vol-name 设备。
- Engine Controller:该设备由
longhorn-engine (Controller 进程) 托管。Controller 进程运行在 instance-manager Pod 中。
- 网络传输:Controller 将数据包复制,通过 TCP 网络并发发送给分布在不同节点上的
longhorn-engine (Replica 进程)。
- 落盘:Replica 进程(也在各节点的
instance-manager 中)收到数据,写入本地磁盘文件(backing file)。
- 确认:所有 Healthy Replica 确认写入成功后,Controller 返回成功给业务 Pod。
相关进程
longhorn controller:I/O 的总指挥
如果不运行 controller,Longhorn 的 Volume 就只是一堆躺在硬盘上的静态文件(Replica)。controller 的作用是将这些静态文件激活为一个可读写的块设备。
核心职责
- 前端暴露 (Frontend):创建一个 Linux 块设备(如
/dev/longhorn/vol-name),供文件系统挂载。
- 读写分发 (Fan-out Write):
- 写:收到 4KB 数据 -> 并发发送给所有 Healthy Replicas -> 等待确认 -> 返回成功。
- 读:收到请求 -> 从任意一个响应最快的 Healthy Replica 读取 -> 返回数据。
- 高可用仲裁:监控 Replica 的连接状态。如果某个 Replica 写入超时或报错,Controller 会将其踢出(Mark as Error),保证 Volume 整体可用。
关键参数解析 (Flags)
longhorn controller 通常由 longhorn-instance-manager 启动,命令结构如下:
longhorn controller <volume-name> --frontend <type> --replica tcp://IP:Port ...
| 参数分类 |
参数名 |
说明 |
技术细节与思考 |
| 网络控制 |
--listen |
监听地址 (IP:Port) |
通常监听 localhost:Port。这是控制平面(Longhorn Manager)向它发送指令(如扩容、快照、添加 Replica)的 gRPC 接口。 |
| 前端接口 |
--frontend |
核心参数,决定设备类型 |
socket: 创建一个 Unix Domain Socket,用于内部通信或 vhost-user。
tgt-blockdev / tgt-iscsi: 使用 TGT (Linux SCSI Target Framework) 创建 /dev/longhorn/xxx 块设备。这是 K8s Pod 挂载的基础。 |
| 副本管理 |
--replica |
初始副本列表 |
格式为 tcp://<Replica-IP>:<Port>。启动时,Controller 会尝试连接这些地址。注意:这只是初始列表,运行中可以通过 gRPC 动态增删。 |
| 容量定义 |
--size |
卷大小 (Bytes) |
必须与 Replica 的大小一致,否则启动失败。 |
| 升级/恢复 |
--upgrade |
升级模式标记 |
告诉 Controller 这是一个热升级过程,它会尝试接管现有的 socket 连接,确保 I/O 不中断。 |
核心参数深度剖析:--frontend
这是理解 Longhorn 性能和兼容性的关键参数。Controller 如何让 Linux 内核看到这个磁盘?
tgt-blockdev (默认/主流)
- 机制:Longhorn 启动一个
tgt (Linux SCSI Target) 进程作为伴生进程。
- 流程:Controller 进程 <–> TGT 进程 <–>
/dev/longhorn/vol-name 块设备。
- 优点:兼容性极好,所有 Linux 发行版都支持 SCSI/Block 设备。
- 缺点:I/O 路径较长(用户态 -> 内核态 -> 用户态 -> 网络),有一定的上下文切换开销。
socket (主要用于 v2 Data Engine 或特殊场景)
- 机制:不创建块设备,直接暴露一个 Unix Socket。
- 场景:用于 SPDK (Storage Performance Development Kit) 场景,或者作为 VM 的 vhost-user 后端。
- 优点:极致性能,完全绕过内核。
Controller 的运行时行为与交互
理解参数后,我们需要知道 Controller 运行起来后在做什么,这对于排错非常有用。
场景一:Replica 故障处理 (Degraded Mode)
假设启动参数为:
longhorn controller vol-1 --replica tcp://10.0.1.1:9502 --replica tcp://10.0.1.2:9502
- Controller 启动,连接两个 Replica。状态:
Healthy。
- 事件:写入请求到达,发往 1.1 和 1.2。
- 故障:1.2 网络断开或磁盘满,写入返回 Error。
- 反应:Controller 将 1.2 标记为
ERR。
- 结果:后续的 I/O 只发给 1.1。Volume 状态变为
Degraded(降级),但业务 不感知,读写不中断。
场景二:动态添加副本 (Rebuilding)
当 Longhorn Manager 决定重建副本时,它不会重启 Controller 进程来修改 --replica 参数,而是:
- Manager 调用 Controller 的 gRPC API。
- 发送
ReplicaAdd 指令。
- Controller 动态建立与新 Replica 的 TCP 连接,并开始后台同步。
架构思考:Controller 的设计哲学
为什么 Longhorn 要设计一个独立的 controller 进程,而不是让挂载端直接连 Replica?
- “瘦” 控制器 (Thin Controller)
longhorn controller 被设计得非常轻量。
- 无状态:它不持久化存储任何数据(数据全在 Replica 里)。
- 内存态:它只在内存中维护
谁是健康的 Replica这张表。如果 Controller 崩溃重启,它只需要重新连接 Replica,就能恢复工作。
- 写放大的源头 (Source of Write Amplification)
这是分布式存储的代价。
- 参数
--replica 指定了几个地址,Controller 就必须把一份流量放大几倍发送出去。
- 性能瓶颈点:Controller 的网络带宽通常是瓶颈。如果网络带宽是 1Gbps,3 副本模式下,业务最大写入速度只有 330Mbps(因为 100MB 业务数据 = 300MB 网络流量)。
- 前端可插拔
通过 --frontend 参数的设计,Longhorn 解耦了核心存储逻辑和对外暴露协议。
- 今天可以用 iSCSI/TGT。
- 明天可以用 NVMe-oF(Longhorn v2 正在做的)。
- 只要 Controller 的核心逻辑(读写分发、快照管理)不变,前端接口可以随意替换以适应新的内核技术。
longhorn replica:数据的最终守护者
longhorn replica 进程是 Longhorn 存储的最底层单元,它直接操作磁盘文件。每一个 Longhorn Volume 的副本(Replica),在所在的节点上都对应一个运行着的 longhorn replica 进程。
核心作用
- 服务端:启动一个 TCP 服务器(通常监听随机高位端口),等待 Engine Controller 的连接。
- 落盘:接收 Controller 发来的数据块(4KB 对齐),写入本地目录下的稀疏文件(Sparse File)。
- 快照管理:维护快照链(Snapshot Chain),管理
.img 数据文件和 .meta 元数据文件。
关键参数解析 (Flags)
执行命令通常形如:
longhorn replica --listen IP:Port --size <bytes> /path/to/replica/directory
| 参数 |
说明 |
技术细节 |
--listen |
监听地址与端口 |
用于与 Engine Controller 通信。Controller 会把数据扇出(Fan-out)给所有 Replica 的这个端口。 |
--size |
卷大小 (Bytes) |
定义卷的逻辑大小。Replica 初始化时会检查元数据,如果大小不匹配会报错。 |
--backing-file |
基础镜像路径 |
(重要) 如果该 Volume 基于某个 Backing Image(如 VM 镜像),Replica 会以只读方式挂载该路径作为底层数据源。 |
directory |
(位置参数) 存储目录 |
指定数据实际存放在宿主机的哪个目录下,通常是 /var/lib/longhorn/replicas/<pvc-name>-<random-id>/。 |
底层工作机制
当 longhorn replica 启动时,它会在指定目录下寻找或创建以下文件:
volume.meta: 存储卷的元数据(大小、Head 文件的位置、父子快照关系)。
volume-head.img: 当前活跃的读写层。所有新的写入都发生在这里。
volume-snap-xxx.img: 历史快照文件(只读)。
revision.counter: 用于防止脑裂和数据陈旧,记录写入序列号。
longhorn sync-agent:幕后的搬运工
longhorn sync-agent 是一个辅助服务,它的存在感不如 Controller 和 Replica 强,但在 数据恢复(Rebuild) 和 备份(Backup) 场景中起决定性作用。
核心作用
它通常作为 Daemon 运行在 longhorn-instance-manager Pod 内部(或者在旧版本中作为 sidecar)。它的核心职责是解决**如何在两个 Replica 之间高效传输巨大的稀疏文件**。
- 副本重建 (Rebuilding):当一个节点挂了,新节点启动一个新的空 Replica 时,Controller 无法通过普通 I/O 把旧数据补回来。这时,Controller 会命令
sync-agent 从一个健康的 Replica 把所有快照文件拉过来。
- 接收器模式:它本质上是一个 gRPC Server,专门处理文件的接收和同步操作。
关键参数解析
执行命令通常形如:
longhorn sync-agent --listen IP:Port
| 参数 |
说明 |
技术细节 |
--listen |
监听地址与端口 |
默认监听 0.0.0.0:8002 (端口可能随版本变化)。Controller 通过此端口下发同步指令。 |
工作流程深度交互
为了理解 sync-agent 的价值,我们看一个 Replica 重建流程:
- 场景:Replica A(健康),Replica B(新创建,空的)。
- 指令:Engine Controller 发现 B 是空的,需要从 A 同步数据。
- 调用:Controller 通过 gRPC 呼叫 Replica B 旁边的
sync-agent。
- 传输:
- Replica B 的
sync-agent 会主动连接 Replica A。
- 它不是通过 Controller 中转数据(那样会把 Controller 堵死)。
- 它是直接从 Replica A 的磁盘读取快照文件,流式传输到 Replica B 的磁盘。
- 完成:文件传输完毕后,Controller 将 B 加入活跃后端列表。
longhorn replica、sync-agent 对比与总结
| 特性 |
longhorn replica |
longhorn sync-agent |
| 关注点 |
实时 I/O (Hot Path) |
批量数据传输 (Cold/Warm Path) |
| 通信协议 |
自定义 TCP 协议 (高性能,低延迟) |
gRPC / HTTP (控制流与大文件流) |
| 何时忙碌 |
业务应用读写数据时 |
副本重建、克隆卷、恢复备份时 |
| 资源消耗 |
消耗 CPU (校验和计算) 和 磁盘 IOPS |
消耗 网络带宽 (节点间拷贝数据) |
| 如果挂了 |
卷降级 (Degraded) 或 卷不可用 |
无法重建副本,无法备份,但不影响在线读写 |
思想与思考:为什么这样设计?
Longhorn 将 replica(实时读写)和 sync-agent(后台同步)分开,体现了 控制流与数据流分离 以及 快慢路径分离 的架构思想。
- 避免阻塞主路:如果在 Engine Controller 的主 I/O 线程中处理几百 GB 的副本重建数据拷贝,那么业务 I/O 的延迟会瞬间飙升甚至超时。
- 专业分工:
replica 进程极致优化 4K 随机写性能。
sync-agent 优化大文件的流式传输和断点续传。
- 微服务化:
instance-manager 就像一个操作系统,里面运行着负责读写的 replica 进程和负责运维搬运的 sync-agent 进程,互不干扰。
运维总结与常见问题 (Troubleshooting)
在管理这些服务时,以下经验至关重要:
| 服务组件 |
常见状态/问题 |
排查/处理思路 |
| Longhorn Manager |
CrashLoopBackOff |
检查 K8s API 连接,检查 CRD 是否完整。如果 Manager 重启,不会导致 IO 中断。 |
| Instance Manager |
High CPU/Memory |
这是正常的,如果负载过高,考虑隔离 Longhorn 节点或限制单节点 Volume 数量。不要随意 Kill 这个 Pod,杀掉它会导致该节点所有 Volume 瞬间掉线。 |
| Instance Manager |
Image GC 问题 |
如果 K8s 节点磁盘压力大触发 GC,可能会误删 engine 二进制镜像,导致无法启动新进程。 |
| Longhorn Engine |
Volume Detached |
意味着 Controller 进程挂了。通常是因为网络抖动导致 Replica 全部断连,触发了 Engine 的自我保护机制(Faulted)。 |
| Longhorn Engine |
Upgrade |
升级 Longhorn 时,实际上是替换 longhorn-manager 镜像 -> 创建新的 instance-manager -> 重启 Engine 进程。这就是 Longhorn 所谓的Live Upgrade,I/O 会有瞬间暂停但不断开连接(前端使用 iSCSI/TGT 或用户态 socket 保持 fd)。 |
特殊服务补充
除了上述核心,还有两个相关服务值得注意:
- Share Manager (
share-manager):
- 仅在 ReadWriteMany (RWX) 模式下出现。
- 它是一个单独的 Pod,内部运行 NFS Server。Longhorn 将 Volume 挂载给它,它再通过 NFS 暴露给多个业务 Pod。
- Backing Image Manager:
- 用于管理基础镜像(如 VM 的 qcow2 镜像)。负责下载、分发这些只读层。