1. 业务背景

类似Dexx的交易工具需要抓取和存储dex的大量交易对产生的大量交易数据,交易对数量可达数百万,区块中交易笔数每日可达百万级。 如何保证每个交易对的数据存储和查询效率,尤其是高频交易对(如ETH/USDT等)成为了亟待解决的问题。

用户侧主要有两种查询:

  1. 指定交易对:用户查询某个交易对最近的n笔交易。对应[最新成交]的功能模块
  2. 指定交易对和指定钱包地址:用户查询某个交易对某个钱包地址最近的n笔交易。用于发现聪明钱

目前1年的交易数量约10亿数据,使用如下的分表方案

2. 当前方案:基于交易对地址路由的分表方案

现有的分表策略中,交易对的交易记录是通过对交易对地址(PoolAddress)进行哈希计算,然后将哈希值对256取余(PoolAddress % 256),来决定该交易对的数据存储在trade_0trade_255之间的256个分表中的一个。 分表路由规则:(PoolAddress(交易对地址字符串) % 256),计算结果决定该交易对的数据存储在trade_0trade_255的哪一个分表。

当前查询语句

  1. 指定交易对where 交易对=?
  2. 指定交易对和指定钱包地址where 交易对=? And 钱包地址=?

3. 当前问题:热点交易对导致分表数据不均衡

尽管分表方案能将大部分交易对的交易记录均匀分布到256个分表中,但热点交易对(如ETH/USDT)的查询频率和交易量可能会大幅度高于其他交易对。这样的数据分布依然可能造成一些分表(例如trade_0)的负载过重,导致查询延迟增加,系统性能下降。

问题分析:

  • 热点交易对的查询压力:存储热门交易对的分表数据量远超过其他分表,单表可达千万,导致查询效率低下。同时热门交易对的查询频率也高,压力更大。累的累死。。。
  • 冷门交易对的资源浪费:与热门交易对相比,冷门交易对几乎没有查询需求,对应的分表(例如trade_100)几乎没有负载,导致计算和存储资源的浪费。闲的闲死。。。

4. 解决方案:手动调整路由分表并迁移数据

为了优化查询性能和数据分布,提出手动调整分表路由的方案,针对热门交易对进行精确的手动调整,而无需进行二次分表。

4.1 手动调整分表路由

针对热门交易对(例如ETH/USDT),我们可以选择通过手动调整路由来优化分表分布。即将这些热门交易对的交易记录迁移到新的分表中,从而减轻原有分表(如trade_0)的查询压力。具体过程如下:

执行思路

识别热点交易对,规划新的分表-> 入库双写+数据迁移 -> 查旧表改为查新表

4.2 实施过程

为确保迁移过程中的数据一致性和查询不中断,我们采用双写策略来实现平滑迁移。迁移的具体步骤如下:

  1. 启用双写:修改爬虫入库逻辑,确保所有新的交易记录同时写入旧的分表(例如trade_0)和新的分表(例如trade_256)。这样可以确保新交易记录在新分表不丢失。

  2. 迁移历史数据:将热点交易对的历史交易记录从原有分表(如trade_0)迁移到新的分表(如trade_256)。编写脚本,分批将历史数据迁移到新分表。

  3. 确认数据一致性:验证新旧分表中的数据一致,避免数据丢失或重复。

  4. 切换查询路由:历史数据迁移完成后,将查询路由切换到新的分表。此时,所有关于ETH/USDT的查询将直接访问trade_256,而不再访问原分表。

  5. 停止双写:在确认迁移完成并且新分表已经承载查询流量后,停止双写模式。此时,所有数据都只写入新的分表。

  6. 清理旧数据:一旦确认新的分表完全接管了查询请求,可以将旧分表中的相关数据删除,释放存储资源。

5. 缺点与挑战

  • 操作复杂性:手动调整分表路由和数据迁移过程需要精准的计划和执行。
  • 数据一致性问题:双写和数据迁移期间,必须确保新旧表的数据一致性,避免因网络问题或系统故障造成的数据丢失或重复。

6. 总结

通过手动调整路由分表数据迁移,可以有效解决由于热点交易对造成的数据倾斜问题。 相比于复杂的二次分表方案,这种方法在操作上更为简单和灵活,并能高效应对去中心化交易所中高频查询的挑战。

原创文章转载请注明出处: 分表后数据倾斜问题:手动调整分表方案