Postgres 可以替代 Redis 作为缓存吗?
nanshan 2024-12-12 14:07 11 浏览 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
相关推荐
- Let’s Encrypt免费搭建HTTPS网站
-
HTTPS(全称:HyperTextTransferProtocoloverSecureSocketLayer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入...
- 使用Nginx配置TCP负载均衡(nginx tcp负载)
-
假设Kubernetes集群已经配置好,我们将基于CentOS为Nginx创建一个虚拟机。以下是实验种设置的详细信息:Nginx(CenOS8Minimal)-192.168.1.50Kube...
- Nginx负载均衡及支持HTTPS与申请免费SSL证书
-
背景有两台minio文件服务器已做好集群配置,一台是192.168.56.41:9000;另一台是192.168.56.42:9000。应用程序通过Nginx负载均衡调用这两台minio服务,减轻单点...
- HTTPS配置实战(https配置文件)
-
原因现在网站使用HTTPS是规范操作之一,前些日子买了腾讯云服务,同时申请了域名http://www.asap2me.top/,目前该域名只支持HTTP,想升级为HTTPS。关于HTTPS的链接过程大...
- 只有IP地址没有域名实现HTTPS访问方法
-
一般来说,要实现HTTPS,得有个注册好的域名才行。但有时候呢,咱只有服务器的IP地址,没注册域名,这种特殊情况下,也能照样实现HTTPS安全访问,按下面这些步骤来就行:第一步,先确认公网...
- 超详解:HTTPS及配置Django+HTTPS开发环境
-
众所周知HTTP协议是以TCP协议为基石诞生的一个用于传输Web内容的一个网络协议,在“网络分层模型”中属于“应用层协议”的一种。在这里我们并不研究该协议标准本身,而是从安全角度去探究使用该协议传输数...
- Godaddy购买SSL之后Nginx配置流程以及各种错误的解决
-
完整流程:参考地址:https://sg.godaddy.com/zh/help/nginx-generate-csrs-certificate-signing-requests-3601生成NGI...
- Nginx从安装到高可用,一篇搞定(nginx安装与配置详解)
-
一、Nginx安装1、去官网http://nginx.org/下载对应的nginx包,推荐使用稳定版本2、上传nginx到linux系统3、安装依赖环境(1)安装gcc环境yuminstallgc...
- 阿里云免费证书申请,配置安装,使用tomcat,支持http/https访问
-
参数说明商品类型默认已选择云盾证书服务(无需修改)。云盾证书服务类型SSL证书服务的类型。默认已选择云盾SSL证书(无需修改),表示付费版SSL证书。如果您需要免费领取或付费扩容DV单域名证书【免费试...
- 你试过两步实现Nginx的规范配置吗?极速生成Nginx配置小工具
-
NGINX是一款轻量级的Web服务器,最强大的功能之一是能够有效地提供HTML和媒体文件等静态内容。NGINX使用异步事件驱动模型,在负载下提供可预测的性能。是当下最受欢迎的高性能的Web...
- 从零开始搭建HTTPS服务(搭建https网站)
-
搭建HTTPS服务的最初目的是为了开发微信小程序,因为wx.request只允许发起HTTPS请求,并且还必须和指定的域名进行网络通信。要从零开始搭建一个HTTPS的服务需要下面4...
- 群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问
-
安全第一步,群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问【新手导向】NAS本质还是一个可以随时随地访问的个人数据存储中心,我们在外网访问的时候,特别是在公网IP下,其实会面临着很多安...
- 让网站快速升级HTTPS协议提高安全性
-
为什么用HTTPS网络安全越来越受到重视,很多互联网服务网站,都已经升级改造为https协议。https协议下数据包是ssl/tcl加密的,而http包是明文传输。如果请求一旦被拦截,数据就会泄露产生...
- 用Https方式访问Harbor-1.9版本(https访问流程)
-
我上周在头条号写过一篇原创文章《Docker-Harbor&Docker-kitematic史上最详细双系统配置手册》,这篇算是它的姊妹篇吧。这篇文章也将用到我在头条写的另一篇原创文章的...
- 如何启用 HTTPS 并配置免费的 SSL 证书
-
在Linux服务器上启用HTTPS并配置免费的SSL证书(以Let'sEncrypt为例)可以通过以下步骤完成:---###**一、准备工作**1.**确保域名已解析**...
你 发表评论:
欢迎- 一周热门
-
-
极空间如何无损移机,新Z4 Pro又有哪些升级?极空间Z4 Pro深度体验
-
如何在安装前及安装后修改黑群晖的Mac地址和Sn系列号
-
爱折腾的特斯拉车主必看!手把手教你TESLAMATE的备份和恢复
-
10个免费文件中转服务站,分享文件简单方便,你知道几个?
-
[常用工具] OpenCV_contrib库在windows下编译使用指南
-
日本海上自卫队的军衔制度(日本海上自卫队的军衔制度是什么)
-
【系统配置】信创终端挂载NAS共享全攻略:一步到位!
-
UOS服务器操作系统防火墙设置(uos20关闭防火墙)
-
Ubuntu系统Daphne + Nginx + supervisor部署Django项目
-
WindowsServer2022|配置NTP服务器的命令
-
- 最近发表
- 标签列表
-
- 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)