侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Instagram提升PostgreSQL性能的五个技巧

数据库  /  管理员 发布于 5年前   206

 随着Instagram的规模日益扩大,Postgres继续充当着Instagram的坚实基础,并存储着绝大部分的用户数据。不到一年之前,我们还曾在博客上说Instagram“存储着大量数据”,每秒增加90条数据,现在,这个数据已经增长到了峰值的10000条。而我们的基础存储技术依然保持不变。

在过去的两年半中,我们有一些关于Postgres扩展的经验和工具,想要分享出来。真希望在当初启动Instagram的时候就能有这些经验和工具呀。其中有些是Postgres独有的,有些是其它数据库也可以采用的。如果想要了解我们是如何水平分区的,可以看这篇文章。

1. 局部索引

如果我们经常需要按某个固定的特征过滤数据,而且这个特征只存在于一小部分行里,在这种情况下,局部索引非常有效。

比方说,Instagram搜索标签的时候,我们需要找出有许多照片的标签。我们一般会用ElasticSearch之类的技术来进行高级搜索,不过这里只靠数据库的查询能力就完全够了。先来看一下,按标签查询,并按照片数排序,Postgres是怎么做的:
 

EXPLAIN ANALYZE SELECT id from tags WHERE name LIKE 'snow%' ORDER BY media_count DESC LIMIT 10;   QUERY PLAN ---------          Limit (cost=1780.73..1780.75 rows=10 width=32) (actual time=215.211..215.228 rows=10 loops=1)  -> Sort (cost=1780.73..1819.36 rows=15455 width=32) (actual time=215.209..215.215 rows=10 loops=1)     Sort Key: media_count     Sort Method: top-N heapsort Memory: 25kB     -> Index Scan using tags_search on tags_tag (cost=0.00..1446.75 rows=15455 width=32) (actual time=0.020..162.708 rows=64572 loops=1)        Index Cond: (((name)::text ~>=~ 'snow'::text) AND ((name)::text ~<~ 'snox'::text))        Filter: ((name)::text ~~ 'snow%'::text) Total runtime: 215.275 ms(8 rows)

有没有看到,为了得到结果,Postgres不得不对15000行数据进行排序。由于标签的分布满足长尾模式(译者注: 根据百度百科,「我们常用的汉字实际上不多,但因出现频次高,所以这些为数不多的汉字占据了上图广大的红区;绝大部分的汉字难得一用,它们就属于那长长的黄尾。」),我们可以改为查询超过100张照片的标签,先建局部索引:
 
CREATE INDEX CONCURRENTLY on tags (name text_pattern_ops) WHERE media_count >= 100
然后查询,看一下新的查询计划:
 

EXPLAIN ANALYZE SELECT * from tags WHERE name LIKE 'snow%' AND media_count >= 100 ORDER BY media_count DESC LIMIT 10; QUERY PLAN Limit (cost=224.73..224.75 rows=10 width=32) (actual time=3.088..3.105 rows=10 loops=1)  -> Sort (cost=224.73..225.15 rows=169 width=32) (actual time=3.086..3.090 rows=10 loops=1)     Sort Key: media_count     Sort Method: top-N heapsort Memory: 25kB     -> Index Scan using tags_tag_name_idx on tags_tag (cost=0.00..221.07 rows=169 width=32) (actual time=0.021..2.360 rows=924 loops=1)        Index Cond: (((name)::text ~>=~ 'snow'::text) AND ((name)::text ~<~ 'snox'::text))        Filter: ((name)::text ~~ 'snow%'::text) Total runtime: 3.137 ms(8 rows)

可以看到,Postgres只需要访问169行,所以速度快得多。Postgres的查询计划器对约束的评估也很有效。如果以后想要查询超过500张照片的标签,由于这个结果集是上面集合的子集,所以仍然会使用这个局部索引。

2. 函数索引

在某些表上,我们需要对一些很长的字符串建立索引,比如说,64个字符的base64记号。如果直接建索引的话,会造成大量的数据重复,这种情况下,可以用Postgres的函数索引:
 

CREATE INDEX CONCURRENTLY on tokens (substr(token), 0, 8)

虽然这样会造成许多行匹配相同的前缀,但我们可以在匹配的基础上再用过滤,速度很快。而且索引很小,只有大概原来的十分之一。

3. 用pg_reorg来让数据更紧凑

随着时间的流逝,Postgres的表会变得越来越零碎(由MVCC并发模型等原因引起)。而且,数据行插入的顺序往往也不是我们希望返回的顺序。比如说,如果我们经常要按用户来查询照片等,那么最好是在磁盘上把这些东西放在一起,这样就可以减少磁盘寻道的时间。

我们用pg_reorg来解决这个问题,它用三个步骤来让“压紧”一个表:

  1.     取得表的独占锁
  2.     建一个记录变更的临时表,在原始表上加一个触发器,把对原始表的变更复制到临时表上
  3.     用CREATE TABLE...SELECT FROM...ORDER BY建表,新表拥有原始表的全部数据,而且是按索引顺序排序的
  4.     将CREATE TABLE执行时间点以后发生的变更从临时表同步过来
  5.     业务切换到新表

每一步都会有很多细节,不过大体上就是像上面这个样子。我们先对这个工具进行了一些审查,运行了若干测试,然后再把它用到生产环境上。现在,我们已经在几百台机器的环境上跑过几十次pg_reorg,没出现过任何问题。


4. 用WAL-E进行WAL(写前日志)的归档和备份

我们用WAL-E来归档WAL日志,它是Heroku写的一个工具,我们也向它贡献了一部分代码。WAL-E大大简化了数据备份和复制库创建的过程。

WAL-E是利用Progres的archive_command,将PG产生的每个WAL文件都归档到Amazon的S3。利用这些WAL文件和数据库的基准备份,我们可以将数据库恢复到基准备份后任何一个时间点的状态。利用这个手段,我们也可以快速创建只读的复制库或故障备用库。

我们为WAL-E写了一个简单的封装脚本,可以监控归档时的重复故障,见GitHub。
 
5. psycopg2中的自动提交模式和异步模式

我们也开始用psycopg2中的一些高级功能(psycopg2是Postgres的Python驱动)。

一个是自动提交模式。在这个模式里,psycopg2不会发出BEGIN/COMMIT,每个查询跑在自己的单语句事务里。这对不需要事务的只读查询特别有用。开启很简单:

connection.autocommit = True

开启自动提交后,我们的应用服务器和数据库之间的对话大减,数据库服务器的CPU用量也大减。而且,我们是用PGBouncer作为连接池,开启自动提交后,连接的归还也更快了。

与Django的交互细节可以看这里。


psycopg2还有一个很有用的功能,它可以通过注册一个等待回调(wait callback)函数,提供协同程序(coroutine)支持。它可以支持跨连接查询,对命中多个节点的查询非常有用,当有数据时,socket会被唤醒(我们利用Python的select模块来处理唤醒)。它也可以与eventlet和gevent等多线程库很好的协作,参考实现可见psycogreen。

总的来说,我们对Postgres的高性能和可靠性十分满意。想在世界上最大之一的Postgres集群上工作吗?想跟一群基础设施高手们一起干活吗?请联系[email protected]吧。


  • 上一条:
    设置CA证书来强化PostgreSQL的安全性的教程
    下一条:
    在PostgreSQL上安装并使用扩展模块的教程
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 分库分表的目的、优缺点及具体实现方式介绍(0个评论)
    • DevDB - 在 VS 代码中直接访问数据库(0个评论)
    • 在ubuntu系统中实现mysql数据存储目录迁移流程步骤(0个评论)
    • 在mysql中使用存储过程批量新增测试数据流程步骤(0个评论)
    • php+mysql数据库批量根据条件快速更新、连表更新sql实现(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2017-06
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-01
    • 2018-05
    • 2018-10
    • 2018-11
    • 2020-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2021-02
    • 2021-04
    • 2021-07
    • 2021-08
    • 2021-11
    • 2021-12
    • 2022-02
    • 2022-03
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-07
    • 2023-08
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-03
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客