HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

魔鬼存在于细节中:从 Redshift 迁移到 ClickHouse 后再无数据丢失

  • 2019-03-20
  • 本文字数:5853 字

    阅读完需:约 19 分钟

魔鬼存在于细节中:从Redshift迁移到ClickHouse后再无数据丢失

FunCorp 是一家国际性娱乐 App 开发商,知名 App iFunny 就是由 FunCorp 出品的。iFunny 是一款非常有趣的图片和 GIF App,用户可以用它来打发时间,比如看模因、漫画、有趣的图片、宠物 GIF 等,也可以上传和分享自己的内容。iFunny 一直使用 Redshift 作为后端服务和移动 App 的事件存储数据库。他们之所以选择 Redshift,是因为当时从成本和便利性方面来看确实没有更好的选择。然而,ClickHouse 的发布改变了这种状况。他们对它进行了一番彻底的研究,对成本和可能的架构作了一番比较。去年夏天,他们终于决定要尝试一下,看看是否可以使用它。这篇文章将介绍 Redshift 曾经帮助他们解决的挑战,以及他们如何将这个解决方案迁移到 ClickHouse。

我们面临的挑战

iFunny 需要类似 Yandex.Metrika 那样的服务,但要求专门为内部使用而设计。让我解释一下原因。


外部客户端——包括移动 App、网站或内部后端服务——会创建很多事件。如果后端服务出现问题,我们很难向这些客户端说明事件处理服务当前不可用,让它们“在 15 分钟或者一小时后再试一次”。我们有很多客户端,它们持续不断地发送事件消息,一丁点都不想等待。


当然,我们的一些内部服务和用户在这方面却相当宽容:即使分析服务不可用,它们也能够正常运行。大多数产品指标和 A/B 测试每天只需要检查一次,甚至可能更少。这就是为什么读取吞吐量会很低。如果发生故障或进行协调更新,数据库有可能在几个小时内(最坏的情况下可能是几天)不可用或无法保持一致。


从数字方面来看:我们每天需要接收大约 50 亿个事件(300 GB 的压缩数据),同时将数据保存在热存储中三个月,以便为 SQL 查询提供服务。我们还需要将数据保存在冷存储中几年或更长时间,同时能够在短短几天内将数据恢复到热存储中。


通常,我们的数据是按时间排序的事件集。大约有三百种类型的事件,每种事件都有自己的一组属性。我们还有一些来自外部源(例如 MongoDB 或外部 AppsFlyer 服务)的数据需要与分析数据库同步。


最终我们需要为数据库提供大约 40 TB 的磁盘空间,以及大约 250 TB 的磁盘空间用于冷存储。

基于 Redshift 的解决方案


我们有发送事件的移动客户端和后端服务。HTTP 服务接收数据,执行基本的验证,按照分钟将事件分组到文件中,保存在本地磁盘上,然后压缩并发送到 S3 存储。这个服务的可用性取决于应用程序服务器和 AWS S3 的可用性。应用程序是无状态的,所以容易进行负载均衡、缩放和替换。S3 是一个相当简单的文件存储服务,具有良好的声誉和高可用性,我们认为完全可以信任它。


然后我们需要以某种方式将数据发送到 Redshift。这部分相对简单:我们使用内置的 S3 导入器将数据上传到 Redshift。每 10 分钟执行一次脚本,脚本连接到 Redshift,并要求接收以 s3://events-bucket/main/year=2018/month=10/day=14/10_3*为前缀的请求数据。


我们使用 Apache Airflow 来跟踪任务上传状态,可以在发生错误时重启任务,而且它提供了易于读取的任务执行日志,如果任务数量很大,那么这些日志就非常有用。如果我们出现任何问题,可以重复上传特定时间间隔的数据,或者上传 S3 存储中的冷数据,最早可以追溯到一年前。


Airflow 还提供了一些调度脚本,可连接到数据库,并定期从外部存储上传数据或使用类似 INSERT INTO…SELECT…的操作进行事件聚合。


Redshift 的可用性保证很差。AWS 每周一次停止集群进行更新或计划维护,每次最长可达半小时。当一个节点离线时,集群也将变为不可用,直到离线的主机重新上线。这通常需要约 15 分钟,这种情况大约每年发生两次。这对当前系统来说这不是问题,因为我们从一开始就知道数据库会定期不可用。


我们为 Redshift 使用了 4 个 ds2.8xlarge 实例(36 核 CPU、16 个 TB 硬盘),总磁盘空间为 64 TB。


最后一个问题是备份。备份计划可以在集群中设置,运行得非常顺利。

为什么要迁移到 ClickHouse

当然,如果没有遇到任何问题,没有人会想到要迁移到 ClickHouse。我们也不例外。


在将 ClickHouse 的存储模式与 Redshift 进行比较时,我们发现它们的结构非常相似。这两个数据库都是基于列的,它们都擅长处理大量的列和压缩磁盘上的数据(在 Redshift 中,你甚至可以为每个列配置压缩类型)。甚至数据的存储方式都可以是一样的:它们按照主键排序,因此在读取时只读取特定的块,并且不需要在内存中保留特定的索引,这在处理大量数据时起到至关重要的作用。


但是,魔鬼存在于细节之中。

一天一张表

当运行 VACUUM 命令时,数据会在磁盘上排序,并从 Redshift 中删除。


vacuum 过程适用于表中的所有数据。但是,如果三个月的数据都在一个表中,完成这个过程需要很长时间,而我们需要每天至少运行一次,因为在删除旧数据的同时也会添加新数据。我们必须每天创建一张特殊的表,并使用视图合并它们,这不仅使视图轮换和支持变得更加复杂,还减慢了查询速度。“explain”显示,在执行查询时会扫描所有表,即使扫描一张表只需要不到一秒钟的时间,但当我们有 90 张这样的表时,每个查询至少需要一分钟才能执行完。

数据重复

第二个问题是数据重复问题。在线传输数据总会出现两个问题:数据丢失或数据重复。我们不允许丢失消息,所以只能接受出现一小部分重复数据。为了给日数据表去重,我们先创建新表,将旧表中具有唯一 ID 的数据(使用窗口函数删除具有相同 ID 的行)插入到新表中,然后删除旧表并重命名新表。因为视图是从日数据表派生出来的,在重命名表时需要将它们删除。我们还要注意锁,如果收到一个锁定视图或某个表的查询,将会导致这个过程变长。

监控和维护

针对 Redshift 的查询几乎没有几个是少于几秒的。即使你只是想添加用户或列出活跃查询的清单,也需要等待上几十秒。当然,我们习惯了等待,对于这类数据库来说,这样的延迟是可接受的,但不管怎样,我们还是浪费了很多时间。

成本

根据我们的计算,在具有相同资源的 AWS 实例上部署 ClickHouse 只需要一半的成本。这是有道理的,因为 Redshift 是一个开箱即用的数据库。你只需要在 AWS 控制台中单击几下,然后使用 PostgreSQL 客户端连接数据库,剩下的事情就交给 AWS。但这些真的值那么些钱吗?我们已经拥有了基础设施,并且知道如何进行备份、监控和配置内部服务。既然这样,为什么不使用СlickHouse 呢?

迁移

最初,我们部署了一个小型的 ClickHouse:只有一台机器。我们使用内置工具定期从 S3 导入数据。因此,我们能够测试我们对 ClickHouse 性能和功能的假设。在花了几个星期测试一个小数据副本之后,我们找到了在用 Clickhouse 完全替换 Redshift 之前需要解决的一些问题:


  • 应该使用哪些类型的实例和磁盘进行部署?

  • 需要进行复制吗?

  • 如何安装、配置和启动它?

  • 如何监控?

  • 应该使用什么样的 schema?

  • 如何从 S3 将数据发送给它?

  • 如何将所有的标准 SQL 重写为非标准 SQL?


实例和磁盘类型。我们决定使用当前安装的 Redshift 作为参考来确定 CPU 的核心数量、磁盘数量和内存。我们有几种选择,包括带有本地 NVMe 磁盘的 i3 实例,但最终我们选择了 r5.4xlarge 和 8T ST1 EBS 存储。根据我们的估计,这样的性能可能与 Redshift 相当,而价格只有原来的一半。有了 EBS 磁盘,我们就可以通过磁盘快照进行简单的备份和恢复,这与 Redshift 几乎相同。


复制。因为是将现有的 Redshift 配置作为参考,所以我们决定不使用复制。这样做的另一个好处是我们不需要去学习 ZooKeeper,我们的基础设施中本来就没有这项服务(但我们现在可以在需要时进行复制)。


安装。这是最简单的部分,我们只需要用一个 Ansible 角色来安装 RPM 软件包,并在每台主机上使用相同的配置。


监控。我们使用 Prometheus、Telegraf 和 Grafana 来监控所有的服务。我们将 Telegraf 代理安装到 ClickHouse 主机上,并准备了一个 Grafana 仪表盘,用来显示服务器 CPU、内存和磁盘的工作负载。我们使用了一个 Grafana 插件来显示对当前集群的查询情况、从 S3 导入数据的状态以及其他有用的东西。效果比 AWS 控制台提供的仪表盘更好,信息更丰富,速度更快!


schema。我们在 Redshift 中犯的主要错误之一是将主要事件字段保存在单独的列中,然后将其他很少用到的列合并成一个叫作 properties 的列。事实上,在早期我们还不了解所收集的事件以及它们具有哪些属性(它们可能每天变 5 次)时,我们能够灵活地编辑字段。但另一方面,对 properties 列查询所花费的时间越来越长。在 ClickHouse 中,我们决定从一开始就把事情做对,我们采用了所有可能的列,并为它们指定最合适的类型。最终,我们得到了一张包含约两千个列的表。


下一步是为存储和分区选择合适的引擎。


至于分区,我们决定不重新发明轮子:我们重用了在 Redshift 中使用的方法,即每天创建一个分区,只是现在所有分区都存储在一个表中,这大大加快了查询速度并简化了维护工作。我们选择了 ReplacingMergeTree 引擎,因为我们可以使用 OPTIMIZE…FINAL 命令从特定分区中删除重复数据。此外,因为使用了日分区模型,我们只处理一天的数据,如果发生错误或故障,比处理一个月的数据要快得多。


将数据从 S3 传输到 ClickHouse。这是最耗时的过程之一,因为我们无法使用 ClickHouse 的内置工具上传数据。S3 以 JSON 格式存储数据,因此必须通过 jsonpath 提取每个字段,有时候甚至不得不进行转换:例如,将 UUID 从标准格式 DD96C92F-3F4D-44C6-BCD3-E25EB26389E9 转换为字节,并放入 FixedString(16 位)。


我们想要一个类似于 Redshift COPY 命令那样的特殊服务,但无法找到开箱即用的解决方案,所以我们必须自己开发。要描述这个解决方案可能需要另写一篇文章,所以长话短说,它就是一个 HTTP 服务,部署在与 ClickHouse 相同的主机上。在查询参数中,我们指定了 S3 前缀(表示应该从哪里获取文件)、jsonpath 列表(用于将 JSON 转换为一组列),以及每列的转换集。接收查询的服务器从 S3 扫描文件,并将解析任务分配给其他主机。我们需要将无法导入的行保存到单独的СlickHouse 表中,并记录错误消息,这个非常重要。这对于诊断事件处理服务和生成这些事件的客户端来说非常有用。当我们直接将导入器部署在数据库主机上时,我们利用了空闲的资源,因为它们不会全天候接收到复杂的查询。如果查询数量增加,我们还可以将导入器服务移动到独立主机。


从外部导入数据对我们来说并不是个大问题。我们在已有的脚本中将目的地从 Redshift 更改为 ClickHouse。


还有一种办法,就是将 MongoDB 作为字典,而不是每日进行复制。可惜的是,这种方式并不适合我们,因为字典必须始终保存在内存中,而大多数 MongoDB 集合的大小不允许这么做。不过,我们仍然使用了字典,因为从 MaxMind 连接 GeoIP 数据库非常方便,而且在查询时也非常有用。为此,我们使用服务提供的 ip_trie 布局和 CSV 文件。例如,geoip_asn_blocks_ipv4 字典的配置像下面这样:


<dictionaries>    <dictionary>        <name>geoip_asn_blocks_ipv4</name>        <source>            <file>                <path>GeoLite2-ASN-Blocks-IPv4.csv</path>                <format>CSVWithNames</format>            </file>        </source>        <lifetime>300</lifetime>        <layout>            <ip_trie />        </layout>        <structure>            <key>                <attribute>                    <name>prefix</name>                    <type>String</type>                </attribute>            </key>            <attribute>                <name>autonomous_system_number</name>                <type>UInt32</type>                <null_value>0</null_value>            </attribute>            <attribute>                <name>autonomous_system_organization</name>                <type>String</type>                <null_value>?</null_value>            </attribute>        </structure>    </dictionary></dictionaries>
复制代码


将这个配置放在/etc/clickhouse-server/geoip_asn_blocks_ipv4_dictionary.xml 中,你就可以通过 IP 地址向字典发出请求以获取提供者名称:


SELECT dictGetString('geoip_asn_blocks_ipv4','autonomous_system_organization',tuple(IPv4StringToNum('192.168.1.1')));
复制代码


更改数据 schema。如前所述,我们决定放弃复制,因为我们可以承受因发生故障或进行计划维护导致的不可用,而且 S3 中已经保存了一个数据副本,可以在合理的时间内恢复到 ClickHouse。如果我们不使用复制,就不需要部署 ZooKeeper,但少了 ZooKeeper 就无法在 DDL 查询中使用 ON CLUSTER 表达式。我们用一个 Python 脚本解决了这个问题,这个脚本会连接到任意一台 ClickHouse 主机(现在只有 8 台)并执行指定的 SQL 查询。


ClickHouse 对 SQL 的不完整支持。在我们开发导入器的同时,我们将查询语法从 Redshift 转换为 ClickHouse,这个任务主要是由分析师团队完成的。我们的问题主要不在于 JOIN,而在于窗口函数,这看起来可能有点奇怪。我们花了几天时间了解如何使用数组和 lambda 函数来实现它们。庆幸的是,这个问题在 ClickHouse 的众多文章中已经得到了解决,例如,https://events.yandex.ru/lib/talks/5420/。当时,我们的数据同时被记录到两个地方,Redshift 和新的 ClickHouse 数据库,因此我们可以在传输查询时对结果进行比较。尽管如此,要比较性能仍然相当困难,因为我们删除了一个属性列,并且大多数查询只使用了实际需要的列。当然,在这种情况下,性能方面的提升还是很容易看得出来的。对于未解决属性列的查询,具有相当或略高的性能。


结果,数据库 schema 看起来像下面这样:


结果

最后,我们获得了以下这些东西:


  • 一张表,而不是 90 张;

  • 毫秒级的服务查询;

  • 成本减半;

  • 可以简单删除重复事件。


当然也有一些缺点,但我们为它们做好了应对准备:


  • 如果发生故障,我们必须自己恢复集群;

  • 必须分别在每台主机上执行 schema 变更;

  • 我们必须自己更新系统。


我们无法对查询速度进行直接比较,因为数据 schema 发生了很大变化。很多查询的速度得到明显的提升,因为从需要从磁盘读取的数据更少了。


我们花了三个月的时间准备和实现迁移。7 月初,两名专家开始参与该项目,并于 9 月份完成。9 月 27 日,我们关闭了 Redshift。从那时起,我们一直在使用 ClickHouse。已经过去三个月了,时间不算很长,不过我们确实没有遇到会导致整个集群离线的数据丢失或严重错误。我们期待升级到新版本!


英文原文:https://www.altinity.com/blog/migrating-from-redshift-to-clickhouse



2019-03-20 08:004812
用户头像

发布了 38 篇内容, 共 31.5 次阅读, 收获喜欢 208 次。

关注

评论

发布
暂无评论
发现更多内容

大数据培训:Kafka存储结构及Log清理机制

@零度

大数据 kafka log

记某核心MongoDB集群索引优化实践

MongoDB中文社区

mongodb

科创人·弘玑Cyclone CEO高煜光:从RPA到超自动化,以客户需求构建战略纵深

科创人

直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

WorkPlus

ZStack 与龙蜥操作系统完成兼容性认证,共同打造安全可信的云+OS技术生态

OpenAnolis小助手

云计算 开源 操作系统 云平台

深度文 | 一文看懂云原生时代 DevOps 如何选型

星汉未来

运维 云原生 降本增效

带你掌握Redis数据类型:string和Hash

华为云开发者联盟

redis string hash 数据类型

数字化背景下,为何J2PaaS低代码平台,能成为企业技术升级的优选?

J2PaaS低代码平台

低代码 数字化 企业数字化转型 低代码平台 企业级低代码平台

云开发在教育应用开发、运维全流程实践

阿里云云效

云计算 阿里云 DevOps 云原生 开发

【数据库】云数据库rds是什么意思?有什么优势?

行云管家

数据库 云数据库 RDS

高级IO模型之kqueue和epoll

程序那些事

Java io nio 程序那些事 3月月更

什么是SDK,它是怎样威胁我们的隐私?

郑州埃文科技

数字化时代,银行如何建设管理小程序平台促进线上金融业务发展?

FinClip

小程序 银行

45个 GIT 经典操作场景,专治不会合代码

程序员小富

git

web前端培训:js算法面试es6实现

@零度

JavaScript ES6

加入XTransfer,和技术大咖一起大展身手!

XTransfer技术

程序员 招聘 跨境支付

车辆GPS定位整套管理系统,轨迹播放,车辆管理,电子围栏,报警记录,数据库/人员定位/宠物定位/物流跟踪/资产定位

Geek_7jiynf

Java Java web GPS

JAVA只要掌握内部类,多继承和单继承都不是问题

华为云开发者联盟

Java jdk 多继承 内部类 单继承

深度剖析数仓CN增量备份技术

华为云开发者联盟

华为云 备份 GaussDB(DWS) 备份容灾 CN增量备份

福昕软件与中国船级社签署框架合作协议,共建数字船舶发展新高地

联营汇聚

云原生背景下的应用安全建设

火线安全

云原生 云安全

MongoDB常见问题解答:时间与时区

MongoDB中文社区

mongodb

TiDB 5.4 发版丨新功能解读

PingCAP

不会Netty,你永远是个Java菜鸟

博文视点Broadview

Apache Flink 在移动云实时计算的实践

Apache Flink

大数据 flink 开源 编程 实时计算

恒源云(Gpushare)_UNIRE:一种可以共享标签空间的方法

恒源云

OpenCV 计算机视觉 服务器

fastposter v2.5.1 发布 轻松在线作图

物有本末

NFT卡牌盲盒游戏系统开发搭建

薇電13242772558

NFT

【云计算】云计算六大优点简单说明

行云管家

云计算 IT 企业上云 IT运维

【C语言】结构体

謓泽

C语言 结构体 3月月更

基于大数据的医疗健康疾病筛查及风险评估系统

Geek_7jiynf

医疗方案 医疗AI 医疗信息化

魔鬼存在于细节中:从Redshift迁移到ClickHouse后再无数据丢失_大数据_MATVEY KRUGLOV_InfoQ精选文章