系统设计技巧:使用Postgres作为发布/订阅和作业服务器

news2024/11/20 21:36:32

如果在项目中需要发布/订阅和作业服务器,可以尝试使用 Postgres。它将为您提供大量数据完整性和性能保证,并且不需要您或您的团队学习任何新技术。

如果你正在做任何足够复杂的项目,你将需要一个 发布/订阅[1] 服务器来处理事件。

本文将向你介绍 Postgres 实现的可行方案,并引导你了解 发布/订阅 的一个用例及其解决方案。

Postgres 是一个了不起的关系型数据库

如果你对 Postgres[2] 不太熟悉,它是一个功能丰富的关系型数据库,许多公司将其作为传统的中央数据存储。通过在 Postgres 中存储你的 user 表,你可以立即为每个 user 扩展到 100 列每行。

这是有可能的将 Postgres 扩展到完全在内存中存储 10 亿条 1KB 的行 - 这意味着你可以在商用硬件上快速执行针对地球上所有人的全名的查询,而且几乎不需要微调。

我不打算赘述这个叫做 PostgresSQL 的东西是一个好的 SQL数据库。我将向你展示一个更有趣的使用案例,在这个案例中,我们结合一些功能,将Postgres变成一个强大的发布/订阅和作业服务器。

Postgres 是一个强大的持久性发布/订阅服务器

如果你做了足够多的系统设计,你将不可避免地需要解决一个关于发布/订阅[1]架构的问题。我们在webapp.io[3]很快就遇到了这个问题 - 我们需要让测试运行页面的浏览者和 github[4] API 在执行任务的过程中得到通知。

对于你要使用哪种发布/订阅服务器,目前可以有有很多选择:

  • Kafka [5]

  • RabbitMQ [6]

  • Redis PUB/SUB [7]

  • 一个供应商绑定的云服务解决方案 [8]

  • Postgres?

很少有使用场景需要像 Kafka 那样的专业的发布/订阅服务器。Postgres 可以很容易地处理每秒 10,000 次的插入[9],而且它可以被调整到更高的数字。如果你从Postgres开始,然后在时机成熟时换掉系统中最关键的性能部分, 在这个过程中很少会出错。

发布/订阅 + 原子操作 ⇒ 不需要工作服务器

在上面的列表中,我跳过了与发布/订阅服务器类似的东西,称为 工作队列 - 它们每次只让一个 订阅者 观察新的 事件,并保留一个未处理事件的队列:

  • Celery[10]

  • Gearman[11] 

事实证明,Postgres 通常也会取代作业服务器。你可以让你的工人监听新事件通道,并在有新的工作被推送时尝试申请一个工作。好处是,Postgres让其他服务观察事件的状态,而不增加任何复杂性。

我们的用例:CI 运行着按照顺序处理的工作

在 webapp.io,当我们执行 test runs,首先是克隆一个资源库,然后运行一些用户指定的测试。有一些微服务开始为测试运行做各种初始化步骤,还有一些微服务(如 websocket 网关)需要监听任务运行的状态。

d2c737c80d4d8d8b01039b24e82bcc1b.png

一个 API 服务器的实例通过向Postgres表的 Runs 行插入一行来创建一个运行任务:

CREATE TYPE ci_job_status AS ENUM ('new', 'initializing', 'initialized', 'running', 'success', 'error');

CREATE TABLE ci_jobs(
 id SERIAL,
 repository varchar(256),
 status ci_job_status,
 status_change_time timestamp
);

/*在 API 调用*/
INSERT INTO ci_job_status(repository, status, status_change_time) VALUES ('https://github.com/colinchartier/layerci-color-test', 'new', NOW());

工人如何 申请 一份工作?通过原子化地设置工作状态:

UPDATE ci_jobs SET status='initializing'
WHERE id = (
  SELECT id
  FROM ci_jobs
  WHERE status='new'
  ORDER BY id
  FOR UPDATE SKIP LOCKED
  LIMIT 1
)
RETURNING *;

最后,我们可以使用一个触发器和一个通道来通知工人可能有新的工作:

CREATE OR REPLACE FUNCTION ci_jobs_status_notify()
 RETURNS trigger AS
$$
BEGIN
 PERFORM pg_notify('ci_jobs_status_channel', NEW.id::text);
 RETURN NEW;
END;
$$ LANGUAGE plpgsql;



CREATE TRIGGER ci_jobs_status
 AFTER INSERT OR UPDATE OF status
 ON ci_jobs
 FOR EACH ROW
EXECUTE PROCEDURE ci_jobs_status_notify();

工人所要做的就是 监听 到这个频道的状态,并在工作任务的状态发生变化时尝试申请工作:

tryPickupJob := make(chan interface{})
// 相当于 'LISTEN ci_jobs_status_channel;'
listener.Listen("ci_jobs_status_channel")
go func() {
  for event := range listener.Notify {
    select {
    case tryPickupJob <- true:
    }
  }
  close(tryPickupJob)
}

for job := range tryPickupJob {
  //try to "claim" a job
}

当我们把这些元素结合起来时,我们会得到类似以下的东西:

 f3fbcc3f6d570e5e505a95ee75fa241c.png

这种架构可以扩展到许多连续处理工作的工人,你所需要的只是为每个工作标记的 处理中 状态和 已处理 状态。对于 webapp.io 来说,这看起来像:新建、初始化、已初始化、运行、完成。它还允许其他服务观察 ci_jobs_status_channel - 我们的 /run 页面的websocket网关和github通知服务只是监听该通道,并通知任何相关方发布的事件。

使用Postgres作为发布/订阅服务器的其他好处

使用Postgres而不是像 Redis 发布/订阅这样的东西,还有一堆其他的好处:

  • 许多SQL用户已经安装了Postgres作为数据库使用,所以在发布/订阅中使用它不需要额外的设置

  • 作为一个数据库,Postgres 有很好的持久性保证 - 很容易通过查询找出 死掉 的作业,例如,通过 SELECT \* FROM ci_jobs WHERE status='initializing' AND NOW() - status_change_time > '1 hour'::interval 来处理工人崩溃或挂起的情况

  • 由于作业是用 SQL 定义的,所以很容易生成 graphql 和 protobuf 的表示(即提供检查运行状态的API

  • 很容易有多个状态变化的观察者,你可以让其他服务使用相同的 LISTEN ci_jobs_status_channel -Postgres有很好的编程语言支持,对大多数流行语言都有绑定。这与其他大多数发布/订阅 服务器有着明显的区别

  • 你还可以对仍在你的 工作队列 中的事物运行复杂的 SQL 查询,以向你的用户提供高度定制的 API 端点

总结

如果你在项目的任何阶段需要一个发布/订阅或工作服务器,从使用Postgres开始也不失为一个好主意。它将为你提供大量的数据完整性和性能保证,而且它不需要你或你的团队学习任何新的技术。

相关链接:

[1]https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern

[2]https://www.postgresql.org/

[3]https://webapp.io/

[4]https://github.com/

[5]https://kafka.apache.org/

[6]https://www.rabbitmq.com/

[7]https://redis.io/topics/pubsub

[8]https://cloud.google.com/pubsub/docs/overview

[9]https://severalnines.com/blog/benchmarking-postgresql-performance

[10]http://www.celeryproject.org/

[11]http://gearman.org/

原文地址:

https://webapp.io/blog/postgres-is-the-answer/

原文作者:

Colin Chartier

本文永久链接:

https://github.com/gocn/translator/blob/master/2022/w51_System_design_hack_Postgres_is_a_great_pub_sub_&_job_server.md

译者:Cluas

校对:Jancd

往期推荐

a90703db5952e15fcaae8165c112cc84.jpeg

一文读懂 Go Http Server 原理

380113806876cbc6480c26346a8d72bf.jpeg

Golang vs Rust ——服务端编程应该选择哪种语言

f43e57ce9fe7d06b69ce940a91ffe998.jpeg

「每周译Go」了解 Go 中的 defer

想要了解Go更多内容,欢迎扫描下方👇关注公众号,回复关键词 [实战群]  ,就有机会进群和我们进行交流

6a983ddceb2486efab894892a484dbb9.png

分享、在看与点赞Go 7f8765aab626e91017d4375553c0c067.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/159214.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

黑马“兔年限定”春节礼盒准时送达,快来领!

哈咯艾瑞巴蒂&#xff0c;我是播妞前几天一个热搜引起了我的注意# 原来兔年要打384天的工 #看到这标题播妞突然头皮发紧我搜索了一下&#xff0c;原来是......农历癸卯兔年全年共有384天今年的春节是2023年1月22号2024年的春节是2月10号从今年春节到明年的春节算一年由于“闰二…

XCTF:ics-05

测试了所有功能点&#xff0c;大部分没有做出来&#xff0c;只有设备维护中心可以点击 查看源码&#xff0c;发现云平台设备维护中心这里有一个超链接 看到变量传参page&#xff0c;有点像页面文件包含功能&#xff0c;那有可能存在文件包含&#xff0c;测试下&#xff1a; …

ORB-SLAM2 --- LoopClosing::CorrectLoop函数

目录 1.函数作用 2.函数流程 3.code 4.函数解析 4.1 结束局部地图线程、全局BA&#xff0c;为闭环矫正做准备 4.2 根据共视关系更新当前关键帧与其它关键帧之间的连接关系 4.3 通过位姿传播&#xff0c;得到Sim3优化后&#xff0c;与当前帧相连的关键帧的位姿&#xf…

什么是计算机中的高速公路-总线?

文章目录总线是什么&#xff1f;常见总线类型有哪些&#xff1f;总线的串行和并行的区别&#xff1f;数据总线地址总线CPU的寻址能力32位CPU最大支持4G内存&#xff1f;控制总线总线的共享性和独自性系统总线的结构单总线结构双总线结构三总线结构总线传输的四个阶段总线仲裁集…

谷粒商城项目笔记之高级篇(二)

目录1.7 认证服务1.7.1 环境搭建1&#xff09;、创建认证服务微服务2&#xff09;、引入依赖3)、添加相应的域名4&#xff09;、动静分离5&#xff09;、nacos中注册6&#xff09;、配置网关7)、测试访问登录页面8&#xff09;、实现各个页面之间跳转1.7.2 验证码功能1)、验证码…

C++的类介绍(封装特性)

一、类的定义 1.1定义 类是c语言对编程思想的概括深化&#xff0c;其前期的C语言使能面向过程的语言&#xff0c;思想是注重对程序每一步的理解&#xff1b;而面向过程的是C语言之父把生活的类与对象的思想应用于程序设计之中&#xff0c;把程序抽象成一个个对象。 C面向对象…

将时间序列转换为指定的频率并指定填充方法来填充缺失值的DataFrame.asfreq()方法

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 时间序列的插值操作 提升序列中时间密度 DataFrame.asfreq() 选择题 关于以下python代码说法错误的一项是? import pandas as pd myIndexpd.date_range(1/12/2023,periods3,freqT) dfpd.D…

深入了解 LinkedBlockingQueue阻塞队列

1. 前言 今天来逐个方法解析下LinkedBlockingQueue. 其实跟上篇文件深入了解ArrayBlockingQueue 阻塞队列很类似。只不过底层实现不同。其实看名字就能看出来到底依据什么实现的。好了&#xff0c;废话不多说了&#xff0c;接下来让我们开始吧 至于API的使用情况跟ArrayBlockin…

JS垃圾回收

什么是GC GC就是Garbage Collection,程序工作过程中会产生很多垃圾&#xff0c;这些垃圾是程序不用的内存或者是之前用过了&#xff0c;以后不会再用的内存空间&#xff0c;而GC就是负责回收垃圾的。当然也不是所有的语言都会自带GC&#xff0c;比如Java、Python、Javascript等…

电脑修改用户(User)文件夹名称

情景&#xff1a;Windows 11 的用户名与 C 盘&#xff08;系统盘&#xff09;中的文件夹名称不对应&#xff08;可能是由于重装系统导致的&#xff09;&#xff0c;例如我笔记本中系统用户名是 “fly”&#xff0c;但文件夹名称却是“16490”。 Step 1&#xff1a;打开Administ…

智能图像处理:基于边缘去除和迭代式内容矫正的复杂文档图像校正

本文简要介绍ACM MM 2022录用论文“Marior: Margin Removal and Iterative Content Rectification for Document Dewarping in the Wild”的主要工作。该论文针对现有的矫正方法只能在紧密裁剪的文档图像上获得较为理想的矫正效果这一不足&#xff0c;提出了一个新的矫正方法Ma…

基于webrtc多人音视频的研究(一)

众所周知&#xff0c;WebRTC非常适合点对点&#xff08;即一对一&#xff09;的音视频会话。然而&#xff0c;当我们的客户要求超越一对一&#xff0c;即一对多、多对一设置多对多的解决方案或者服务&#xff0c;那么问题就来了&#xff1a;“我们应该采用什么样的架构&#xf…

利用AirTest实现自动安装APK-跳过vivo手机安装验证

利用AirTest实现自动安装APK-跳过vivo手机安装验证 前言 最近在帮测试组看个问题&#xff0c;他们在自动化测试的时候&#xff0c;通过adb install 命令在vivo手机上安装apk的时候出现”外部来源应用&#xff0c;未经vivo安全性和兼容性检测&#xff0c;请谨慎安装“的提示页面…

仅需一行Python代码,为图片上版权!

哈啰&#xff0c;大家好&#xff0c;我是派森酱&#xff0c;一个Python技术爱好者。今天一个朋友跟我吐槽&#xff1a;前段时间&#xff0c;我辛辛苦苦整理的一份XX攻略&#xff0c;分享给自己的一些朋友&#xff0c;结果今天看到有人堂而皇之地拿着这份攻略图片去引流&#xf…

多项目同时进行时,做好进度管理很重要

进行多项目同时进行时&#xff0c;做好进度管理非常重要。最简单的方法是使用项目管理软件&#xff0c;可以帮助你组织和跟踪多项目的进度。 此外&#xff0c;需要定期审核每个项目的进度&#xff0c;并对项目进行必要的调整&#xff0c;以确保每个项目都能按时完成。 1、多项…

1579_AURIX_TC275_MTU中的ECC机理以及各种寄存器实现

全部学习汇总&#xff1a; GreyZhang/g_TC275: happy hacking for TC275! (github.com) 这一夜的信息全是寄存器地址信息&#xff0c;在了解功能的时候都是非关键信息。后续的内容整理中&#xff0c;这部分类似的信息我都会跳过。 在这个系列的MCU中&#xff0c;ECC实现了单bit…

Angular CLI命令详解

Angular CLI自身操作 显示版本 ng version 或 ng v 这条命令除了显示当前的cli的版本号&#xff0c;还显示LOGO&#xff0c;运行环境等内容&#xff1a; 显示帮助 ng --help 或 ng <sub cmd> --help 比如&#xff1a; ng build --help 如果记不住命令&#x…

数据库,计算机网络、操作系统刷题笔记32

数据库&#xff0c;计算机网络、操作系统刷题笔记32 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

BGP-路由反射器、联邦实验(1.11)

目标&#xff1a; 1、首先需要基于该与拓扑图对172.16.0.0/16进行子网划分&#xff1a; 题中一共需要八个网段的环回和一个骨干链路共8个网段&#xff1b; 172.16.0.0 20 骨干 再分为八个&#xff1a; 172.16.0.0 30 172.16.0.4 30 172.16.0.8 30 172.16.0.12 30 172.16.0.…

1、基本数据类型

目录 一、数值类型 1.整数类型 2.浮点数类型 3.复数 4.无穷量&#xff08;Inf&#xff09;和非数值量&#xff08;NaN&#xff09; 二、逻辑类型 一、数值类型 数值类型数据的分类&#xff1a; 注意&#xff1a;在未加说明与特殊定义时&#xff0c;MATLAB对所有数值按照…