LAVIK-CTL · 0.1.0-BETA.1

使用 lavik-ctl 部署主从高可用集群

创建三个 Meta、两个 Data 的 beta.1 集群,验证复制、管理切换并使用 Grafana 监控。

理解部署结构

本指南使用 v0.1.0-beta.1 软件包中一同发布的 lavik、lavik-meta 和 lavik-ctl。lavik-ctl 用于管理 Meta,并不安装版本、启动操作系统进程或提供 start/stop 服务管理。先启动 Meta 和 Data,再用 cluster-create 初始化全新拓扑。

可执行示例在一台 Linux 主机上运行三个 Meta 投票成员和两个 Data 进程,演示主从行为;整机故障仍会让所有进程停止。独立主机部署章节说明了故障域和端点必须如何调整。

单节点与 HA 实验会复用相同端口。启动另一套实验前先停止前一套;若之后还要返回,请保留原状态目录。

进程回环地址端口用途
Meta 17101 / 7201 / 7301Raft / 管理 / Data 控制
Meta 27102 / 7202 / 7302Raft / 管理 / Data 控制
Meta 37103 / 7203 / 7303Raft / 管理 / Data 控制
Data 16371 / 9101初始主节点 / 指标
Data 26372 / 9102初始从节点 / 指标

实验使用明文回环监听。--allow-plaintext-admin 显式允许本地 Leader 发现,并不是身份认证;不要公开这些端口。三个 Meta 投票成员需要至少两个构成多数派。数据复制是异步的,自动故障转移不保证零数据丢失。

1. 安装确切的 v0.1.0-beta.1

使用支持 io_uring 的 Linux 6.1+ 和兼容 Ubuntu 24.04 的 glibc。Mac 或 Windows 用户需要 Linux 虚拟机。Minimal 最容易上手;Standard 也可使用相同的内核 TCP / io_uring 设置。本指南不配置 SPDK 设备。HA 实验建议至少预留 4 GiB 内存,监控需要额外内存。

下载软件包与 SHA-256 校验和 →

使用下方链接中的软件包选择器与安装命令,然后留在解压目录。后续代码块使用 Bash,并在同一终端依次运行;遇到失败应先检查原因。Ubuntu 需要 redis-tools、curl 和 python3;Python 用于恢复前的状态校验。无需修改全局 PATH 或安装 systemd 服务。

软件包选择器与可复制安装命令 →

Linux · bash
./lavik --version
./lavik-meta --version
./lavik-ctl --version

三个输出都必须包含 0.1.0-beta.1;lavik-meta 还会打印 NuRaft 修订号。不要混用 nightly 二进制、其他版本的 Meta 或更新的 lavik-ctl。

Docker 验证为每个进程设置了 512 MiB 的锁定内存软、硬限额。启动前请检查登录会话或服务的 memlock 限额;若缓冲区注册失败,可能需要通过服务管理器或登录策略提高限额。Docker 中验证过的配置为 --ulimit memlock=536870912:536870912。

2. 创建全新状态目录与清单

此步骤在二进制旁创建私有目录,为每个 Data 进程分配一个 512 MiB 数据文件,并写入完整初始清单;已有目录会被拒绝。实际服务应在初始化前选择持久存储上的绝对路径,并与后续的软件包升级分开。不要让 cluster-create 指向需要保留的数据。

Linux · bash
# Run from the extracted v0.1.0-beta.1 package directory.
export LAVIK_BIN_DIR="$(pwd -P)"
export LAVIK_ROOT="$LAVIK_BIN_DIR/ha-beta1"
# Initialization is for a new, empty directory only.
test ! -e "$LAVIK_ROOT" || { echo "Already exists: $LAVIK_ROOT" >&2; exit 1; }
umask 077
mkdir -p "$LAVIK_ROOT"
for i in 1 2 3; do mkdir "$LAVIK_ROOT/meta-$i"; done
for i in 1 2; do
  mkdir "$LAVIK_ROOT/data-$i"
  fallocate -l 512M "$LAVIK_ROOT/data-$i/lavik.data"
done
cat > "$LAVIK_ROOT/cluster.toml" <<'TOML'
schema_version = 1
slot_strategy = "contiguous-even"

[[meta_members]]
id = 1
raft_endpoint = "tcp://127.0.0.1:7101"
data_control_endpoint = "tcp://127.0.0.1:7301"
ctl_endpoint = "tcp://127.0.0.1:7201"

[[meta_members]]
id = 2
raft_endpoint = "tcp://127.0.0.1:7102"
data_control_endpoint = "tcp://127.0.0.1:7302"
ctl_endpoint = "tcp://127.0.0.1:7202"

[[meta_members]]
id = 3
raft_endpoint = "tcp://127.0.0.1:7103"
data_control_endpoint = "tcp://127.0.0.1:7303"
ctl_endpoint = "tcp://127.0.0.1:7203"

[[data_nodes]]
id = "1111111111111111111111111111111111111111"
client_endpoint = "tcp://127.0.0.1:6371"

[[data_nodes]]
id = "2222222222222222222222222222222222222222"
client_endpoint = "tcp://127.0.0.1:6372"

[[groups]]
id = "group-1"
primary = "1111111111111111111111111111111111111111"
replicas = ["2222222222222222222222222222222222222222"]
TOML

节点 ID、Meta ID、端点和 Group 成员必须与启动参数一致。初始主节点为 111…111;清单里的每个 Data ID 均为 40 个十六进制字符。全部槽分配给 group-1。

3. 先启动 Meta,再启动 Data

下面的代码块先启动后台 Meta 进程,等待选出 Leader,再启动 Data。每个进程使用独立的日志、状态目录和 PID 文件。这里的小规模线程、内存和文件设置用于实验,并不是已发布性能基准的配置。

Linux · bash
# Reuse these paths after a restart; do not initialize the directory again.
: "${LAVIK_BIN_DIR:?Set the absolute package directory}"
: "${LAVIK_ROOT:?Set the existing state directory}"
test -f "$LAVIK_ROOT/cluster.toml"
for pidfile in "$LAVIK_ROOT"/*.pid; do
  [ -f "$pidfile" ] || continue
  if kill -0 "$(cat "$pidfile")" 2>/dev/null; then
    echo "A recorded process is still running: $pidfile" >&2
    exit 1
  fi
done
for i in 1 2 3; do
  bootstrap=()
  if [ ! -f "$LAVIK_ROOT/meta-$i/cluster_config.dat" ]; then
    bootstrap=(--initial-cluster-manifest "$LAVIK_ROOT/cluster.toml")
  fi
  nohup "$LAVIK_BIN_DIR/lavik-meta" --id "$i" \
    --addr "127.0.0.1:$((7100+i))" \
    --ctl-addr "127.0.0.1:$((7200+i))" \
    --data-control-addr "127.0.0.1:$((7300+i))" \
    --data-dir "$LAVIK_ROOT/meta-$i" "${bootstrap[@]}" \
    > "$LAVIK_ROOT/meta-$i.log" 2>&1 < /dev/null &
  echo "$!" > "$LAVIK_ROOT/meta-$i.pid"
done
# Wait for a leader before submitting the creation request.
deadline=$((SECONDS+30))
leader=0
while (( SECONDS < deadline )); do
  for directory in "$LAVIK_ROOT"/meta-*; do
    [ -d "$directory" ] || continue
    output=$("$LAVIK_BIN_DIR/lavik-ctl" --socket "$directory/meta-admin.sock" status 2>/dev/null) || continue
    if [[ "$output" == *"leader=1"* ]]; then leader=1; break; fi
  done
  (( leader == 1 )) && break
  sleep 1
done
(( leader == 1 )) || { echo "No Meta leader: inspect $LAVIK_ROOT/meta-*.log" >&2; exit 1; }

for i in 1 2; do
  node_id=$(printf '%040d' 0 | tr '0' "$i")
  nohup "$LAVIK_BIN_DIR/lavik" --bind 127.0.0.1 \
    --port "$((6370+i))" --metrics-port "$((9100+i))" \
    --network kernel --storage uring --threads 1 --no-pin-workers \
    --registered-buffer-mb-per-worker 64 --max-memory 512MiB \
    --shutdown-checkpoint --cluster-enabled --cluster-node-id "$node_id" \
    --cluster-announce-ip 127.0.0.1 \
    --cluster-meta-seed 127.0.0.1:7301 \
    --cluster-meta-seed 127.0.0.1:7302 \
    --cluster-meta-seed 127.0.0.1:7303 \
    --data-file "$LAVIK_ROOT/data-$i/lavik.data" \
    --log-dir "$LAVIK_ROOT/data-$i/logs" \
    > "$LAVIK_ROOT/data-$i.log" 2>&1 < /dev/null &
  echo "$!" > "$LAVIK_ROOT/data-$i.pid"
done

创建完成前,Data 进程即使在运行,也可能因为 Meta 尚未初始化数据副本和权限而返回 LOADING。若 Meta 未选出 Leader,请检查进程日志。仅在 cluster_config.dat 不存在时传入初始清单。

4. 用 lavik-ctl 初始化并等待就绪

创建过程中应保持三个初始 Meta 成员都在线。引导工作流会在创建屏障等待每个初始 Meta 状态机追上进度,只有多数派在线并不足以完成这一阶段;该阶段之后,常规控制面修改使用多数派完成条件。

cluster-create 是会初始化并清除目标 Data 数据的操作,不是重启或接入已有集群的命令。先审阅清单。--yes 会直接接受规范化计划;若希望交互输入 yes,可去掉它。仅在这套全新环境上执行一次。

Linux · bash
# Destructive, one-time initialization of the fresh Data files above.
# --yes accepts the displayed plan; omit it to confirm interactively.
"$LAVIK_BIN_DIR/lavik-ctl" cluster-create \
  --manifest "$LAVIK_ROOT/cluster.toml" \
  --socket "$LAVIK_ROOT/meta-1/meta-admin.sock" \
  --allow-plaintext-admin --yes

退出码 0 表示 Genesis 请求已提交,不代表客户端已能使用集群。接下来单独检查就绪状态。若创建退出码为 3,表示结果不确定,应检查 cluster-status 和打印的操作 ID,而不是再次提交 create。

Linux · bash
# cluster-create returning 0 means accepted, not ready to serve.
# Retry status reads only; never automatically retry cluster-create.
deadline=$((SECONDS+120))
ready=0
while (( SECONDS < deadline )); do
  if "$LAVIK_BIN_DIR/lavik-ctl" cluster-status \
    --socket "$LAVIK_ROOT/meta-1/meta-admin.sock" \
    --allow-plaintext-admin; then
    ready=1
    break
  else
    code=$?
    if (( code != 2 && code != 3 )); then exit "$code"; fi
  fi
  sleep 1
done
(( ready == 1 )) || { echo "Not ready: inspect status and logs; do not recreate." >&2; exit 1; }
Linux · bash
"$LAVIK_BIN_DIR/lavik-ctl" cluster-status \
  --socket "$LAVIK_ROOT/meta-1/meta-admin.sock" \
  --allow-plaintext-admin --json

预期看到 cluster_state=created、result=ready、serving_ready=true,且 blockers 为空。cluster-status 的退出码分别为:0 READY、2 NOT READY、3 RETRYABLE、1 本地或传输致命错误。未就绪时请阅读 status_explanation 和 next_action。

5. 检查从节点并运行客户端

不要把创建成功回复或某一次就绪快照当作从节点已完成同步的证明。在初始布局中,节点 2 是从节点。验证切换前,先等待复制链路正常且全量同步完成。

Linux · bash
# Initial creation only: node 2 is the follower. After failover, discover roles again.
deadline=$((SECONDS+120))
synced=0
while (( SECONDS < deadline )); do
  if ! info=$(redis-cli -h 127.0.0.1 -p 6372 --raw INFO replication 2>/dev/null); then
    sleep 1
    continue
  fi
  if [[ "$info" == *"lavik_replication_failed_stopped:1"* ]]; then
    printf '%s\n' "$info" >&2
    echo "Follower replication stopped; inspect logs before a state-preserving follower restart." >&2
    break
  fi
  if [[ "$info" == *"master_link_status:up"* && "$info" == *"master_sync_in_progress:0"* ]]; then
    synced=1
    printf '%s\n' "$info"
    break
  fi
  sleep 1
done
if (( synced != 1 )); then
  printf '%s\n' "$info" >&2
  echo "Follower is not synchronized; inspect its log and Meta observations." >&2
fi
# Return a failed check without explicitly exiting a reader's interactive shell.
(( synced == 1 ))

即使 cluster-status 显示 READY,也应单独检查从节点同步。若上一项检查报告 lavik_replication_failed_stopped:1,或超时且从节点链路仍未连接,应先检查日志。以下带校验的代码仅重启初始从节点,不删除其状态。它只适用于第一次故障转移前、没有并发拓扑变更的情况;执行后重新检查从节点。若仍被阻塞,应保留文件并排查,不要重新创建集群。 防护检查要求退出码为 0、原主节点在 Group 任期 1 中正常服务、节点观测新鲜且故障转移检测器健康。如果拒绝重启,请先检查状态和日志;初始领导者预热可能需要几秒钟。此快照不是锁:执行期间不要并发修改拓扑。

Linux · bash
# Only for node 2 in the initial two-Data lab, before any failover.
# Preserve its data file, node ID and Meta state. Requires python3.
(
if ! status=$("$LAVIK_BIN_DIR/lavik-ctl" cluster-status \
  --socket "$LAVIK_ROOT/meta-1/meta-admin.sock" --allow-plaintext-admin --json); then
  echo "Cluster status is not ready; stop and inspect." >&2
  exit 1
fi
printf '%s' "$status" | python3 -c '
import json,sys
s=json.load(sys.stdin)
assert s["result"] == "ready" and s["cluster_state"] == "created"
assert all(s[k] is True for k in ("meta_available", "meta_membership_stable", "topology_converged", "serving_ready", "cluster_ready"))
assert s["blockers"] == [] and len(s["groups"]) == 1
g = s["groups"][0]
assert g["group_id"] == "group-1" and g["term"] == "1"
assert g["owner_node_id"] == "1"*40 and g["serving_ready"] is True
assert g["topology_converged"] is True and g["automatic_failover_state"] == "healthy"
assert g["current_reason"] is None and g["blocked_reason"] is None
assert len(s["data_nodes"]) == 2
for node_id, role in (("1"*40, "primary"), ("2"*40, "replica")):
    n = next(n for n in s["data_nodes"] if n["node_id"] == node_id)
    assert n["role"] == role and n["group_id"] == "group-1" and n["retired"] is False
    assert all(n[k] is True for k in ("current_session", "projection_current", "health_fresh", "population_current"))
' || { echo "Initial serving roles, term or transition checks failed; stop and inspect." >&2; exit 1; }
pid=$(cat "$LAVIK_ROOT/data-2.pid")
test "$(readlink "/proc/$pid/exe")" = "$LAVIK_BIN_DIR/lavik" || exit 1
tr '\0' '\n' < "/proc/$pid/cmdline" | grep -F -- "$LAVIK_ROOT/data-2/lavik.data" > /dev/null || exit 1
kill -TERM "$pid"
deadline=$((SECONDS+60))
while [ "$(readlink "/proc/$pid/exe" 2>/dev/null)" = "$LAVIK_BIN_DIR/lavik" ]; do
  (( SECONDS < deadline )) || { echo "Follower did not stop; inspect logs." >&2; exit 1; }
  sleep 1
done
nohup "$LAVIK_BIN_DIR/lavik" --bind 127.0.0.1 --port 6372 --metrics-port 9102 \
  --network kernel --storage uring --threads 1 --no-pin-workers \
  --registered-buffer-mb-per-worker 64 --max-memory 512MiB --shutdown-checkpoint \
  --cluster-enabled --cluster-node-id 2222222222222222222222222222222222222222 \
  --cluster-announce-ip 127.0.0.1 \
  --cluster-meta-seed 127.0.0.1:7301 --cluster-meta-seed 127.0.0.1:7302 \
  --cluster-meta-seed 127.0.0.1:7303 \
  --data-file "$LAVIK_ROOT/data-2/lavik.data" --log-dir "$LAVIK_ROOT/data-2/logs" \
  >> "$LAVIK_ROOT/data-2.log" 2>&1 < /dev/null &
echo "$!" > "$LAVIK_ROOT/data-2.pid"
)

执行此可选恢复步骤后,应重新运行上方从节点同步检查,再继续后续操作。正常初始化成功时不需要执行恢复块。

Linux · bash
# SET and WAIT must share a connection. WAIT is not a failover/durability guarantee.
redis-cli -c -h 127.0.0.1 -p 6371 --raw <<'COMMANDS'
SET greeting "hello from Lavik"
WAIT 1 5000
GET greeting
COMMANDS
# The replica redirects this read to the primary; -c follows that redirect.
redis-cli -c -h 127.0.0.1 -p 6372 GET greeting
redis-cli -h 127.0.0.1 -p 6371 CLUSTER SLOTS

第一个连接预期输出 OK、1 和 hello from Lavik。WAIT 1 5000 请求在五秒内收到一个副本确认;返回更小的数量表示未满足确认条件。它既不会启用同步复制,也不保证写入持久化或未来切换零丢失。-c 跟随集群重定向,发送给从节点的普通读取会被重定向到主节点。beta.1 支持 CLUSTER SLOTS,请勿替换为 CLUSTER SHARDS。

使用 lavik-ctl 管理与检查

Linux · bash
# These are local committed reads. Select the current Meta leader first.
# Check status on each member: leader=1 identifies the leader at that moment.
for directory in "$LAVIK_ROOT"/meta-*; do
  [ -d "$directory" ] || continue
  "$LAVIK_BIN_DIR/lavik-ctl" --socket "$directory/meta-admin.sock" status
done

status 返回所选 Meta 成员本地已提交的视图。报告 leader=1 的成员是当前 Leader。cluster-status 会发现 Leader 并返回集群级就绪视图。Leader 变更后,执行 observations 或 getop 等直接读取前应重新发现 Leader。

Linux · bash
export LAVIK_LEADER_SOCKET=''
for directory in "$LAVIK_ROOT"/meta-*; do
  [ -d "$directory" ] || continue
  output=$("$LAVIK_BIN_DIR/lavik-ctl" --socket "$directory/meta-admin.sock" status) || continue
  if [[ "$output" == *"leader=1"* ]]; then
    export LAVIK_LEADER_SOCKET="$directory/meta-admin.sock"
    break
  fi
done
: "${LAVIK_LEADER_SOCKET:?No current Meta leader; inspect quorum and logs}"
"$LAVIK_BIN_DIR/lavik-ctl" --socket "$LAVIK_LEADER_SOCKET" observations group-1
"$LAVIK_BIN_DIR/lavik-ctl" --socket "$LAVIK_LEADER_SOCKET" getpolicy lavik.automatic-uncontrolled-failover-v1
"$LAVIK_BIN_DIR/lavik-ctl" --socket "$LAVIK_LEADER_SOCKET" getpolicy lavik.authority-lease-v1
"$LAVIK_BIN_DIR/lavik-ctl" --socket "$LAVIK_LEADER_SOCKET" getpolicy lavik.candidate-recovery-v1

observations group-1 展示各节点上报的数据副本与来源历史证据;getpolicy 返回策略当前版本和文档;getop 接收 cluster-create 或 failover 打印的操作 ID,应在当前 Leader 上查询。它们不同于仅检查进程是否存在。

维护前的计划内切换

只有在从节点已同步、当前主节点健康时才开始。受控切换会暂停修改操作,让候选节点追上稳定的源端进度。应用应处理短暂 TRYAGAIN / LOADING 回复,并更新集群拓扑。

Linux · bash
"$LAVIK_BIN_DIR/lavik-ctl" failover group-1 \
  --socket "$LAVIK_ROOT/meta-1/meta-admin.sock" \
  --allow-plaintext-admin --failover-timeout-ms 120000

退出码 0 仅表示请求已提交。复制打印的操作 ID,找到当前 Meta Leader,然后用 getop 查询,直到返回 OK completed failover-completed。aborted 不代表切换成功。若提交退出码为 3,应先确认同一个操作的结果,再决定后续动作。

Linux · bash
# First export LAVIK_OPERATION_ID to the actual ID printed by the CLI.
# Refresh LAVIK_LEADER_SOCKET using the leader-discovery block above.
: "${LAVIK_OPERATION_ID:?Set the operation ID printed by cluster-create or failover}"
: "${LAVIK_LEADER_SOCKET:?Discover the current Meta leader first}"
"$LAVIK_BIN_DIR/lavik-ctl" --socket "$LAVIK_LEADER_SOCKET" getop "$LAVIK_OPERATION_ID"
Linux · bash
"$LAVIK_BIN_DIR/lavik-ctl" cluster-status \
  --socket "$LAVIK_ROOT/meta-1/meta-admin.sock" \
  --allow-plaintext-admin --json

检查 groups[].owner_node_id 并连接新的主节点。在本实验第一次切换后,新主节点为 6372 上的 222…222。旧主节点重新跟随时仍可能返回 LOADING,此时新主节点可能已能服务。再次切换前,应重新检查 INFO replication、observations 以及同一连接上的 SET / WAIT 探针。不能仅凭进程数量判断候选节点是否可用。

beta.1 已默认启用自动故障转移。默认怀疑阈值为 5,000 ms,是去抖策略而不是停机时间 SLA;检测、权限到期、选举、候选恢复和客户端重试也需要时间。非受控恢复可能丢失只在故障主节点上得到确认的写入。不要把 promote --accept-data-loss 当成普通重启步骤。

停止并重启,不重复初始化

记录 LAVIK_BIN_DIR 和 LAVIK_ROOT 的绝对路径。在新终端里先重新 export 相同路径,再执行命令。停止脚本会核对 PID 对应的可执行文件和状态目录,然后发送 SIGTERM,保留所有 Data 和 Meta 状态。整套停止会主动中断实验服务。

Linux · bash
# Linux lab process management; this does not erase Meta or Data state.
: "${LAVIK_ROOT:?Set the existing state directory}"
: "${LAVIK_BIN_DIR:?Set the absolute package directory}"
owns_pid() {
  local pid="$1" executable
  [[ "$pid" =~ ^[0-9]+$ ]] || return 1
  executable=$(readlink "/proc/$pid/exe") || return 1
  [[ "$executable" == "$LAVIK_BIN_DIR/lavik" || "$executable" == "$LAVIK_BIN_DIR/lavik-meta" ]] || return 1
  tr '\0' '\n' < "/proc/$pid/cmdline" | grep -Fq -- "$LAVIK_ROOT/"
}
# Stop Data first, then Meta. Send SIGTERM and wait instead of using kill -9.
for role in data meta; do
  for pidfile in "$LAVIK_ROOT"/"$role"-*.pid; do
    [ -f "$pidfile" ] || continue
    pid=$(cat "$pidfile")
    if owns_pid "$pid"; then kill -TERM "$pid"; fi
  done
  deadline=$((SECONDS+60))
  while :; do
    running=0
    for pidfile in "$LAVIK_ROOT"/"$role"-*.pid; do
      [ -f "$pidfile" ] || continue
      if owns_pid "$(cat "$pidfile")"; then running=1; fi
    done
    (( running == 0 )) && break
    (( SECONDS < deadline )) || { echo "Shutdown timed out; inspect logs." >&2; exit 1; }
    sleep 1
  done
  for pidfile in "$LAVIK_ROOT"/"$role"-*.pid; do
    [ ! -f "$pidfile" ] || rm "$pidfile"
  done
done

重新运行第 3 步的启动块,再执行第 4 步的就绪检查。不要重复目录初始化、fallocate 或 cluster-create。已有 Meta 状态必须在不传 --initial-cluster-manifest 的情况下重启,保留原 ID、数据路径和公告端点。

无人值守运行时,可将相同进程参数交给 Linux 服务管理器,使用绝对二进制路径、持久目录和合适的锁定内存限额。lavik-ctl 是管理客户端,不是进程监督器。生产环境单节点维护应先做计划内切换,不应停止整个集群。

恢复过程中角色可能变化。重启后使用 cluster-status 发现当前主节点;cluster.toml 中的初始主节点不代表当前主节点。

配置 Prometheus 与 Grafana

启动命令已在 9101 和 9102 启用指标。metrics-port 必须非零。先检查端点;它不提供身份认证或 TLS,应仅放在回环地址或受保护的监控网络。

Linux · bash
curl -fsS http://127.0.0.1:9101/metrics
curl -fsS http://127.0.0.1:9102/metrics

在同一 Linux 主机安装 Docker Engine 和 Docker Compose v2.24.4+。下载 beta.1 对应确切源码提交的监控目录,其中配置了 Prometheus v3.11.3、Grafana 13.1.0 和 Lavik Overview 仪表盘;它与 Lavik 二进制软件包分开提供。

若已经按照另一篇指南配置过监控,请复用其目录和已有 .env。使用下方更新流程修改 LAVIK_TARGETS,不要为已有数据卷生成另一套凭据。

Linux · bash
# Use a new directory on the Linux host that will run monitoring.
mkdir lavik-monitoring-beta1
cd lavik-monitoring-beta1
curl -fL https://github.com/eloqdata/lavik/archive/3955b98d43b312324aa8d52775df52cfb111c0d0.tar.gz -o source.tar.gz
(
# These upstream configuration files contain no credentials.
# Containers run as other users and need readable files/traversable directories.
umask 022
tar --no-same-permissions -xzf source.tar.gz --strip-components=3 \
  lavik-3955b98d43b312324aa8d52775df52cfb111c0d0/deploy/monitoring
)
Linux · bash
# Run inside lavik-monitoring-beta1. Keep this file private.
# Do not overwrite an existing monitoring installation's credentials.
test ! -e .env || { echo ".env already exists; edit it instead." >&2; exit 1; }
umask 077
password=$(openssl rand -hex 24)
printf '%s\n' \
  'LAVIK_TARGETS=127.0.0.1:9101,127.0.0.1:9102' \
  'GRAFANA_ADMIN_USER=admin' \
  "GRAFANA_ADMIN_PASSWORD=$password" \
  'GRAFANA_BIND_ADDRESS=127.0.0.1' \
  'PROMETHEUS_BIND_ADDRESS=127.0.0.1' > .env
unset password

生成的 .env 仅包含这套监控的配置和新随机 Grafana 密码,请妥善保管。登录时在本地查看 GRAFANA_ADMIN_PASSWORD,用户名为 admin;不要把文件粘贴到工单或日志中。复用已有 Grafana 卷不会重置原管理员密码。

实验中的 Lavik 绑定回环地址,普通桥接网络容器无法抓取该回环端点。下面的 Linux 专用覆盖配置共享主机网络,并将两个监控界面也绑定回环地址,同时让预配置数据源的 prometheus 名称解析到主机网络中的 Prometheus。

Linux · bash
# Linux Docker Engine, Compose v2.24.4+.
# Share the Linux host network to scrape this guide's loopback-only Lavik nodes.
cat > compose.local.yaml <<'YAML'
services:
  prometheus:
    network_mode: host
    ports: !reset []
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --storage.tsdb.path=/prometheus
      - --storage.tsdb.retention.time=30d
      - --web.listen-address=127.0.0.1:9090
  grafana:
    network_mode: host
    ports: !reset []
    environment:
      GF_SERVER_HTTP_ADDR: 127.0.0.1
    extra_hosts:
      - prometheus:127.0.0.1
YAML
# --quiet validates without printing the Grafana password.
docker compose --env-file .env -f compose.yaml -f compose.local.yaml config --quiet
docker compose --env-file .env -f compose.yaml -f compose.local.yaml up -d
docker compose --env-file .env -f compose.yaml -f compose.local.yaml ps

打开 http://127.0.0.1:3000/d/lavik-overview/lavik-overview 访问 Grafana;Prometheus 目标状态位于 http://127.0.0.1:9090/targets。若 Linux 主机位于远程,请用 SSH 隧道访问这些回环端口。仪表盘的 Lavik instance 选择器可筛选节点,至少等待一个抓取周期后再观察数据。

打开 Lavik Overview 仪表盘 →

查看 Prometheus 目标状态 →

监控目标在线状态、命令吞吐与延迟、可用存储、复制健康、控制会话连接和权限到期。命令耗时直方图不包含套接字响应写出时间,也不等于应用端到端延迟。这套配置提供采集和仪表盘,告警规则及通知路由需按需配置。

PromQL

up{job="lavik"}
rate(lavik_commands_total[1m])
lavik_cluster_control_connected
increase(lavik_cluster_control_lease_expirations_total[5m])

要修改节点列表,编辑本目录 .env 中的 LAVIK_TARGETS,并仅重建 target-config。Prometheus 会在 30 秒内发现目标文件变化。主机网络模式使用本实验的 127.0.0.1 端口;独立监控主机应使用可达的节点私网 IP,并仅使用原始 compose.yaml,不加载 compose.local.yaml。不要把容器自身的回环地址误当作远程节点地址。

Linux · bash
# Edit LAVIK_TARGETS in this monitoring directory's .env first.
docker compose --env-file .env -f compose.yaml -f compose.local.yaml \
  up --force-recreate --exit-code-from target-config target-config
# After exit 0, allow up to 30 seconds for discovery, then check Prometheus Targets.

停止监控时保留历史;除非确实打算删除监控数据和生成的目标文件,否则不要加 -v。

Linux · bash
# Keep named volumes, dashboards and metric history.
docker compose --env-file .env -f compose.yaml -f compose.local.yaml down

将 HA 拓扑部署到独立主机

这应是一套独立的全新部署,不能通过改写已创建实验集群的清单来移动持久端点。使用三个稳定私网地址,将主从节点放在不同故障域;第三个 Meta 投票成员必须能在任一 Data 主机故障时继续存活。客户端必须能够访问所有公告的 Data 端点。

主机进程私网端点
A · 10.0.0.11Meta 1 + 初始主节点7100 / 7200 / 7300;6379 / 9100
B · 10.0.0.12Meta 2 + 初始从节点7100 / 7200 / 7300;6379 / 9100
C · 10.0.0.13Meta 37100 / 7200 / 7300
  • 向每个 Meta 成员提供相同的完整初始清单,并按主机映射替换端点;40 位 Data ID 与 Group 成员保持一致。
  • 每台主机仅启动分配给自己的 Meta ID,使用 --addr HOST_IP:7100、--ctl-addr HOST_IP:7200、--data-control-addr HOST_IP:7300,以及私有持久目录。
  • 在 A、B 上启动各自的 Data ID,设置 --bind HOST_IP --port 6379 --metrics-port 9100 --cluster-announce-ip HOST_IP,并传入三个 7300 端口的 --cluster-meta-seed 地址。各进程独占自己的数据文件。
  • 用 lavik-ctl 通过可达的 Meta 管理端点初始化一次。按用途放行 Meta 间 Raft、Data 到 Meta 控制、Data 复制、客户端到 Data、监控到指标端点的私网流量。
  • 对于非完全可信网络,使用 mTLS 并遵守 beta.1 的证书身份规则。Meta Raft / Data 控制、管理端以及 Data 复制 / 客户端 TLS 的设置不同,管理客户端证书不会自动保护所有流量。
  • 采用生产可用性目标前,应自行测量应用重试、持续复制延迟、恢复和故障域丢失行为。同机 Docker 测试不代表多主机、TLS 或网络分区认证。

固定到 beta.1 的 Meta、TLS 与成员管理手册 →

应用应使用具备集群感知能力的客户端,以两个 Data 端点作为种子地址,并在重定向或连接断开后刷新槽归属。Meta 管理端口和 Data 控制端口属于控制面,不是应用的 Redis 连接端口。请在自己的故障演练中验证具体客户端的重连行为。

排障与恢复边界

现象处理方式
找不到 lavik-ctl / start 命令不支持运行软件包中的 ./lavik-ctl 或绝对路径。使用三个真实二进制;beta.1 不提供 start 命令。
Meta 套接字不存在 / 权限不足检查 Meta 日志,并以相同服务用户运行 CLI。Meta 状态目录应保持私有,不应放宽套接字权限来绕过认证。
LOADING / NOT READY检查 cluster_state、blockers、Data 会话与日志;进程存活并不充分。保留状态目录,不要重跑 cluster-create。
副本缺失 / WAIT 返回 0检查 INFO replication 与 Meta observations;等待全量同步,并在维护前确认当前主节点和源历史域。
Grafana 没有数据检查 /metrics、Prometheus /targets、目标地址与防火墙。回环实验需要 Linux 主机网络覆盖配置。
io_uring / memlock 错误检查 Linux 内核、容器 seccomp 与锁定内存限额。Linux 发布包不能直接在 macOS 上运行。

不要删除 Meta 状态或改写持久配置来强制恢复;cluster-create 不是修复工具。非正常停止的 Data 节点可能需要重建副本或人工恢复,进程重启不代表冗余已经恢复。若 Group 持续被阻塞,应保留日志并遵循固定版本的恢复手册。

验证范围与原始依据

2026-09-25 · Linux Docker · aarch64 · Minimal + Standard

本指南的启动、初始化、客户端、指标和正常重启命令在真实 beta.1 二进制上执行。HA 测试还检查受控切换完成及主进程被终止后的自动提升。Prometheus / Grafana 在隔离共享网络命名空间中运行,用它代替 Linux 主机网络,避免开放宿主端口。

测试不认证独立主机故障、网络分区、TLS、SPDK、生产 SLA、断电恢复或崩溃节点重新加入后的冗余恢复。

查看实际测试记录 ↗
本版本的上游源码与运维文档
继续阅读使用 lavik-ctl 启动单节点 →