从ZooKeeper切换到ClickHouse-Keeper,藏着怎样的秘密

news2024/11/16 17:40:07

图片

本文字数:7772;估计阅读时间:20 分钟

作者:博睿数据  李骅宸(太道)& 小叮当

本文在公众号【ClickHouseInc】首发

本系列前两篇内容:

图片

从ES到ClickHouse,Bonree ONE平台更轻更快!

图片

100%降本增效!Bonree ONE平台通过ClickHouse实现了可观测信号数据的统一!

背景

Bonree ONE是博睿数据公司发布的一体化智能可观测平台。平台所有信号数据迁移到ClickHouse集群后,随着数据量的增长,对ZooKeeper的性能和稳定性要求也越来越高。ZooKeeper是一个开源的分布式协调组件,用于分布式系统之间的协调作用。但我们在使用中也遇到了一些痛点,如果不及时处理会影响到业务。最终我们选择用ClickHouse-Keeper替代ZooKeeper,解决写入性能和维护成本以及集群管理出现的问题。想做到丝滑切换,还需要考虑自动化升级、鉴权情况、数据迁移、数据验证等细节。

ZooKeeper vs ClickHouse-Keeper

ZooKeeper

在数据量和数据种类不断扩充的情况下,ClickHouse集群对于ZooKeeper的压力越来越大。例如在基于实时性要求高的告警数据入库查询时,数据查询的实时性要求秒级返回,ZooKeeper在我们实践中遇到过以下问题:

  • 承载力有限。在我们自建云部署中,按Keeper 4C8G资源配置,单ZooKeeper集群(3个节点)的情况下,最多支持到5个shard(16C32G配置,双副本),每个shard的parts数量大概在2W左右,那5个shard总parts共计10W左右。在不断的数据量增加和表增加的情况下,集群规模会迅速膨胀。所以每扩容5个shard,就得再扩一套ZooKeeper集群,这也带来了极大的维护成本。

  • 性能有瓶颈。初始ClickHouse存储1T数据,总共parts数量在1.2W以内时,数据可以在毫秒级插入成功,但是随着数据量不断增加,parts数量达到2W时,数据插入的响应时间会明显越来越慢,需要几十秒以上才可以插入成功。导致产品上会有查询不到数据,或者查询的数据不及时的现象,影响体验。

  • 资源占用多。ZooKeeper占用内存和IO多,随着数据量的上涨,成本会越来越高。我们在同样的可观测性数据环境中对比发现,ZooKeeper内存消耗是ClickHouse-Keeper的4.5倍,IO占用是ClickHouse-Keeper的8倍。

  • 稳定性不高。ZooKeeper使用Java语言开发,在内存设置不合理的情况下,会出现频繁Full GC从而导致服务中断,从而引起ClickHouse的性能抖动,有时还会出现zxid溢出的问题。另外,当ClickHouse后台执行副本间parts同步时,需要先在ZooKeeper上注册,这时如果ZooKeeper性能表现不佳,会引起后台线程剧增满载,从而导致副本间数据同步延迟。我们在自建云观察在使用ZooKeeper进行存储元数据时,副本间的parts数量延迟队列能达到1W多个,这将严重影响前台业务查询的数据的准确性。

ClickHouse-Keeper

基于以上痛点对比,加上写多读少的统计分析场景特点,我们选择了表现更佳的ClickHouse-Keeper作为Zookeeper的替代品,主要考虑以下几点:

判断兼容性。ClickHouse-Keeper兼容ZooKeeper客户端的协议,任何标准的ZooKeeper客户端都可以与ClickHouse-Keeper进行交互,支持使用ClickHouse的客户端命令。这样就对服务端来说,不改造就可以连接到ClickHouse-Keeper。

历史数据迁移。使用ClickHouse-keeper-converter工具对ZooKeeper历史数据进行转换,并将转换后的快照文件导入到ClickHouse-Keeper集群中。转换效率做到百万路径控制在五分钟以内,降低整体集群停止写入的时间,降低对线上产品的影响程度。

服务稳定。ClickHouse-Keeper使用C++语言编写,提升了整体服务的稳定性,从根本上解决了ZooKeeper的Full GC带来的服务中断,并可以通过调整服务端参数提升服务性能。

资源和性能。对元数据进行压缩存储降低服务的资源占用。同时在CPU和内存以及磁盘IO上使用效率更高。在更好资源情况下,ClickHouse-Keeper性能更佳。

方案演进

1.基于ZooKeeper的原有方案

在集群业务不断扩充的情况下,我们的业务也逐渐划分成重要业务和一般业务,重要业务的性能和查询需求需要优先保证,资源就得绝对隔离高保。我们知道在单个ClickHouse服务中,如果做大量的资源控制,对于大集群来说是一件灾难性的事件,因为我们每次都要重新划分新业务的比重同时调整资源比例。如果我们从物理上直接隔离不同业务的资源将是非常友好的一件事,这样对于运维只需要关心这个业务给多少资源支撑。早期我们因为业务多样复杂性和SLA的不同,通过Zookeeper实现了多个ClickHouse Cluster方案。但在ClickHouse不断扩容的情况下,整个ClickHouse对于ZooKeeper的压力也水涨船高,压力倍增。这时候使用一套ZooKeeper存储所有的元数据,对于ZooKeeper来说已经不能够支持ClickHouse提供正常的服务,插入延迟和任务堆积都将出现。为了解决这个困境,使用ClickHouse官方提供的多ZooKeeper方案。针对我们的业务数据特性和压力,每5个shard的ClickHouse存储parts存储到一个ZooKeeper集群(3个实例)。表的元信息存储到另一套单独的ZooKeeper集群中(3个实例)。

图片

如上图举例,业务A和业务B需要做物理隔离,为A提供CK1集群(15个shard,双副本),为B提供CK2集群(5个shard,双副本),业务查询根据不同cluster名字映射到不同物理资源上的ClickHouse实例,从而做到资源隔离,业务不会影响。按5个shard为一组,ZK1、ZK2、ZK3三个集群平分CK1的15个shard的parts管理,ZK4管理CK2的5个shard的parts。CK1和CK2的所有表的元信息单独存储到公用ZK5集群中(出于稳定性要求考虑)。这样一共需要5套ZK集群(3x5 = 15个ZK实例),维护起来非常麻烦,并且存储时间久了性能和稳定性不太好。

2.基于ClickHouse-Keeper的新方案

测试中已验证使用ClickHouse-Keeper,提升了数据插入速度,提升了ClickHouse的稳定性,副本间同步文件的速度。因为ClickHouse-Keeper表现优异,我们完全不再需要用那么多套keeper管理,索性就维护一套ClickHouse-Keeper,完全可以支持到15个shard以上,相比原来方案精简了许多。

图片

3.升级前的准备

我们知道ClickHouse会不断的更新在ZooKeeper上的数据,当我们停止入库后,其实还有一部分的后台任务在进行(例如后台merge任务),这些任务会改变在ZooKeeper上的数据内容,这样我们就没有办法判断升级之后和升级之前的内容是否是一致的,是否成功将ZooKeeper中的数据转换成功,同时我们又不能将ClickHouse停止,因为停止了ClickHouse的话,平台就无法使用。为此我们深入了解了ClickHouse在ZooKeeper上这些后台任务,并通过命令(例如:SYSTEM STOP MERGES)将这些任务停止掉。这样在升级前后ZooKeeper和ClickHouse-Keeper中的数据是完全一致的,也为我们后面进行数据对比验证提供了条件。因为全过程实现了自动化执行,保障了停止入库时间控制在30分钟内变更完成,不严重影响业务。

4.自动化升级(ZooKeeper -> ClickHouse-Keeper)

升级过程涉及跨机器执行多命令,以及对执行结果判断,大量的人为操作会导致出错概率成倍增加,并使升级时间大大增加。为了解决此问题,我们基于ansible开发自动化升级工具(ansible 是一款 IT 自动化工具,主要应用场景有配置系统、软件部署、持续发布及不停服平滑滚动更新的高级任务编排)。那么我们如何做的自动化升级呢?大致步骤如下:

(1)停止数据入库任务。

(2)停止ClickHouse的merge等后台任务。

(3)记录需要对比的指标数据。

(4)依次重启各个ZooKeeper集群获取最新产生的快照文件。

(5)按照ZooKeeper和ClickHouse-Keeper的对应规则进行快照文件Copy和转换成ClickHouse-Keeper的快照文件。

(6)将快照文件加载到ClickHouse-Keeper中,并进行抽样对比ZooKeeper和ClickHouse-Keeper节点内容。

(7)切换ClickHouse的元数据存储由ZooKeeper到ClickHouse-Keeper。

(8)查询对比指标,并与步骤(3)中指标对比。

(9)启动ClickHouse的merge等后台任务,启动数据入库。

在基于ansible做自动化升级之后,避免升级操作失误,真正做到了傻瓜式升级。同时提升了升级速度,由原先2-3小时的手动升级时间,缩短到现在的分钟级完成,降低了业务查询在ClickHouse的升级过程中影响范围。自动化核心过程:

//停止ClickHouse建库建表等操作
stopClickHouseManagers()

//停止ClickHouse 数据写入作
stopClickHouseConsumers()

//停止ClickHouse Merge等后台任务
ClickHouseStopMerges()

//获取Zookeeper集群最新的快照信息
getNewZookeeperSnap()

//转换Zookeeper快照生成ClickHouse keeper快照文件
createAndExecConvertShell(housekeeperClusterName)

//启动ClickHouse集群
startClickHouses()
    
//对比升级前后数据
checkClickHouseSelectData()

遇到的挑战

那么对于上面讲述的升级过程,就算完成了吗?其实那只是基础步骤。我们环境还更加复杂,除了历史部署了多cluster、多套ZK,还遇到了多套ZK转单套ClickHouse-Keeper(社区版只支持一转一)、ZK加密鉴权问题、数据验证效率等一些难题。

1.多套ZooKeeper转单套ClickHouse-Keeper

为什么会有这个需求呢?主要是因为我们在ZooKeeper和ClickHouse-Keeper性能测试中发现,ClickHouse-Keeper的性能在模拟ClickHouse 请求时性能远超ZooKeeper,对于已经是多套ZooKeeper存储parts的情况,为避免资源浪费,我们需要将集群进行缩减。在CK官方提供的工具中,只能进行一套ZooKeeper通过快照转换到一套ClickHouse-Keeper中。无法支持多套ZooKeeper 迁移到同一套ClickHouse-Keeper。如果不牵扯到服务缩减的话,还遇不到这个问题。那么我们是如何解决的呢,主要通过两方面:

  • 在迁移之前我们会抽样一部分节点对这些节点信息进行保存,在迁移之后对比迁移之前抽样的节点信息是否一致,同时也会抽样表格数据进行查询,确保整个升级过程的前后,数据一致,以防异常情况带来的影响。

  • 在原有的ClickHouse-keeper-converter源码中修改相关代码,支持多套ZooKeeper快照文件合并到同一套ClickHouse-Keeper。比如:

//循环反序列化所有的快照文件
for (const auto & item : existing_snapshots)
{
deserializeKeeperStorageFromSnapshot(storage, item.second, log);
}

//修改numChildren属性获取方式,不用自增id
storage.container.updateValue(parent_path, [path = itr.key] (KeeperStorage::Node & value) { value.addChild(getBaseName(path)); value.stat.numChildren = static_cast<int32_t>(value.getChildren().size());});

//创建转换快照文件时的文件输出流,为了后续diff工具快速读取用
int flags = (O_APPEND | O_CREAT | O_WRONLY);
std::unique_ptr<WriteBufferFromFile> out = std::make_unique<WriteBufferFromFile>("pathLog", DBMS_DEFAULT_BUFFER_SIZE, flags);

2.加密鉴权

我们有很多私有化TOB客户,历史上有些要求对ZK加密,有些不加密,情况不一,但都需要考虑能兼容各种,能丝滑升级。大家知道ZK可以进行ACL加密,对于已经加密的ZK集群转换如何处理,对于部分ZK集群加密转换如何处理,对于完全没有加密的ZK集群又如何处理,分不同策略:

  • 全部加密,或全部不加密。全部加密并且加密信息一致的情况下,即每个ZooKeeper集群中的节点都是使用的相同的ACL策略,同时策略内容相同,并且ClickHouse-Keeper的ACL兼容ZK的ACL,则这种情况下我们是可以保留原有的加密信息,直接进行转换,同时ClickHouse中的配置文件也无需修改。如果全部没有加密,即ClickHouse在使用ZooKeeper的时候没有配置ACL信息,则这种情况也可以直接转换,同时ClickHouse中的配置文件也无需修改。

  • 部分加密,或加密信息不一致。这种情况下就要将原有的加密信息去掉,同时修改ClickHouse 配置文件将加密方式修改为一致。去除ZooKeeper加密方式如下:

(1)添加超级管理员账户。在Zookeeper集群启动的时候在启动的JAVA命令中添加:

Dzookeeper.DigestAuthenticationProvider.superDigest=zookeeper:{XXXXXX}

(2)重启Zookeeper集群。

(3)使用Zookeeper客户端进入集群。

zkCli.sh -server ${zookeeper集群地址,格式为ip1:port,ip2:port}

(4)登录超级管理员账户。

addauth digest zookeeper:#{XXXXXX}

(5)执行取消节点的鉴权命令(目标路径下节点越多耗时越长)。

setAcl -R ${zookeeper的znode路径} world:anyone:cdrwa

(6)去除步骤(1)中的超级管理员账户,同时重启Zookeeper集群。

(7)待升级之后,看自己是否需要在ClickHouse-Keeper中再开启加密。

3.对比验证

我们知道在ZooKeeper中存储的路径是无法直接获取所有的路径,同时我们还遇到了多个ZooKeeper集群合并到同一个ClickHouse-Keeper集群中的情况。如果在自动化升级过程中不能快速准确的进行数据对比,升级时长会成倍增加,同时容易出现误判断,导致升级失败。对于如何快速获取路径和路径对比我们做了如下策略:

(1)我们在ZooKeeper快照转换成ClickHouse-Keeper快照的时候会将转换的所有的path都打印到一个pathlog目标文件中,在对比的时候对这个文件中的内容进行抽样,这样就将查询ZooKeeper的操作变成了读文件操作。原先读取900W个ZooKeeper路径大概需要9个小时,优化后只需要十几秒就可以完成(pathlog加载到内存中读取)。

(2)我们在获取到抽样的ClickHouse-Keeper之后,会根据转换关系,将znode路径和多个ZooKeeper集群的znode路径依次对比。同时在对比之前我们已经关闭了merge等任务,进一步保证临时目录不会出现,从而保证对比的有效性。分情况对比:

  • 差异性路径。此类路径只存在于/clickhouse/tables的路径下,并且只会存在于唯一一套ZK集群中,则对比验证成功。反之,无论在多套ZK集群都不存在,或者存在于两套或两套以上,则对比验证失败。这样就保证了差异性路径数据的正确性。
  • 公共路径。路径在所有ZK集群中的内容都是相同的,才算对比验证通过。这样就保证了公共路径数据的正确性。

4.ClickHouse-Keeper关键参数调优

  • max_requests_batch_size。这个表示发送到raft之前,请求攒批的最大size。集群越大,这个值适量调整大一些,利于攒批和性能提升,我们场景里把value设置为1W。

  • force_sync。表示请求是否同步写入日志,优化设置为false。

  • compress_logs。表示是否压缩日志,日志文件大小会影响启动速度和磁盘占用,优化设置为true。

  • compress_snapshots_with_zstd_format。表示是否压缩快照,日志文件大小会影响启动速度和磁盘占用,优化设置为true。

效果

我们将ZooKeeper替换为ClickHouse-Keeper之后,资源收益和写入耗时收益显著,解决了在ZooKeeper存储元数据的性能瓶颈问题,同时在易用性上降低了门槛。之前ZK的IO瓶颈会直接影响到整体ClickHouse存储的写入耗时。在我们自建云千亿数据实践验证中,从ZK已迁移到HouseKeeper后,CPU和内存占用节省了75%以上,故障率几乎没有。但更值得一提的是,即使再高配置的ClickHouse集群也不要忽视了IO的重要性。最终切换到ClickHouse-Keeper后,IO开销降低了8倍,同时性能也提高了近8倍,这个数据比较符合预期。原本没想到ClickHouse本身性能强悍,ClickHouse-Keeper的性能也毫不逊色!

图片

征稿启示

面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

​​联系我们

手机号:13910395701

邮箱:Tracy.Wang@clickhouse.com

满足您所有的在线分析列式数据库管理需求

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1693176.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作抖音小店一直不出单怎么办?只需要做好这两点就可以了!

大家好&#xff0c;我是电商小V 最近很多新手小伙伴来咨询我说自己操作抖音小店&#xff0c;自己的店铺长时间不出单应该怎么办&#xff1f;今天咱们就来详细的说一下&#xff0c; 咱们要清楚的就是自己的店铺不出&#xff0c;只需要咱们做好这两点就可以了&#xff0c; 第一点…

七个很酷的GenAI LLM技术性面试问题

不同于互联网上随处可见的传统问题库&#xff0c;这些问题需要跳出常规思维。 大语言模型(LLM)在数据科学、生成式人工智能(GenAI)和人工智能领域越来越重要。这些复杂的算法提升了人类的技能&#xff0c;并在诸多行业中推动了效率和创新性的提升&#xff0c;成为企业保持竞争…

阿里云产品DTU评测报告(一)

阿里云产品DTU评测报告&#xff08;一&#xff09; 名词解释物联网平台控制台产品设备 DTU设备模拟器 体验评价针对业务场景&#xff0c;您觉得该产品还有哪些可改进的地方&#xff1f;什么场景下使用该产品产品的优势是什么个人建议 在正式进行DTU测评之前&#xff0c;说一点题…

【LeetCode】【2】两数相加(1411字)

文章目录 [toc]题目描述样例输入输出与解释样例1样例2样例3 提示Python实现模拟 个人主页&#xff1a;丷从心 系列专栏&#xff1a;LeetCode 刷题指南&#xff1a;LeetCode刷题指南 题目描述 给两个非空的链表&#xff0c;表示两个非负的整数&#xff0c;它们每位数字都是按…

SpringBoot + Redis实现对接口的限流

目录 前言 什么是限流&#xff1f; 实现限流 创建一个注解类 接着创建一个切面类 前言 在项目中&#xff0c;对于接口的限流&#xff0c;是任何项目都必不可少的一部分&#xff0c;主要是为了防止用户频繁的发送请求&#xff0c;对服务器造成压力。 另外一点就是防止外来攻…

齐护K210系列教程(三十)_多任务切换

多任务切换 1&#xff0c;任务1的设定2&#xff0c;任务2的设定3&#xff0c;主程序4&#xff0c; 课程资源联系我们 在开发项目时&#xff0c;我们常会用到AIstart的多个任务来切换应用&#xff0c;比如当我识别到某种卡片时&#xff0c;要切换到别的任务&#xff0c;这样就要…

ClickHouse vs. Elasticsearch: 计数聚合的工作原理

本文字数&#xff1a;7875&#xff1b;估计阅读时间&#xff1a;20 分钟 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 介绍 在另一篇博客文章中&#xff0c;我们对 ClickHouse 和 Elasticsearch 在大规模数据分析和可观测性用例中的性能进行了比较&#xff0c;特别是对…

【Linux】LAMP集群分布式安全方案

LAMP集群分布式安全方案主要涉及确保Linux、Apache、MySQL和PHP&#xff08;LAMP&#xff09;组合构成的集群环境的安全性和稳定性。 本次实验通过网络层安全对防火墙配置&#xff1a;使用防火墙&#xff08;如iptables或firewalld&#xff09;来限制对集群的访问&#xff0c;只…

CSDN 访问量增加脚本

在脚本猴中新建脚本并使用: // ==UserScript== // @name CSDN Blog Visitor // @namespace http://tampermonkey.net/ // @version 2024-05-25 // @description Automated visits to CSDN blog pages to simulate user interaction. // @author FontTi…

力扣--字符串58.最后一个单词的长度

思路分析 初始化变量: num 用于记录当前单词的长度。before 用于记录上一个单词的长度。 遍历字符串: 如果字符不是空格&#xff0c;增加 num 计数。如果字符是空格&#xff0c;检查 num 是否为 0&#xff1a; 如果 num 为 0&#xff0c;说明之前没有记录到单词&#xff0c;所以…

无人机支持下的自然灾害风险评估技术应用

张老师&#xff08;副教授&#xff09;&#xff0c;长期从事无人机遥感技术与应用&#xff0c;主持多项国家级科研项目&#xff0c;编写著作2部&#xff0c;第一作者发表科研论文20余篇。对无人机遥感的多平台、多传感应用现状以及涉及的核心技术具有很深的理解&#xff0c;精通…

Spring 模拟管理Web应用程序

MVC&#xff1a;Model View Controller 1&#xff09;controller&#xff1a;控制层&#xff08;Servlet是运行服务器端&#xff0c;处理请求响应java语言编写技术&#xff09; 2&#xff09;service&#xff1a;业务层&#xff08;事务&#xff0c;异常&#xff09; 3&#xf…

linux系统防火墙开放端口命令

目录 linux相关命令参考文章1.开放端口1.1 开发单个端口1.2 一次性开放多个端口 2.保存设置3.查看所有开放的端口4.查看防火墙状态 linux相关命令参考文章 管理、设置防火墙规则&#xff08;firewalld&#xff09;: https://download.csdn.net/blog/column/8489557/137911049 i…

如何参与github开源项目并提交PR

&#x1f47d;System.out.println(“&#x1f44b;&#x1f3fc;嗨&#xff0c;大家好&#xff0c;我是代码不会敲的小符&#xff0c;目前工作于上海某电商服务公司…”); &#x1f4da;System.out.println(“&#x1f388;如果文章中有错误的地方&#xff0c;恳请大家指正&…

编程式路由导航

之前的导航区都是使用<RouterLink>实现路由跳转的 但是很多时候我们希望不需要用户点击就能实现页面跳转&#xff0c;比如首页待三秒自动跳转到新闻页等&#xff0c;有时候需要点击按钮执行函数然后实现跳转&#xff0c;这时候函数是在脚本中&#xff0c;不在结构中&…

2.Redis之Redis的背景知识

Redis 是一个在内存中存储数据的中间件 用于作为数据库,用于作为数据缓存. 在分布式系统中能够大展拳脚~ 1.Redis的特性介绍(优点) 1.1 在内存中存储数据 MySQL 主要是通过"表"的方式来存储组织数据的,"关系型数据库" Redis 主要是通过“键值对" 的…

SpringMVC流程

1、SpringMVC常用组件&#xff1a; DispatcherServlet&#xff08;请求分发器&#xff09;&#xff1a;Spring MVC的核心组件之一&#xff0c;负责处理全局配置和将用户请求分发给其他组件进行处理。Controller&#xff08;处理器&#xff09;&#xff1a; 实际处理业务逻辑的…

链接物化视图在 ClickHouse 中的应用

本文字数&#xff1a;7728&#xff1b;估计阅读时间&#xff1a;20 分钟 作者&#xff1a;Mark Needham 审校&#xff1a;庄晓东&#xff08;魏庄&#xff09; 本文在公众号【ClickHouseInc】首发 在 ClickHouse 中&#xff0c;物化视图【https://clickhouse.com/docs/en/guide…

uni-app App端实现文字语音播报(Ba-TTS)

前言 最近在遇到消息提示语音播放出来&#xff0c;查了一圈文档发现并没有自带api 后面想起支付宝收钱播报&#xff0c;不受限与系统环境和版本环境&#xff08;后面查阅他是音频实现的&#xff09; 如果是由安卓端需要语音播放功能-直接使用Ba-TTs救急&#xff08;需要付费2…

tcpdump源码分析

进入tcpdump.c&#xff08;函数入口&#xff09;之前&#xff0c;先看一些头文件netdissect.h里定义了一个数据结构struct netdissect_options来描述tcdpump支持的所有参数动作&#xff0c;每一个参数有对应的flag, 在tcpdump 的main 里面&#xff0c; 会根据用户的传入的参数来…