Postgres 可以替代 Redis 作为缓存吗?
nanshan 2024-12-12 14:07 12 浏览 0 评论
近期,一篇名为“Postgres 可以替代 Redis 作为缓存吗?”的文章在Medium迅速出圈,这一新颖的话题,似乎能带来不少实际项目的启示,下面跟随着作者Raphael De Lio来解读这一疑问。
我在Twitter上询问大家了一个问题:你想到的第一个消息队列是什么?
其中一个回答引起我的注意:Postgres
“使用 Postgres 作为消息队列,并使用 SKIP LOCKED 代替 Kafka(如果你只需要一个消息队列的话)”。— Stephan Schmid
更令我惊讶的是,还有提出使用Postgres作为缓存来替代 Redis的观点。
“使用 Postgres 进行缓存,而不是 Redis。使用 UNLOGGED 表和 TEXT 作为 JSON 数据类型。存储过程可以使用 ChatGPT 编写,添加和强制执行数据的到期日期,就像在 Redis一样”。— Stephan Schmidt
在我学习 Redis 的过程中,我经常听到很多人(来自 Redis)提倡:Redis可以成为你的主要数据库。
这可能是一个好主意。Redis是一个真正的数据库,只是因为它速度非常快,可以在一秒钟内执行数百万次操作,被大家常用来作为缓存。
而当我看到最喜欢的关系型数据库 Postgres 可以取代我最喜欢的非关系型数据库 Redis 时,我的世界发生了翻天覆地的变化。我应该用Postgres取代 Redis,还是用Redis取代Postgres?
在考虑这个问题之前,我想先搞清楚:Postgres作为缓存真的是个好主意吗?它真的可以取代 Redis 吗?
Stephan Schmidt主张用 Postgres 替换 Redis(实际上他主张用 Postgres 替换一切),他认为这样做可以消除一定的复杂性。(请阅读:https://medium.com/@AmazingCTO)
“一切都用 Postgres 吧(如何降低复杂性并加快速度)” — Stephan Schmid
然而,他并不是唯一一个主张更换 Redis 的人,也有人做了同样的事情:
但首先,我为什么要用 Postgres 替换 Redis?
Stephan 已经给出了两个理由:复杂性更低和变化更快。是否还有其他驱动因素呢?
使用 Postgres 作为缓存虽不是常见的选择,但在某些情况下具有一定的优势:
统一技术栈
Postgres 是最流行的数据库之一,且开源免费,将其用作缓存可以减少管理和维护多个数据库系统的工作,从而简化技术堆栈。
熟悉的界面
Postgres 支持复杂的查询和索引,特别是对于精通 SQL的人来说,直接在缓存层内处理高级数据检索和转换任务会更加容易。
成本
某些情况下,使用现有的 Postgres 资源进行缓存,可能比部署单独的缓存解决方案(如 Redis)更具成本效益。尤其是在基础设施预算有限的环境中,将 Postgres 同时用作主存储和缓存可以提高资源利用率。
我们对缓存服务有怎样的目标?
传统缓存服务(例如 Redis)具有一系列可增强应用程序性能和可扩展性的功能,Postgres 是否真的可以取代 Redis,需要从以下几个关键层面考量:
表现
缓存服务的主要目标,是通过加快数据访问速度,来提高应用程序的性能。
高性能缓存解决方案可以处理高吞吐量工作负载,并提供亚毫秒级的响应时间,从而显著加快检索数据的进程。
删除策略
通过设置缓存数据的过期时间,让过期数据在指定时间后自动从缓存中删除。确保过期数据不会提供给应用程序。
逐出策略
缓存服务通常将其数据保存在内存中,而内存一般是有限的。因此,需要设置逐出策略让我们自动删除不常用的数据,为新数据腾出空间。
键值存储
大多数缓存服务的核心都是以键值对的形式存储数据。这种简单但功能强大的模型可以快速检索数据,从而轻松高效地存储和访问常用数据。
简而言之,缓存服务需要更快地访问数据并返回尽可能最新的数据。
怎样才能将 Postgres 变成缓存?
Stephan 和 Martin 都表示,我们可以通过使用 UNLOGGED 表将 Postgres 变成缓存服务。
结合Martin Heinz《你不需要专用的缓存服务 - PostgreSQL 作为缓存》这篇文章内容(链接:https://martinheinz.dev/blog/105),得到了这些答案:
未记录表和预写日志
Postgres 中的未记录表是一种防止特定表生成 WAL(预写日志)的方法。
反言之,WAL可确保对数据库所做的所有更改,在实际写入数据库文件之前都已记录。在系统崩溃和断电等极端情况的时候,就有助于维护数据完整性。
补充说明:Redis提供了一种类似的机制,称为仅附加文件 (AOF) ,它不仅提供了一种在 Redis中持久保存数据的机制,而且还以类似的方式运行,即记录在 Redis 中执行的所有操作。如果使用 Redis 作为主数据库,我们会启用 AOF ,而如果使用 Postgres 作为缓存,我们会关闭(在特定表上)WAL。
关闭WAL提高性能
对于每次数据修改,Postgres 必须更改写入 WAL 和数据文件。这使所需的写入操作数量加倍。
除此之外,为了确保每个已提交的事务都物理写入磁盘,WAL被设计为强制执行磁盘刷新 (fsync)。频繁的磁盘刷新操作会影响性能,因为它们会引入等待磁盘确认数据已安全写入的延迟。
放弃坚持
未记录表不是持久的。
Postgres会使用WAL来重放和应用自上次检查点以来所做的任何更改,如果我 们没有此日志记录,则无法通过重放WAL记录将数据库恢复到一致状态。但这也是缓存的一大特点。
CREATE UNLOGGED TABLE cache (
id serial PRIMARY KEY,
key text UNIQUE NOT NULL,
value jsonb,
inserted_at timestamp);
CREATE INDEX idx_cache_key ON cache (key);
存储过程的过期
Martin 和 Stephan 都表示,可以使用存储过程来实现过期,这会导致一定的复杂性。
因此,Stephan甚至更进一步建议我们使用ChatGPT来编写存储过程。
CREATE OR REPLACE PROCEDURE expire_rows (retention_period INTERVAL) AS
$
BEGIN
DELETE FROM cache
WHERE inserted_at < NOW() - retention_period;
COMMIT;
END;
$ LANGUAGE plpgsql;
CALL expire_rows('60 minutes'); -- This will remove rows older than 1 hour
然而事实是,大多数现代应用程序不再依赖存储过程,而且现在很多软件开发人员都反对使用存储过程,以此避免把业务逻辑泄露到数据库中,且随着存储数据的增加,管理和理解会变得更为麻烦。
此外,我们还需要按计划调用这些存储过程。为此,我们需要使用一个扩展 pg_cron 。安装扩展后,我们仍然需要创建调度程序:
-- Create a schedule to run the procedure every hour
SELECT cron.schedule('0 * * * *', $CALL expire_rows('1 hour');$);
-- List all scheduled jobs
SELECT * FROM cron.job;
然而,复杂性还在持续增加。
存储过程逐出策略
Stephan在他的文章中没有提到逐出策略,而Martin则表示,由于过期可以保持存储大小,因此也可以作为一个选择。
但是,如果仍然想要启用逐出策略,Martin建议在我们的表中添加一个名为 last_read_timestamp的列,并偶尔运行另一个存储过程来实现“最近使用”(LRU)逐出策略。
CREATE OR REPLACE PROCEDURE lru_eviction(eviction_count INTEGER) AS
$
BEGIN
DELETE FROM cache
WHERE ctid IN (
SELECT ctid
FROM cache
ORDER BY last_read_timestamp ASC
LIMIT eviction_count
);
COMMIT;
END;
$ LANGUAGE plpgsql;
-- Call the procedure to evict a specified number of rows
CALL lru_eviction(10); -- This will remove the 10 least recently accessed rows
Redis 提供了八种现成的逐出策略(官方文档:https://redis.io/docs/latest/develop/reference/eviction/)。如果想要为“Postgres Cache”设置另一种逐出策略?问ChatGPT即可。
性能表现如何?
性能表现是缓存服务选型的决定性因素,因为我们需要缓存服务的主要原因是想更快地访问的数据。
Greg Sabino Mullane在他的文章《PostgreSQL Unlogged Tables — Look Ma, No WAL! 》中展示了测试结果(原文链接:https://www.crunchydata.com/blog/postgresl-unlogged-tables),比较了 Postgres 中 UNLOGGED 和 LOGGED 表的性能。数据显示, 写入 UNLOGGED 表的性能是在 LOGGED 表中执行相同操作的两倍。具体数据如下:
- 未记录表
延迟:2.059 ms
TPS:485,706168
- 记录表
延迟:5.949 ms
TPS:168,087557
读写表现如何呢?
这就是最大的问题:Postsgres 性能优化策略依赖于共享缓冲区。
共享缓冲区将经常访问的数据和索引直接存储在内存中,使其可以快速访问,并减少从磁盘读取的需要,提高已记录和未记录表的查询性能和数据访问能力。
未记录表可能留在这些缓冲区中,但如果它们变得太大或内存有限,它们则会被写入磁盘。因此,未记录表主要提高写入速度,而不是读取速度。
为了证明这一点,我使用进行了快速实验 pgbench (具体操作请见:GitHub - raphaeldelio/redis-postgres-cache-benchmark)
结果表明,记录表和未记录表的性能实际上非常相似,读取这两种类型的表平均需要大约 0.650 ms。具体数据如下:
- 未记录表
延迟:0.679 ms
TPS:14.724,204
- 记录表
延迟:0.627ms
TPS :15.946,025
这一结果测试进一步验证:未记录表主要增强了写入性能。
对于读取操作,未记录表的性能优势并不明显,因为记录表和未记录表都同样受益于 Postgres 的缓存和优化策略。
与 Redis 相比性能如何?
除了对 Postgres 进行基准测试之外,我还对 Redis 进行了实验。(具体操作请见:GitHub - raphaeldelio/redis-postgres-cache-benchmark)。结果显示,Redis在读写操作方面具有显著的性能优势:
- 读取
延迟 (p50) :0.095ms
每秒请求数 (RPS) :892.857,12
- 写入
延迟 (p50) :0.103ms
每秒请求数 (RPS) :892857,12
性能比较显示,Redis 在写入和读取操作方面都明显优于 Postgres:Redis只有 0.095ms的延迟, Postgres未记录表有0.679ms。
Redis还能处理更高的请求率,每秒 892,857.12 个请求,而 Postgres 每秒只能处理 15,946.025 个请求。
在写入操作方面,我们也可以看到Redis提供了更优异的性能,吞吐量明显更高,延迟也更低。
如果我在 RAM 中运行 Postgres 会怎样?
在审查本文的过程中,Xebia的同事Maksym Fedorov表示:
“ 如果现在在与内存映射文件对应的表空间中创建未记录表会怎么样?我猜我们会看到完全不同的数字。”
为了测试这一点,我使用保存在 RAM 中的 Postgres 数据运行了基准测试。 令人惊讶的是,结果没有任何改善。基准测试显示:
- 读取
延迟:0.652ms
每秒请求数 (TPS) :15329,776954
经过进一步研究,我了解到,即使数据存储在 RAM 中,在Postgres 的共享缓冲区内访问数据也会产生额外成本,这些成本来自管理锁,以及数据完整性和并发访问所需的其他内部进程。
而且,Postgres总是先检查数据是否在共享缓冲区中,如果不在,它会先将数据从tmpfs文件系统复制到共享缓冲区中,然后再提供服务,即使数据库保存在 RAM中。
我应该用 Postgres 替换 Redis 吗?
综上所述,如果您需要缓存服务来提高写入性能,可以使用未记录表优化 Postgres。但是,虽然未记录表比记录表提供更好的写入性能,但与 Redis 相比仍然不足。
使用缓存服务的主要原因是缩短数据检索时间。未记录的表不会提高读取性能,而Redis则以极快的读取优势作为更优选择。
此外,Redis有助于防止大量低成本查询访问数据库,这是未记录表无法提供的优势。Redis还提供内置功能,如过期、逐出策略等,这些功能在 Postgres 中很难实现。
尽管对某些人来说,管理 Postgres 似乎更容易,但将 Postgres 变成缓存并不能提供专用缓存服务的优势。同时,Redis 的学习、部署和使用都很简单,而且很有趣。
所以为了获得更快的性能和简单性,选择像Redis这样真正的缓存服务似乎才是更明智的选择。
作者丨Raphael De Lio 编译丨Rio
来源丨https://medium.com/redis-with-raphael-de-lio/can-postgres-replace-redis-as-a-cache-f6cba13386dc
*本文为dbaplus社群编译整理,如需转载请取得授权并标明出处!欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn
相关推荐
- 服务器温度监控--lm-sensors(服务器温度怎么看)
-
lm-sensors是一款linux的硬件监控的软件,可以帮助我们来监控主板,CPU的工作电压,风扇转速、温度等数据。这些数据我们通常在主板的BIOS也可以看到。当我们可以在机器运行的时候通过...
- MySQL版本区别及管理(mysql版本最新版本)
-
MySQL版本区别及管理一.MySQL5.6与MySQL5.7安装的区别1、cmake的时候加入了bostorg2、初始化时使用mysqld--initialize替代mysql_install...
- Linux技术问答系列-NO4(linux必知必会)
-
一.绝对路径用什么符号表示?当前目录、上层目录用什么表示?主目录用什么表示?切换目录用什么命令?绝对路径:如/etc/init.d当前目录和上层目录:./../主目录:~/切换目录:cd二...
- 猫盘原版系统开启ssh教程(猫盘原版系统怎么样)
-
猫盘是之前网上流传许久的矿渣,默认其系统不支持SSH功能,为了能打开其SSH功能,我特意制作操作教程如下:1、到网盘下载相关软件,利用猫盘系统自带功能,将assets放入个人存储目录下,并牢记对应的...
- 一探究竟——天融信网闸TopRules7000
-
网闸即:安全隔离与信息交换系统,常用作企业内外网隔离与业务互访用途。相比给服务器加多块网卡跨多个网段来说,网闸提供了更加安全的方式。探究背景:某次,网闸配置新业务,重启设备查看是否生效,结果发现刚重启...
- 操作系统加固通用Linux篇(linux系统加固常见操作)
-
1检查是否配置登陆超时时间设置编辑vi/etc/profile文件,配置TMOUT将值设置为低于300.TMOUT=3002检查是否禁止root用户登录FTP设置如下将对应配置文件中,设置roo...
- zabbix agent的安装与配置(zabbix-agent安装)
-
Agent安装rpm-ivhzabbix-agent-3.2.4-1.el6.x86_64.rpm安装完成后,zabbixagent端已经安装完成了,zabbixagent端的配置目录位于/e...
- Linux基础命令之计划任务(linux计划任务crontab)
-
一、计划任务1、at只能执行一次语法:at时间服务:atd必须开启123[root@xuegod163~]#/etc/init.d/atdstatus#查看服务状态atd(pid2...
- Secure Delivery Center (SDC)安装指南二:Delivery Hub
-
免费下载SecureDeliveryCenter2015>7月23日软件分发管理神器SecureDeliveryCenter免费技术交流会,MyEclipse原厂商倾力主讲,敬请关注!...
- OpenWrt 常用命令及用法!!(openwrt常用功能)
-
OpenWrt是一个高度可定制的嵌入式Linux操作系统,常用于路由器等网络设备。以下是一些常见的OpenWrt命令及其详细解释和示例操作:一、系统信息相关命令1.`uname-a``u...
- Linux 设置定时任务crontab命令(linux定时任务cron表达式)
-
看了同事的脚本,发现他用了cron来自检自身的那个程序是否崩溃了,这是有多大的不自信才用这种机制的?点击(此处)折叠或打开$sudocat/var/spool/cron/crontabs/ro...
- vCenter纳管ESXI主机出错(vsphere esxi)
-
vCenter纳管主机的大致步骤为:(1)vc和esxi交换证书,确立信任;(2)esxi把自己的资源信息同步到VC,VC建立清单。(3)VC在esxi建立几个操作用户;(4)然后下发...
- 从选购到安装 小白也能看懂的超全NAS经验分享
-
0.篇首语Hello大家好,我是KC,上一篇器材和工作流分享的文章里,有小伙伴问我怎么没有提到NAS?其实是因为前段时间碰巧更换了一台新NAS,折腾了一段时间很多内容还没来及整理和汇总,今天就...
- 手把手教你!如何在 Linux 服务器中搭建 Sentinel 环境?
-
你在Linux服务器上搭建Sentinel环境时,是不是也遇到过各种报错,要么是启动失败,要么是配置后无法正常访问控制台?看着同事顺利搭建好,自己却一头雾水,别提多着急了!其实,很多互联网大厂...
- 服务器被暴力破解的解决办法(二)(服务器被攻破严重吗)
-
上一次,我们说到小王公司服务器遭遇暴力破解,拿到解决方案回公司就开始部署。部署完成后的确起到了一定的效果,不过接下来的一个问题让他很头疼,原来黑客虽然攻入不进系统,但是依旧不依不饶的进行暴力破解。...
你 发表评论:
欢迎- 一周热门
-
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
如何修复用户配置文件服务在 WINDOWS 上登录失败的问题
-
手机如何设置与显示准确时间的详细指南
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
FANUC 0i-TF数据备份方法(fanuc系统备份教程)
-
NAS:DS video/DS file/DS photo等群晖移动端APP远程访问的教程
-
- 最近发表
-
- 服务器温度监控--lm-sensors(服务器温度怎么看)
- MySQL版本区别及管理(mysql版本最新版本)
- Linux技术问答系列-NO4(linux必知必会)
- 猫盘原版系统开启ssh教程(猫盘原版系统怎么样)
- 一探究竟——天融信网闸TopRules7000
- 操作系统加固通用Linux篇(linux系统加固常见操作)
- zabbix agent的安装与配置(zabbix-agent安装)
- Linux基础命令之计划任务(linux计划任务crontab)
- Secure Delivery Center (SDC)安装指南二:Delivery Hub
- OpenWrt 常用命令及用法!!(openwrt常用功能)
- 标签列表
-
- linux 查询端口号 (58)
- docker映射容器目录到宿主机 (66)
- 杀端口 (60)
- yum更换阿里源 (62)
- internet explorer 增强的安全配置已启用 (65)
- linux自动挂载 (56)
- 禁用selinux (55)
- sysv-rc-conf (69)
- ubuntu防火墙状态查看 (64)
- windows server 2022激活密钥 (56)
- 无法与服务器建立安全连接是什么意思 (74)
- 443/80端口被占用怎么解决 (56)
- ping无法访问目标主机怎么解决 (58)
- fdatasync (59)
- 405 not allowed (56)
- 免备案虚拟主机zxhost (55)
- linux根据pid查看进程 (60)
- dhcp工具 (62)
- mysql 1045 (57)
- 宝塔远程工具 (56)
- ssh服务器拒绝了密码 请再试一次 (56)
- ubuntu卸载docker (56)
- linux查看nginx状态 (63)
- tomcat 乱码 (76)
- 2008r2激活序列号 (65)