# 系统健康检查和快速恢复

## 健康检查

当系统出现问题或要对系统做出任何改动时，都需要首先检查系统的整体健康状态。\
本指南列出了用于判断系统是否健康的部分关键信息。

### 指标和仪表盘

不同配置和流量下，指标统计值和错误阈值可能有很大差异。\
判断的基本思路是检查关键指标的天同比或周同比的情况，观察是否存在显著差异。

#### 活跃性

对于 worker 而言，`alluxio_data_access_bytes_count` 指标将计算 worker 接收的读写请求。\
在 Prometheus 中，我们可以通过查询 `irate(alluxio_data_access_bytes_count[5m])` 来计算每秒请求数（RPS）。\
RPS 应保持稳定。如果 RPS 快速增加，说明 worker 可能将面临容量不足的风险。

#### UFS 数据流

`alluxio_ufs_data_access` 指标记录在 worker 上访问 UFS 的读/写数据流量，如果启用了 UFS 回退功能，也会记录 FUSE 进程的相关数据流量。

`alluxio_ufs_error` 指标记录每种 UFS 的 API 访问错误代码。如果该指标增加，说明访问 UFS 出现问题。\
可使用`error_code` 标签来过滤掉可预期错误，如 "no such file（无此类文件）"。\
在 S3 中，该错误代码是`404`。不同的 UFS 可能会有不同的错误代码。

#### 缓存命中率

对于 worker 而言，`alluxio_cached_data_read_bytes_total` 和 `alluxio_missed_data_read_bytes_total` 指标可以计算缓存命中率。\
要计算每秒的缓存命中率，应在 Prometheus 中使用 `irate` 函数，然后使用 `sum` 来移除未使用的标签。

* 单个 worker 的缓存命中率为：

  ```
  sum by (instance) (irate(alluxio_cached_data_read_bytes_total{job="worker"}[5m])) / (sum by (instance) (irate(alluxio_cached_data_read_bytes_total{job="worker"}[5m])) + sum by (instance) (irate(alluxio_missed_data_read_bytes_total{job="worker"}[5m])))
  ```
* 整体缓存命中率（已集成到仪表盘中）：

  ```
  sum(irate(alluxio_cached_data_read_bytes_total{job="worker"}[5m])) / (sum(irate(alluxio_cached_data_read_bytes_total{job="worker"}[5m])) + sum(irate(alluxio_missed_data_read_bytes_total{job="worker"}[5m])))
  ```

### 整体状态

#### Alluxio Process Readiness

```shell
# 检查 kubernetes 中 worker 的就绪性
# 确保 READY 的值为 100%。即使状态显示为 "Running（运行中）"，也不一定表示 worker 是健康的。
$ kubectl get pod -l app.kubernetes.io/component=worker
NAME                              READY   STATUS    RESTARTS   AGE
alluxio-worker-59476bf8c5-lg4sc   1/1     Running   0          46h
alluxio-worker-59476bf8c5-vg6lc   1/1     Running   0          46h

# 或使用以下一行命令来获取进程就绪的百分比
# 如果有多个 Alluxio 集群，请使用 `app.kubernetes.io/instance=alluxio` 来指定集群
$ kubectl get pod -l app.kubernetes.io/component=worker -o jsonpath='{range .items[*]}{.status.containerStatuses[0].ready}{"\n"}{end}' | awk 'BEGIN{t=0}{s+=1;if($1=="true")t+=1}END{print t,"ready /",s,"expected =",t/s*100,"%"}'
2 ready / 2 expected = 100 %
```

#### ETCD 就绪性

```shell
# 检查 etcd 集群的就绪性
# 使用 `app.kubernetes.io/instance=alluxio` 来选择与 Alluxio 集成的 etcd 集群
$ kubectl get pod -l 'app.kubernetes.io/component=etcd,app.kubernetes.io/instance=alluxio'
NAME             READY   STATUS    RESTARTS   AGE
alluxio-etcd-0   1/1     Running   0          46h
alluxio-etcd-1   1/1     Running   0          46h
alluxio-etcd-2   1/1     Running   0          46h

# 使用以下一行命令获取集群就绪的百分比
$ kubectl get pod -l 'app.kubernetes.io/component=etcd,app.kubernetes.io/instance=alluxio' -o jsonpath='{range .items[*]}{.status.containerStatuses[0].ready}{"\n"}{end}' | awk 'BEGIN{t=0}{s+=1;if($1=="true")t+=1}END{print t,"ready /",s,"expected =",t/s*100,"%"}'
3 ready / 3 expected = 100 %

# 检查 etcd 是否能够处理正常的 I/O 操作
# 输出为 Alluxio worker 的注册信息。请勿以这种方式更改或写入值
$ kubectl exec -it alluxio-etcd-0 -c etcd -- bash -c 'ETCDCTL_API=3 etcdctl get --keys-only --prefix /ServiceDiscovery'
/ServiceDiscovery/default-alluxio/worker-1b4bad64-f195-46a8-be5f-27825a8100a4

/ServiceDiscovery/default-alluxio/worker-49ca0d6f-7a0a-482f-bb17-5550bd602a02

```

#### UFS 就绪性

```shell
$ ./bin/alluxio exec ufsTest --path s3://your_bucket/test_path
Running test: createAtomicTest...
Passed the test! time: 5205ms
Running test: createEmptyTest...
Passed the test! time: 4076ms
Running test: createNoParentTest...
Passed the test! time: 0ms
Running test: createParentTest...
Passed the test! time: 4082ms
...
Running test: listStatusS3RootTest...
Passed the test! time: 543ms
Running test: createFileLessThanOnePartTest...
Passed the test! time: 3551ms
Running test: createAndAbortMultipartFileTest...
Passed the test! time: 6227ms
Tests completed with 0 failed.

# 该示例显示 client 将启动两个线程来向 UFS 写入并读取一个 512MB 的文件，并打印测试结果
$ ./bin/alluxio exec ufsIOTest --path s3://test_bucket/test_path --io-size 512m --threads 2
{
  "readSpeedStat" : {
    "mTotalDurationSeconds" : 483.992,
    "mTotalSizeBytes" : 1073741824,
    "mMaxSpeedMbps" : 2.0614405926641703,
    "mMinSpeedMbps" : 1.0578687251028942,
    "mAvgSpeedMbps" : 1.5596546588835323,
    "mClusterAvgSpeedMbps" : 2.1157374502057884,
    "mStdDev" : 0.7096324729606261,
    "className" : "alluxio.stress.worker.IOTaskSummary$SpeedStat"
  },
  "writeSpeedStat" : {
    "mTotalDurationSeconds" : 172.136,
    "mTotalSizeBytes" : 1073741824,
    "mMaxSpeedMbps" : 3.5236227246137433,
    "mMinSpeedMbps" : 2.974392340939722,
    "mAvgSpeedMbps" : 3.2490075327767327,
    "mClusterAvgSpeedMbps" : 5.948784681879444,
    "mStdDev" : 0.3883645287295896,
    "className" : "alluxio.stress.worker.IOTaskSummary$SpeedStat"
  },
  "errors" : [ ],
  "baseParameters" : {
    "mCluster" : false,
    "mClusterLimit" : 0,
    "mClusterStartDelay" : "10s",
    "mJavaOpts" : [ ],
    "mProfileAgent" : "",
    "mBenchTimeout" : "20m",
    "mId" : "local-task-0",
    "mIndex" : "local-task-0",
    "mDistributed" : false,
    "mStartMs" : -1,
    "mInProcess" : true,
    "mHelp" : false
  },
  "points" : [ {
    "mMode" : "WRITE",
    "mDurationSeconds" : 145.305,
    "mDataSizeBytes" : 536870912,
    "className" : "alluxio.stress.worker.IOTaskResult$Point"
  }, {
    "mMode" : "WRITE",
    "mDurationSeconds" : 172.136,
    "mDataSizeBytes" : 536870912,
    "className" : "alluxio.stress.worker.IOTaskResult$Point"
  }, {
    "mMode" : "READ",
    "mDurationSeconds" : 248.37,
    "mDataSizeBytes" : 536870912,
    "className" : "alluxio.stress.worker.IOTaskResult$Point"
  }, {
    "mMode" : "READ",
    "mDurationSeconds" : 483.992,
    "mDataSizeBytes" : 536870912,
    "className" : "alluxio.stress.worker.IOTaskResult$Point"
  } ],
  "parameters" : {
    "className" : "alluxio.stress.worker.UfsIOParameters",
    "mThreads" : 2,
    "mDataSize" : "512m",
    "mPath" : "s3://test_bucket/test_path",
    "mUseUfsConf" : false,
    "mConf" : { }
  },
  "className" : "alluxio.stress.worker.IOTaskSummary"
}
```

### 日志

#### Alluxio 进程

```shell
# 使用 `kubectl logs <pod-name>` 来获取单个 pod 的所有日志
# 在裸机上，日志位于`logs/<component>.log`，例如：`logs/worker.log`

# 使用 `grep` 命令来过滤特定的日志级别
# 当捕获到异常时，在 WARN/ERROR 日志之后会有附加信息,
# 使用 `-A` 打印更多行
$ kubectl logs alluxio-worker-acee53e8f0a9-3gjbrdekk0 | grep -A 1 'WARN\|ERROR'
2024-07-04 17:29:53,499 ERROR HdfsUfsStatusIterator - Failed to list the path hdfs://localhost:9000/
java.net.ConnectException: Call From myhost/192.168.1.10 to localhost:9000 failed on connection exception: java.net.ConnectException: Connection refused; For more details see:  http://wiki.apache.org/hadoop/ConnectionRefused

# 使用 `kubectl logs -p` 获取之前失败容器的日志
$ kubectl logs -p alluxio-worker-59476bf8c5-lg4sc | grep -A 1 'WARN\|ERROR'
2024-07-05 14:22:28,290 [QuotaCoordinatorTimerThread] ERROR quota.QuotaCoordinator (QuotaCoordinator.java:lambda$new$0) - Failed to run quota janitor job
java.io.IOException: Failed to poll quota usage from worker WorkerInfo{id=7128818659502632567, identity=worker-7128818659502632567, address=WorkerNetAddress{host=sunbowen, containerHost=, rpcPort=64750, dataPort=64751, webPort=64753, domainSocketPath=, secureRpcPort=0, httpServerPort=0}, lastContactSec=283, state=LIVE, capacityBytes=1073741824, usedBytes=0, startTimeMs=1720160253072, capacityBytesOnTiers={MEM=1073741824}, usedBytesOnTiers={MEM=0}, version=3.x-7.0.0-SNAPSHOT, revision=fca83a4688187055d7abfd3a7d710b83a6b62ac6}
```

## 快速恢复

### ETCD 故障

Alluxio 针对 ETCD 故障已经实现了自动应急处理。\
在 ETCD 出现故障后，Alluxio 会在一段（一般这个周期为24小时）时间内容忍 ETCD 故障以保证 IO 的正常进行。\
同时管理员应当在这段时间内解决ETCD 故障。

当 ETCD 出现故障时，一般可以通过重启 ETCD pod来解决。\
在特殊情况下，如果 ETCD 节点无法通过K8s重启解决问题，可以参考如下步骤重建和恢复 ETCD 服务。

1. 关闭集群：`kubectl delete -f alluxio-cluster.yaml`
2. 删除原来的 ETCD PV 和PVC
3. 对原来的 ETCD pv 目录进行备份，防止之后需要恢复数据
4. 检查所有物理机上的 ETCD 文件夹并将里面的内容都删掉
5. 创建三个 ETCD PV。如果 PV 是由管理员手动创建，则建议在 PV 当中增加`nodeAffinity` section 保证 PV 分别对应一个 ETCD 节点和一个物理机。

```yaml
apiVersion: v1
kind: PersistentVolumeClaim
spec:
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - ip-10-0-4-212.ec2.internal
```

6. 重启集群：`kubectl create -f alluxio-cluster.yaml`
7. 如果 `UnderFileSystem` 资源中未定义 UFS 挂载点，则需要重新执行`alluxio mount add`命令以重新挂载 UFS。

### Worker 故障

Alluxio 通过优化功能可以在保证 I/O 不中断的情况下处理 Worker 故障。\
一般来说，少量 Worker 故障不会影响 Alluxio 的功能。

当 Worker 出现故障时，K8s 会通过重启 Worker pod 来解决，不会影响已缓存数据。

### Coordinator 故障

Coordinator 负责处理负载作业和管理服务。\
它将提交的作业的元数据持久化到元存储（metastore），并在崩溃时进行恢复。\
如果持久化的数据出现损坏，未完成的作业将丢失，并需要重新提交。

当 coordinator 出现故障时，K8s 会自动重启 coordinator pod。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://documentation.alluxio.io/ee-da-cn/start/system-health.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
