简单组合异构存储实现高效商品检索

197 阅读3分钟

image.png

image.png

计算模块 Elasticsearch -- 用于商品按条件打分排序聚合 -- list 查询;

内存模块 Redis ( Tendis ) -- 用于商品数据高速访问 -- KV 查询;

事务模块 MySQL -- 用于数据持久化 ( 可靠性 ) 以及事务支持;

缓存访问优化 Local Bloomfilter + Hash -- 在访问 Redis 前通过一层 Local Bloomfilter 过滤不存在 Key,能显著降低 Key 请求数 ( 进而降低 CPU )。之所以没有用 Redis Bloomfilter Plugin,一方面考虑到 Insert 很少 ( 这一点从监控数据统计得到,而存在性问题无关 Update ),意味着 Bloomfilter 的变化并不频繁,因此更适合放在本地,可以减少一次网络 IO 以及一次 Redis 命令执行;另一方面则是没有官方 Plugin。同时为了减少某次插入带来的 Bloomfilter 更新产生的同步大流量,对 Bloomfilter 进行一次 hash,构造一个逻辑上整体物理上分散的 Bloomfilter,除了能较少每次单次同步产生的流量,还能降低 Bloomfilter 总的存储消耗 ( 稀疏存储 )。

缓存流量优化 Customize Compression -- 由于每条记录 ( Record In MySQL ) 信息较少,常规压缩算法并没有太大效果,在观察数据特征后发现,由于 column name 可枚举且数量有限,很适合用一两个字节压缩表示,由原来的 10+ 个字符压缩成 1-2 个字节 ( 数字方便计算机,字符方便人类阅读 ),同样地,可以枚举的column value 也是做同样的处理进行压缩。而至于如何分配 id,直接借助 DB 的唯一索引即可,只在第一次初始化需要分配,没什么性能顾虑。

数据索引一致性问题 -- 由于异构存储间各自独立,因为数据一致性并没有什么太好的解决方案,无外乎就是重试 + 延迟补偿 + 周期全量。而要很好解决这问题,核心就是需要将数据本身的更新、缓存索引的更新、计算索引的更新置于一个事务中,即有那么一个 NewDB:支持分片、支持字段同时设置 B+ Tree 和 Hash、提供打分模块、分片中数据和索引更新使用本地事务保障数据索引一致性。

Above all:

  1. 低成本 -- ES 使用其默认创建索引特性,组合查询涉及多路归并,索时间复杂度 O(k * p * log n),无需关注是否创建索引以及 MySQL DML 带来的影响;
  2. 高性能 -- 结合 to C 接口,大抵两类查询:多态查询 + 键值查询,前者由 ES 搞定,后者由 Redis 搞定;Redis 使用其 O(1) 时间复杂度的等值查询,Pika 则是使用其磁盘存储特性
  3. 水平扩展 -- ES、RC 都可以简单通过增加副本提升独吞吐
  4. 海量存储 -- 结合 ES、Tedis 的分片和磁盘存储,支持海量设备,同时提升写吞吐;
  5. 具备 Read Committed 隔离级别。

Tips:

  1. 不支持 RR 级别;
  2. 适用场景:终一致性,读多写少;
  3. 需要代码处理下数据延迟的情况;
  4. 对于新索引需要初始化。

组合的场景非常常见,如计算机存储体系 -- CPU cache + memory + disk,虽然更有所短,但在合适的场景下 ( 时间局部性和空间局部性 ),能各自取长补短。