- 每天插入约 1000 亿条记录,每秒超过 100 万条记录
- 能够每天聚合超过 10 亿独立用户
- 从 MSSQL 迁移到 Azure 表存储再到 ClickHouse
- ClickHouse 部署在 15 台服务器上,总内存 2 TB
Admixer 是一家广告技术公司,为品牌、广告代理商、媒体公司、出版商、广告网络以及其他寻求有效广告管理的买方和卖方行业参与者提供构建广告产品基础设施的所有组件。 Admixer 的一个显着特点是他们的技术,该技术允许
- 代理商根据指定的执行条件(条款、预算、创意展示设置)投放广告活动
- 设置在数千家出版商之间分配广告活动预算的规则
- 为出版商提供账户,他们不仅可以在其中查看收入统计数据或提款,还可以创建自己的广告活动,以及连接除网络广告活动之外的其他盈利来源。
Admixer 的产品包括
- SSP – 供应方平台,出版商/网站在此提供广告位
- DSP – 需求方平台,广告商在此购买广告位
- ADX – 广告交易平台(连接 SSP 和 DSP – 广告和广告位的买方和卖方)
- DMP – 数据管理平台(供广告商配置他们想要定位的受众)
Admixer 不仅提供对这些产品的访问权限,还允许客户构建整个生态系统。
为了实现前一点,Admixer 开始开发广告交易平台。最初,AdExchange 基于外部 DSP 销售本地库存。然后它开始聚合外部 SSP 的流量,以便在其上投放本地广告,然后将此流量重定向到外部 DSP。因此,ADX 被创建了。
在 2015-2016 年,外部库存的份额为 3%(1 亿次请求),然后在 2016 年底,超过 90%(30 亿次请求)。随着请求的急剧增加,其处理负载增加,最重要的是,存储和提供在线分析的负载增加。关系数据库无法处理用于统计记录的那么多插入。在迁移到 Azure 之前,我们使用 MSSQL 服务器来存储对象结构和统计数据。
2011 年,在迁移到 Azure 时,我们使用 Azure 表存储来存储和发布统计数据。但是,随着事务数量和数据量的增加,使用此解决方案并非最佳选择,因为 Azure 表存储按事务数量和数据量收费。
因此我们需要
- 在用户界面中实时显示广告交易的统计数据;
- 接受大量数据(每秒 100 万条记录)进行插入;
- 聚合接收到的不同部分的数据(40 个操作和相同数量的指标);
- 能够随着请求数量的增长扩展数据仓库;
- 完全控制我们的成本。
此图显示了配置文件报告。 Admixer 中的任何广告活动都按行项目(配置文件)拆分。可以概览每个配置文件的详细报告,包括日期时间统计信息、地理位置、域、SSP。此报告也会实时更新。
ClickHouse 帮助应对上述挑战并提供以下优势
- 不受平台限制(我们决定从云迁移);
- 我们构建的集群允许我们每秒接收高达一百万次插入(并且我们知道如何按需扩展);
- 具有用于聚合和跨表分发数据的内置机制(物化视图);
- 出色的数据压缩;
- 读取速度使得可以在用户界面中实时直接显示统计数据;
- 具有 SQL 方言,可以构建任何报告;
- 具有多个高级函数(并允许您编写自己的函数)来处理统计数据;
- 内置 HyperLogLog 用于存储粗略数据;
- 数据抽样;
- 开源 / 社区 / 良好的文档;
- 不断添加新功能、错误修复和改进当前功能;
- 便捷的操作。
我们的架构从 2016 年到 2020 年发生了变化。下面有两个图表:我们开始时的状态和我们达到的状态。
2016 年架构
2020 年架构
请求处理程序是一个组件,它接受广告请求并确定要显示哪个横幅。选择横幅后,它会将其记录在统计信息中。自 2020 年以来,这些组件每秒接收超过 100 万个请求。统计信息通过名为 Global Events Queue 的中间元素记录。事件从 GlobalEventsQueue 中检索,由 EventsProcessor 组件读取,并经过额外的验证/丰富,然后写入 ClickHouse 集群。
最初,我们从 ClickHouse 中的 EventsProcessor 并行写入多个表,但随后切换到 Buffer-> Null-table-> MatViews。接下来,我们将研究版本 21.11 中的新异步插入功能是否可以替代使用缓冲区表。
我们还审查了事件队列的实现。最初,我们使用 Redis(但 Redis 是内存存储),因此
- 在服务器重启时,存在丢失事件的风险;
- RAM 容量相对较小,如果我们计划停止 Events Processor 或 ClickHouse,则存在事件队列溢出的风险,因此需要对事件处理器问题做出非常快速的响应。
我们尝试替换 Redis 并改用 Kafka,但当时用于 ClickHouse 的 Kafka 驱动程序在数组方面存在问题(此问题已得到修复)。
因此,我们实现了自己的事件队列,该队列存储在每个 EventHandler 组件的磁盘上,本地 EventsProcessor 与其位于同一服务器上。 EventsProcessor 组件的数量有所增加,这意味着 ClickHouse 中的插入请求数量也随之增加,但这并不是问题。
由于财务优化对我们来说也是一个重要因素,因此该方案在这方面也被证明是出色的。为了接收来自 ADX 的数据处理和存储,我们组装了一个包含 15 台服务器(40 个线程、128 RAM、SSD 存储)的集群,并且我们也留有余量。对于唯一用户的存储集群,我们使用了 6 台相同服务器的集群。
另一个重点是从集群接收数据的工作。如果您轻率地向集群发送请求,这可能会对其造成相当大的负载,导致其他进程变慢。但是 ClickHouse 具有用于限制资源和为特定用户分配配额的设置,这使我们能够快速解决此问题。所有配置文件都可以完美地放置在配置管理系统中并从中进行管理。
除了按维度汇总指标的统计信息聚合之外,Admixer 还提供有关在任意时间内有多少独立用户观看了广告的信息。唯一用户的数量无法求和。在我们的系统中,用户 ID 是 UUID。当我们想要获取某个任意期间的多个唯一 UUID 时,我们需要每次都重新计算该期间的唯一 UUID。我们无法预先分解所有可能的组合,因为交集会太大。
在使用 ClickHouse 之前,我们只能针对预定义的时间段(天、周、月、所有时间)计算唯一用户。此外,切片的数量也受到限制。此外,对 Aerospike 的持续批量请求减慢了事件处理器的速度。
AggregatingMergeTree 使我们能够以最低的成本在一个报告中按大量键计算唯一用户。最初,使用来自三台服务器的集群,我们可以轻松地在约 12 个切片中每天计算 10 亿个唯一用户。其中存在细微差别;大型切片无法输出到界面,因为同时扫描大型表会占用大量 CPU 时间。此问题的解决方案是报告生成服务,该服务具有其内部队列并将已生成的 CSV 文件发送到界面。另一方面,我们可以将小切片输出到具有有限日期范围的界面。
ClickHouse 非常适合作为我们 ML 模型的大数据存储。
魔鬼在细节中!
ClickHouse 技术提示
- 如果您不需要高数据精度,请使用 HyperLogLog 和抽样;
- 在组装集群之前,运行负载测试以确定您的集群在给定数据结构的情况下可以承受的操作数量;
- Buffer 是插入数据的好方法,但要注意内存;
- 使用 Native 格式进行插入;
- 避免为连续流插入使用大量小部件。表太多会在后台生成大量合并,例如“部件过多 (300)”错误;
- 有必要在开始时决定复制方案。一种选择是使用 ZooKeeper 并让表使用 ReplicatedMergeTree 和其他复制表引擎自行复制。因为我们有很多表,并且我们想要选择将哪些数据部分复制到哪些服务器,所以我们选择不使用 ZooKeeper,而是让我们的客户端分散写入——每次写入都转到两台服务器。
在过去的五年中,Admixer 的核心团队一直致力于高负载和大数据聚合。任何工作都有其微妙之处,不要重蹈覆辙。使用我们的经验。
我们为客户提供专业的审计、咨询或使用 ClickHouse 创建现成的解决方案来解决高负载任务。这些专业服务现在通过我们的新举措 LoadFighters 提供。
Admixer 是一家独立的广告技术公司,致力于开发全栈程序化解决方案生态系统。 Admixer 拥有自己的系列广告技术产品,面向品牌、广告代理商、媒体公司、出版商、广告网络以及其他寻求有效广告管理的买方和卖方行业参与者。我们可定制的技术、深入的专业知识和个性化的方法帮助企业将程序化广告转变为可扩展的收入渠道。
自 2008 年成立以来,我们的使命一直是构建一个生态系统,在数字广告行业的所有参与者之间建立有效且透明的关系。
如今,该公司在全球拥有 100 多个供需合作伙伴、3,000 多家客户和 200 多名员工。他们在乌克兰、白俄罗斯、哈萨克斯坦、摩尔多瓦、格鲁吉亚设有办事处,并在英国和德国设有法律实体。
欲了解更多信息,请访问