3年部署3000套PG实例的架构设计与踩坑经验( 四 )



3年部署3000套PG实例的架构设计与踩坑经验
本文插图
案例二:精准营销
对电商来说 , 实时把握客户留存实施精准营销是一项非常重要的功课 。 但是对于有数亿会员和大量商品的大型电商平台 , 常规的处理方式是很低效的 。 通过探索和演进 , 现在我们使用citus + pg_roaringbitmap插件的技术方案 。
roaringbitmap是一种高效的bitmap压缩存储格式 , 在标签类的应用中 , 已被业界广泛使用 。 pg_roaringbitmap插件则把roaringbitmap作为一种新的数据类型引入到了PostgreSQL里 。 这体现了PostgreSQL非常容易扩展的特点 , 不仅数据类型 , 索引类型 , FDW甚至存储过程语言等等都可以扩展 。 再结合Citus的水平扩展能力 , 我们实现了百亿级标签的实时存储和查询 。
3年部署3000套PG实例的架构设计与踩坑经验
本文插图
案例三:基于地理位置的搜索和推荐
苏宁有大量线下门店 , 为支撑线下业务的运营 , 需要基于地理位置为用户提供个性化的搜索和推荐服务 。 并且在大促期间 , 需要支撑非常高的访问量 。 我们使用PostgreSQL + PostGiS插件支持位置数据的存储和高效查询 , 通过一主多从和基于JDBC多主机URL的读写分离水平扩展数据库处理能力 。 大促期间会临时增加从节点提升数据库的吞吐能力 , 最多时扩容到11个节点 。
3年部署3000套PG实例的架构设计与踩坑经验
本文插图
五、PostgreSQL使用经验
在使用PostgreSQL的过程中 , 我们踩过一些坑也积累了一些经验 。 下面我介绍三个PostgreSQL使用过程中需要注意的地方 。
问题一:Gin索引
Gin索引是PostgreSQL的一个特色功能 , 很多研发小伙伴反映 , 数据库从商业数据库迁到PG后 , 他们最惊喜的PG特性就是GIN索引 。 很多系统的用户都有灵活的数据查询需求 , 查询条件涉及的字段不固定 , 之前应用开发者不得不为每种查询组合都创建一个Btree索引 。 这样做导致需要创建的索引非常多 , 不仅占用空间 , 影响更新性能 , 而且仍然难以覆盖所有查询场景 。
对于这种搜索类的场景 , 有些业务会将数据导入到Elasticsearch进行查询 。 但是这种方案增加了系统的复杂度 , 需要保证ES中的数据和原始数据库的数据的保持一致 , 而且ES的索引更新相对与原始数据还存在一定延迟 。 而使用PostgreSQL的Gin索引 , 不存在这些问题 。
3年部署3000套PG实例的架构设计与踩坑经验
本文插图
Gin的基本原理和ES的倒排索引一样 。 它把每个(列号 , Key值)作为倒排索引的键 , 将匹配这些键的元组的物理位置 , 即TID , 作为值存在Entry Tree中 。 其中TID值存储在Entry Tree的叶子节点 。 匹配同一个Key的元组比较少时 , TID集合以列表的形式存储;匹配同一个Key的元组比较多时 , TID集合以Btree的形式存储 , 即Posting Tree 。 新插入的元组先写入Fast update list , 达到一定数量时在批量合并到Entry Tree , 这一优化可以大大提升插入数据到Gin索引的性能 。 另外Gin索引存储TID集合时做了压缩处理 , 因此对于低基数的索引字段 , Gin索引能显著地节省存储空间 。
和常规的Btree索引相比 , Gin索引主要有如下优势:

  • 支持任意字段组合查询
  • 低基数字段的索引占用空间小
下面的测试数据可以更直观的反映Gin索引的优点 。
对于低基数的索引字段 , Gin占用空间甚至不到Btree的十分之一 。
3年部署3000套PG实例的架构设计与踩坑经验