这两天在调研clickhouse集群部署方案,为实现高可用且性能较优,现可实行方案如下:
基于ClickHouse的集群的常见方案,结合业界的架构方案,优质的选择是基于ReplicatedMergeTree + Distributed的集群架构方案,也是分布式高可用的集群架构方案,但是在使用该集群架构的过程中,需要注意:
写表的方式:写本地表,读分布式表
由于分布式表的逻辑简单,仅仅是转发请求,所以在转发安全性上,会有风险,并且rand的方式,可能会造成不均衡,业界建议,通过DNS轮训,写本地表,这样最保险和均衡
统一的建表,表管理入口
CK的分布式,完全依赖配置文件,即每个节点,都共享同样的配置文件,建表要区分集群,又要区分副本,建议写一个脚本来统一建表,或者开发一个可视化的页面,操作管理CK表
建议结合查询的负载均衡做,分布式查询的节点可以在每一个节点都建分布式表,查询的选择性更多
ReplicatedMergeTree + Distributed的分布式的方案,副本的复制依赖zk,需要统一的规划Zookeeper的使用规范
一台或者多台查询机?建立分布式表,平衡好查询节点机器资源和数据量之间的关系
ClickHouse查询使用并行处理机制,对CPU和内存的要求比较高,不建议单台机器部署多个节点,同时建议建Zookeeper的节点和CK的节点分开部署,防止高负载下的相互影响
介于ClickHouse对并发的支持有限,建议查询做LB
CK默认的查询并发是100,当并发达到一定的程度,会存在一个排队的现象,介于多shard,多副本的情况,做查询的负载均衡能很好的提高查询的并发有限的问题
同一份数据,日常至少有2份即可,如果其中一份挂掉,新建一个表,把另一份及时同步过来就好
重要的数据建议3个节点做复制,设置至少保证2个节点收到数据才算成功,增强数据的一致性
ClickHouse的节点故障,出现问题,在节点恢复的过程中:故障恢复的过程中的确存在带宽的问题
ClickHouse目前不支持多数据盘,选择合适的RAID方式,建议使用RAID5,配置热备盘,对数据的可靠性,数据恢复,运维难度都有比较好的保障
关闭Linux虚拟内存。在ClickHouse服务器内存耗尽的情况下,Kill掉占用内存最多的Query之后发现,这台ClickHouse服务器并没有如预期的那样恢复正常,所有的查询依然运行的十分缓慢。
通过查看服务器的各项指标,发现虚拟内存占用量异常。因为存在大量的物理内存和虚拟内存的数据交换,导致查询速度十分缓慢。关闭虚拟内存,并重启服务后,应用恢复正常。
由于CK查询性能在单节点查询的时候基本能跑满CPU,所以建议CPU的核数高一点,建议选择48核,内存选择192G
集群规模的建议
ClickHouse官方建议不搞特别大的集群,建议一个业务就跑一个集群,具体多少分片,自己衡量
请务必使用hostname,并在所有/etc/hosts下加入对应的host规则,否则可能一定导致zookeeper无法同步复制表信息!!!!
规划好和ClickHouse的数据交换服务及相关设置
实时写入ClicHouse的时候需要注意的问题
尽量做1000条以上批量的写入,避免逐行insert或小批量的insert,update,delete操作,因为ClickHouse底层会不断的做异步的数据合并,会影响查询性能,这个在做实时数据写入的时候要尽量避开;
Load Balance + Distributed table + ReplicatedMergeTree + zookeeper
假设已经部署好了k8s集群。
Apache ZooKeeper是一个分布式的开源协调服务,用于分布式应用程序。ZooKeeper允许你读取、写入和观察数据的更新。数据以文件系统的形式组织,并复制到整个集群(一组ZooKeeper服务器)的所有ZooKeeper服务器。所有对数据的操作都是原子的和顺序一致的。ZooKeeper通过使用Zab共识协议在整个集群的所有服务器上复制状态机来确保这一点。
在 ClickHouse 部署方案中,ZooKeeper 主要扮演了以下4个角色:
总的来说,ZooKeeper 在 ClickHouse 部署方案中起到了关键的协调和管理角色,确保了 ClickHouse 集群的稳定性和高可用性。
本文ZooKeeper是部署在k8s集群上的,部署方案参考:zookeeper_on_k8s
主要包含4块内容:Headless Service, Service, PodSisruptionBudget, StatefulSet
apiVersion: v1
kind: Service
metadata:
name: zk-hs
labels:
app: zk
spec:
ports:
- port: 2888
name: server
- port: 3888
name: leader-election
clusterIP: None
selector:
app: zk
---
apiVersion: v1
kind: Service
metadata:
name: zk-cs
labels:
app: zk
spec:
ports:
- port: 2181
name: client
selector:
app: zk
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: zk-pdb
spec:
selector:
matchLabels:
app: zk
maxUnavailable: 1
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zk
spec:
selector:
matchLabels:
app: zk
serviceName: zk-hs
replicas: 3
updateStrategy:
type: RollingUpdate
podManagementPolicy: OrderedReady
template:
metadata:
labels:
app: zk
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- zk
topologyKey: "kubernetes.io/hostname"
containers:
- name: kubernetes-zookeeper
imagePullPolicy: Always
image: "registry.k8s.io/kubernetes-zookeeper:1.0-3.4.10"
resources:
requests:
memory: "10Gi"
cpu: "1"
ports:
- containerPort: 2181
name: client
- containerPort: 2888
name: server
- containerPort: 3888
name: leader-election
command:
- sh
- -c
- "start-zookeeper \
--servers=3 \
--data_dir=/var/lib/zookeeper/data \
--data_log_dir=/var/lib/zookeeper/data/log \
--conf_dir=/opt/zookeeper/conf \
--client_port=2181 \
--election_port=3888 \
--server_port=2888 \
--tick_time=2000 \
--init_limit=10 \
--sync_limit=5 \
--heap=512M \
--max_client_cnxns=60 \
--snap_retain_count=3 \
--purge_interval=12 \
--max_session_timeout=40000 \
--min_session_timeout=4000 \
--log_level=INFO"
readinessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- sh
- -c
- "zookeeper-ready 2181"
initialDelaySeconds: 10
timeoutSeconds: 5
volumeMounts:
- name: datadir
mountPath: /var/lib/zookeeper
securityContext:
runAsUser: 1000
fsGroup: 1000
volumeClaimTemplates:
- metadata:
name: datadir
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: csi-rbd-sc
resources:
requests:
storage: 100Gi
在install之前,我们可以看到ZooKeeper Data需要创建PVC进行存储,由于我们用的后端存储是ceph,所以这里我直接创建cephfs的PVC
apiVersion: v1
kind: PersistentVolume
metadata:
name: zookeeper-data-pv
spec:
capacity:
storage: 1000Gi
accessModes:
- ReadWriteMany
cephfs:
monitors:
- 192.168.0.13:6789
- 192.168.0.14:6789
- 192.168.0.15:6789
user: admin
path: /app/zookeeper/data
secretRef:
name: ceph-secret
namespace: airflow
readOnly: false
persistentVolumeReclaimPolicy: Retain
---
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zookeeper-data-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1000Gi
volumeName: zookeeper-data-pv
这里我们使用ceph rbd作为后端持久化存储,这样能保证数据持久化,不会因为服务重启或中断而丢失。
生成之后,我们会有一个文件: zookeeper.yaml
kubectl create ns zookeeper
kubectl apply -f zookeeper.yaml -n zookeeper