

对于低于每秒一百万个数据点的摄取率,建议使用单节点版本而不是集群版本。单节点版本可根据 CPU 内核、RAM 和可用存储空间的数量进行扩展。单节点版本比集群版本更容易配置和操作,所以在使用集群版本之前要三思而后行。上面我们介绍了 VM 的单节点版本的基本使用,接下来我们来介绍下如何使用集群版。
前面我们了解了 VM 的基本架构,对于集群模式下主要包含以下几个服务:
vmstorage:存储原始数据并返回指定标签过滤器在给定时间范围内的查询数据,当 -storageDataPath 指向的目录包含的可用空间少于 -storage.minFreeDiskSpaceBytes 时,vmstorage 节点会自动切换到只读模式,vminsert 节点也会停止向此类节点发送数据并开始将数据重新路由到剩余的 vmstorage 节点。vminsert:接受摄取的数据并根据指标名称及其所有标签的一致性哈希将其分散存储到 vmstorage 节点。vmselect:通过从所有配置的 vmstorage 节点获取所需数据来执行查询。每个服务都可以进行独立扩展,vmstorage 节点之间互不了解、互不通信,并且不共享任何数据。这样可以增加集群的可用性,并且简化了集群的维护和扩展。
最小集群必须包含以下节点:
-retentionPeriod(最小数据保留时间) 和 -storageDataPath 参数的单 vmstorage 节点-storageNode= 的单 vminsert 节点-storageNode= 的单 vmselect 节点但是我们建议为每个服务组件运行至少两个节点以实现高可用性,这样当单个节点暂时不可用时,集群会继续工作,而且其余节点还可以处理增加的工作负载。如果你的集群规模较大,那么可以运行多个小型的 vmstorage 节点,因为这样可以在某些 vmstorage 节点暂时不可用时减少剩余 vmstorage 节点上的工作负载增加。
各个服务除了可以通过参数标志进行配置之外,也可以通过环境变量的方式进行配置:
-envflag.enable 标志必须设置. 必须替换为 _,例如 -insert.maxQueueDuration 可以转换为 insert_maxQueueDuration=, 作为分隔符将不同的值连接成一个,例如 -storageNode -storageNode 将转换为 -storageNode=, -envflag.prefix 为环境变量设置前缀,例如设置了 -envflag.prefix=VM*,则环境变量参数必须以 VM* 开头此外 VM 集群也支持多个独立的租户(也叫命名空间),租户由 accountID 或 accountID:projectID 来标识,它们被放在请求的 urls 中。
accountID 和 projectID 都由一个 [0 … 2^32] 范围内的任意 32 位整数标识,如果缺少 projectID,则自动将其分配为 0。有关租户的其他信息,例如身份验证令牌、租户名称、限额、计费等,将存储在一个单独的关系型数据库中。此数据库必须由位于 VictoriaMetrics 集群前面的单独服务管理,例如 vmauth 或 vmgateway。vmstorage 节点中,当不同租户有不同的数据量和不同的查询负载时,这保证了 vmstorage 节点之间的均匀负载。VM 集群的性能和容量可以通过两种方式进行扩展:
通过向集群中的现有节点添加更多资源(CPU、RAM、磁盘 IO、磁盘空间、网络带宽),也叫垂直可扩展性。
通过向集群添加更多节点,又叫水平扩展性。
对于集群扩展有一些通用的建议:
vmselect 节点添加更多 CPU 和内存,可以提高复杂查询的性能,这些查询可以处理大量的时间序列和大量的原始样本。vmstorage 节点可以增加集群可以处理的活跃时间序列的数量,这也提高了对高流失率(churn rate)的时间序列的查询性能。集群稳定性也会随着 vmstorage 节点数量的增加而提高,当一些 vmstorage 节点不可用时,活跃的 vmstorage 节点需要处理较低的额外工作负载。vmstorage 节点添加更多 CPU 和内存,可以增加集群可以处理的活跃时间序列的数量。与向现有 vmstorage 节点添加更多 CPU 和内存相比,最好添加更多 vmstorage 节点,因为更多的 vmstorage 节点可以提高集群稳定性,并提高对高流失率的时间序列的查询性能。vminsert 节点会提高数据摄取的最大速度,因为摄取的数据可以在更多的 vminsert 节点之间进行拆分。vmselect 节点可以提高查询的最大速度,因为传入的并发请求可能会在更多的 vmselect 节点之间进行拆分。vminsert 和 vmselect 节点。vmstorage 节点,则集群仍然可用:
vminsert 将传入数据从不可用的 vmstorage 节点重新路由到健康的 vmstorage 节点vmstorage 节点可用,则 vmselect 会继续提供部分响应。如果优先考虑可用性的一致性,则将 -search.denyPartialResponse 标志传递给 vmselect 或将请求中的 deny_partial_response=1 查询参数传递给 vmselect。如果 -dedup.minScrapeInterval 命令行标志设置为大于 0 的时间,VictoriaMetrics 会去除重复数据点。例如,-dedup.minScrapeInterval=60s 将对同一时间序列上的数据点进行重复数据删除,如果它们位于同一离散的 60 秒存储桶内,最早的数据点将被保留。在时间戳相等的情况下,将保留任意数据点。
-dedup.minScrapeInterval 的推荐值是等于 Prometheus 配置中的 scrape_interval 的值,建议在所有抓取目标中使用一个 scrape_interval 配置。
如果 HA 中多个相同配置的 vmagent 或 Prometheus 实例将数据写入同一个 VictoriaMetrics 实例,则重复数据删除会减少磁盘空间使用。这些 vmagent 或 Prometheus 实例在其配置中必须具有相同的 external_labels 部分,因此它们将数据写入相同的时间序列。
根据我们的案例研究,与竞争解决方案(Prometheus、Thanos、Cortex、TimescaleDB、InfluxDB、QuestDB、M3DB)相比,VictoriaMetrics 在生产工作负载上使用的 CPU、内存和存储空间更少。
每种节点类型 - vminsert、vmselect 和 vmstorage 都可以在最合适的硬件上运行。集群容量随着可用资源的增加而线性扩展。每个节点类型所需的 CPU 和内存数量很大程度上取决于工作负载 - 活跃时间序列的数量、序列流失率、查询类型、查询 qps 等。建议为你的生产工作负载部署一个测试的 VictoriaMetrics 集群,并反复调整每个节点的资源和每个节点类型的节点数量,直到集群变得稳定。同样也建议为集群设置监控,有助于确定集群设置中的瓶颈问题。
指定保留所需的存储空间(可以通过 vmstorage 中的 -retentionPeriod 命令行标志设置)可以从测试运行中的磁盘空间使用情况推断出来。例如,如果在生产工作负载上运行一天后的存储空间使用量为 10GB,那么对于 -retentionPeriod=100d(100 天保留期)来说,它至少需要 10GB*100=1TB 的磁盘空间。可以使用 VictoriaMetrics 集群的官方 Grafana 仪表板监控存储空间使用情况。



建议留出以下数量的备用资源。
所有节点类型中 50% 的空闲内存,以减少工作负载临时激增时因为 OOM 崩溃的可能性。
所有节点类型中 50% 的空闲 CPU,以减少工作负载临时高峰期间的慢速概率。
vmstorage 节点上 -storageDataPath 命令行标志指向的目录中至少有 30% 的可用存储空间。
VictoriaMetrics 集群的一些容量规划技巧:
vmstorage 节点和/或通过增加每个 vmstorage 节点的内存和 CPU 资源来增加活跃时间序列的集群容量。vmstorage 节点的数量和/或通过增加每个 vmselect 节点的内存和 CPU 资源来减少查询延迟。vminsert 节点所需的 CPU 内核总数可以通过摄取率计算:CPUs = ingestion_rate / 100K。vminsert 节点上的 -rpc.disableCompression 命令行标志可以增加摄取容量,但代价是 vminsert 和 vmstorage 之间的网络带宽使用率会更高。默认情况下,VictoriaMetrics 的数据复制依赖 -storageDataPath 指向的底层存储来完成。
但是我们也可以手动通过将 -replicationFactor=N 命令参数传递给 vminsert 来启用复制,这保证了如果多达 N-1 个 vmstorage 节点不可用,所有数据仍可用于查询。集群必须至少包含 2*N-1 个 vmstorage 节点,其中 N 是复制因子,以便在 N-1 个存储节点丢失时为新摄取的数据维持指定的复制因子。
例如,当 -replicationFactor=3 传递给 vminsert 时,它将所有摄取的数据复制到 3 个不同的 vmstorage 节点,因此最多可以丢失 2 个 vmstorage 节点而不会丢失数据。vmstorage 节点的最小数量应该等于 2*3-1 = 5,因此当 2 个 vmstorage 节点丢失时,剩余的 3 个 vmstorage 节点可以为新摄取的数据提供服务。
启用复制后,必须将 -dedup.minScrapeInterval=1ms 命令行标志传递给 vmselect 节点,当多达 N-1 个 vmstorage 节点响应缓慢和/或暂时不可用时,可以将可选的 -replicationFactor=N 参数传递给 vmselect 以提高查询性能,因为 vmselect 不等待来自多达 N-1 个 vmstorage 节点的响应。有时,vmselect 节点上的 -replicationFactor 可能会导致部分响应。-dedup.minScrapeInterval=1ms 在查询期间对复制的数据进行重复数据删除,如果重复数据从配置相同的 vmagent 实例或 Prometheus 实例推送到 VictoriaMetrics,则必须根据重复数据删除文档将 -dedup.minScrapeInterval 设置为更大的值。 请注意,复制不会从灾难中保存,因此建议执行定期备份。另外 复制会增加资源使用率 - CPU、内存、磁盘空间、网络带宽 - 最多 -replicationFactor 倍。所以可以将复制转移 -storageDataPath 指向的底层存储来做保证,例如 Google Compute Engine 永久磁盘,该磁盘可以防止数据丢失和数据损坏,它还提供始终如一的高性能,并且可以在不停机的情况下调整大小。对于大多数用例来说,基于 HDD 的永久性磁盘应该足够了。
建议从即时快照执行定期备份,以防止意外数据删除等错误。必须为每个 vmstorage 节点执行以下步骤来创建备份:
通过导航到/snapshot/create HTTP handler 来创建一个即时快照。它将创建快照并返回其名称。
/snapshot/create 这个 HTTP handler 来创建即时快照,它将创建快照并返回其名称。vmbackup 组件从 <-storageDataPath>/snapshots/ 文件夹归档创建的快照。归档过程不会干扰 vmstorage 工作,因此可以在任何合适的时间执行。/snapshot/delete?snapshot= 或 /snapshot/delete_all 删除未使用的快照,以释放占用的存储空间。vmstorage 节点之间同步备份。从备份恢复:
kill -INT 停止 vmstorage 节点。vmrestore 组件将备份中的数据还原到 -storageDataPath 目录。vmstorage 节点。在了解了 VM 集群的一些配置细节后,接下来我们就来开始部署 VM 集群。
如果你已经对 VM 组件非常了解了,那么推荐使用 Helm Chart 的方式进行一键安装。
☸ ➜ helm repo add vm https://victoriametrics.github.io/helm-charts/
☸ ➜ helm repo update
# 导出默认的 values 值到 values.yaml 文件中
☸ ➜ helm show values vm/victoria-metrics-cluster > values.yaml
# 根据自己的需求修改 values.yaml 文件配置
# 执行下面的命令进行一键安装
☸ ➜ helm install victoria-metrics vm/victoria-metrics-cluster -f values.yaml -n NAMESPACE
# 获取 vm 运行的 pods 列表
☸ ➜ kubectl get pods -A | grep 'victoria-metrics'
我们这里选择手动方式进行部署,之所以选择手动部署的方式是为了能够了解各个组件的更多细节。
实验环境:
1、win10,vmwrokstation虚机;
2、k8s集群:3台centos7.6 1810虚机,1个master节点,2个node节点
k8s version:v1.22.2
containerd://1.5.5
链接:https://pan.baidu.com/s/1iqnWMtrZT-Z5KEU9kq14OA?pwd=b3wd
提取码:b3wd

2022.8.13-VictoriaMetrics之集群版-code
由于 vmstorage 组件是有状态的,这里我们先使用 StatefulSet 进行部署,由于该组件也是可以进行扩展的,这里我们首先部署两个副本,对应的资源清单如下所示:
vim cluster-vmstorage.yaml
# cluster-vmstorage.yaml
apiVersion: v1
kind: Service
metadata:
name: cluster-vmstorage
namespace: kube-vm
labels:
app: vmstorage
spec:
clusterIP: None #因为你是一个Statefulset,所以要用一个headless无头服务来着的
ports:
- port: 8482
targetPort: http
name: http
- port: 8401
targetPort: vmselect
name: vmselect
- port: 8400
targetPort: vminsert
name: vminsert
selector:
app: vmstorage
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: vmstorage
namespace: kube-vm
labels:
app: vmstorage
spec:
serviceName: cluster-vmstorage
selector:
matchLabels:
app: vmstorage
replicas: 2
podManagementPolicy: OrderedReady #这个是什么??
template:
metadata:
labels:
app: vmstorage
spec:
containers:
- name: vmstorage
image: "victoriametrics/vmstorage:v1.77.0-cluster"
imagePullPolicy: "IfNotPresent"
args:
- "--retentionPeriod=1" #默认也是1个月
- "--storageDataPath=/storage"
- --envflag.enable=true
- --envflag.prefix=VM_
- --loggerFormat=json
ports:
- name: http #storage暴露的api接口
containerPort: 8482
- name: vminsert
containerPort: 8400
- name: vmselect
containerPort: 8401
livenessProbe:
failureThreshold: 10
initialDelaySeconds: 30
periodSeconds: 30
tcpSocket:
port: http
timeoutSeconds: 5
readinessProbe:
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 15
timeoutSeconds: 5
httpGet:
path: /health
port: http
volumeMounts:
- name: storage
mountPath: /storage
volumeClaimTemplates: #因为你是一个无状态,所以这里要使用volumeClaimTemplates
- metadata:
name: storage
spec:
storageClassName: longhorn #裂了,那我的k8s环境还要再部署一遍longhorn环境喽…… 后面自己已经部署好了longhorn环境了
accessModes:
- ReadWriteOnce
resources:
requests:
storage: "2Gi"
首先需要创建一个 Headless 的 Service,因为后面的组件需要访问到每一个具体的 Pod,在 vmstorage 启动参数中通过 --retentionPeriod 参数指定指标数据保留时长,1 表示一个月,这也是默认的时长,然后通过 --storageDataPath 参数指定了数据存储路径,记得要将该目录进行持久化。

或者,当然你用OpenDBs去做一个LocalPV的自动创建也是可以的哈。😢
#[root@master1 vm-cluster]#kubectl apply -f cluster-vmstorage.yaml
service/cluster-vmstorage created
statefulset.apps/vmstorage created
[root@master1 vm-cluster]#kubectl get pods -n kube-vm -l app=vmstorage -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
vmstorage-0 1/1 Running 0 6m7s 10.244.2.70 node2 <none> <none>
vmstorage-1 1/1 Running 0 2m22s 10.244.2.71 node2 <none> <none>
[root@master1 vm-cluster]#kubectl get svc -n kube-vm -l app=vmstorage
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cluster-vmstorage ClusterIP None <none> 8482/TCP,8401/TCP,8400/TCP 10m
接着可以部署 vmselect 组件,由于该组件是无状态的,我们可以直接使用 Deployment 来进行管理,对应的资源清单文件如下所示:
[root@master1 vm-cluster]#vim cluster-vmselect.yaml
# cluster-vmselect.yaml
apiVersion: v1
kind: Service
metadata:
name: vmselect
namespace: kube-vm
labels:
app: vmselect
spec:
ports:
- name: http
port: 8481
targetPort: http
selector:
app: vmselect
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vmselect
namespace: kube-vm
labels:
app: vmselect
spec:
selector:
matchLabels:
app: vmselect
template:
metadata:
labels:
app: vmselect
spec:
containers:
- name: vmselect
image: "victoriametrics/vmselect:v1.77.0-cluster"
imagePullPolicy: "IfNotPresent"
args:
- "--cacheDataPath=/cache"
- --storageNode=vmstorage-0.cluster-vmstorage.kube-vm.svc.cluster.local:8401
- --storageNode=vmstorage-1.cluster-vmstorage.kube-vm.svc.cluster.local:8401
- --envflag.enable=true
- --envflag.prefix=VM_
- --loggerFormat=json
ports:
- name: http
containerPort: 8481
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
livenessProbe:
tcpSocket:
port: http
initialDelaySeconds: 5
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
其中最重要的部分是通过 --storageNode 参数指定所有的 vmstorage 节点地址,上面我们使用的 StatefulSet 部署的,所以可以直接使用 FQDN 的形式进行访问。直
[root@master1 vm-cluster]#kubectl apply -f cluster-vmselect.yaml
service/vmselect created
deployment.apps/vmselect created
[root@master1 vm-cluster]#kubectl get pods -n kube-vm -l app=vmselect -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
vmselect-bcb54965f-kq49c 1/1 Running 0 2m51s 10.244.1.181 node1 <none> <none>
[root@master1 vm-cluster]#kubectl get svc -n kube-vm -l app=vmselect
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
vmselect ClusterIP 10.100.142.147 <none> 8481/TCP 3m8s
接着就需要部署用来接收指标数据插入的 vminsert 组件,同样该组件是无状态的,其中最重要的也是需要通过 --storageNode 参数指定所有的 vmstorage 节点:
[root@master1 vm-cluster]#vim cluster-vminsert.yaml
# cluster-vminsert.yaml
apiVersion: v1
kind: Service
metadata:
name: vminsert
namespace: kube-vm
labels:
app: vminsert
spec:
ports:
- name: http
port: 8480
targetPort: http
selector:
app: vminsert
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vminsert
namespace: kube-vm
labels:
app: vminsert
spec:
selector:
matchLabels:
app: vminsert
template:
metadata:
labels:
app: vminsert
spec:
containers:
- name: vminsert
image: "victoriametrics/vminsert:v1.77.0-cluster"
imagePullPolicy: "IfNotPresent"
args:
- --storageNode=vmstorage-0.cluster-vmstorage.kube-vm.svc.cluster.local:8400
- --storageNode=vmstorage-1.cluster-vmstorage.kube-vm.svc.cluster.local:8400
- --envflag.enable=true
- --envflag.prefix=VM_
- --loggerFormat=json
ports:
- name: http
containerPort: 8480
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 5
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
livenessProbe:
tcpSocket:
port: http
initialDelaySeconds: 5
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
由于本身是无状态的,所以可以根据需要增加副本数量,也可以配置 HPA 进行自动扩缩容。
[root@master1 vm-cluster]#kubectl apply -f cluster-vminsert.yaml
service/vminsert created
deployment.apps/vminsert created
[root@master1 vm-cluster]#kubectl get pods -n kube-vm -l app=vminsert
NAME READY STATUS RESTARTS AGE
vminsert-66c88cd497-6wg2l 1/1 Running 0 10m
[root@master1 vm-cluster]#kubectl get svc -n kube-vm -l app=vminsert
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
vminsert ClusterIP 10.98.142.18 <none> 8480/TCP 11m
集群模式的相关组件部署完成后。
我们看下当前k8s环境,因为上次实验我们已经用vm单节点替代了prometheus了:

[root@master1 vm]#kubectl scale deploy victoria-metrics --replicas=0 -n kube-vm
deployment.apps/victoria-metrics scaled
[root@master1 vm]#kubectl scale deploy prometheus --replicas=1 -n kube-vm
deployment.apps/prometheus scaled
remote_write 的地址为 http://vminsert:8480/insert/0/prometheus/,注意和单节点模式的 API 路径不一样,如下所示:[root@master1 vm]#vim vm-prom-config3.yaml
# vm-prom-config3.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: prometheus-config
namespace: kube-vm
data:
prometheus.yaml: |
global:
scrape_interval: 15s
scrape_timeout: 15s
remote_write: # 写入到远程 VM 存储,url 是远程写入接口地址
- url: http://vminsert:8480/insert/0/prometheus/
# queue_config: # 如果 Prometheus 抓取指标很大,可以加调整 queue,但是会提高内存占用
# max_samples_per_send: 10000 # 每次发送的最大样本数
# capacity: 20000
# max_shards: 30 # 最大分片数,即并发量。
scrape_configs:
- job_name: "nodes"
static_configs:
- targets: ['172.29.9.51:9111', '172.29.9.52:9111', '172.29.9.53:9111']
relabel_configs: # 通过 relabeling 从 __address__ 中提取 IP 信息,为了后面验证 VM 是否兼容 relabeling
- source_labels: [__address__]
regex: "(.*):(.*)"
replacement: "${1}"
target_label: 'ip'
action: replace
[root@master1 vm]#kubectl apply -f vm-prom-config3.yaml
configmap/prometheus-config configured
[root@master1 vm]#curl -X POST "http://172.29.9.51:30832/-/reload" #执行下curl操作
观察效果:

此时,来到prometheus,看下其配置文件是否有更改过来?
http://172.29.9.51:30832/

http:///select/0/prometheus/ 。http://vmselect:8481/select/0/prometheus/

☸ ➜ kubectl logs -f vmstorage-0 -n kube-vm
......
{"ts":"2022-05-06T08:35:15.786Z","level":"info","caller":"VictoriaMetrics/lib/storage/partition.go:206","msg":"creating a partition \"2022_05\" with smallPartsPath=\"/storage/data/small/2022_05\", bigPartsPath=\"/storage/data/big/2022_05\""}
{"ts":"2022-05-06T08:35:15.802Z","level":"info","caller":"VictoriaMetrics/lib/storage/partition.go:222","msg":"partition \"2022_05\" has been created"}

测试结束。😘
vmstorage 节点的方法如果现在需要新增 vmstorage 节点,那么需要按照下面的步骤进行操作:
-retentionPeriod 配置启动新的 vmstorage 节点。vmselect 节点,添加新的 -storageNode 参数包含 。vminsert 节点,添加新的 -storageNode 参数包含 。🍀 又是老问题了:
grafna那里配置数据源,一直有问题……


因此:我把这个vmselect用NodePort类型的服务暴露出去,再使用nodeIP:nodePort来访问就可以了……

使用nodeIP:nodePort来访问:


此时,grafna上就可以正常访问了:

我的博客主旨:
🍀 微信二维码
x2675263825 (舍得), qq:2675263825。

🍀 微信公众号
《云原生架构师实战》

🍀 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

🍀 博客
www.onlyyou520.com

🍀 知乎
https://www.zhihu.com/people/foryouone

🍀 语雀
https://www.yuque.com/books/share/34a34d43-b80d-47f7-972e-24a888a8fc5e?# 《云笔记最佳实践》


好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!
