我們需要談談困擾我幾個月的事情。我一直看到獨立駭客和新創公司創始人瘋狂地拼湊各種技術棧,用 Redis 做緩存,用 RabbitMQ 做隊列,用 Elasticsearch 做搜尋,還有用 MongoDB……為什麼?
我也犯過這種錯誤。當我開始建立UserJot (我的回饋和路線圖工具)時,我的第一個反應是規劃一個「合適的」架構,為所有功能提供獨立的服務。然後我停下來問自己:如果我把所有功能都用 Postgres 來做會怎麼樣?
事實證明,房間裡有一頭大象,但沒人願意承認:
Postgres 幾乎可以做到這一切。
而且它的效果比你想像的還要好。
讓我猜猜——有人告訴你,Postgres“只是一個關係資料庫”,需要專門的工具來完成專門的工作。我以前也是這麼想的,直到我發現 Instagram 可以在單一 Postgres 實例上擴展到 1400 萬用戶。 Discord 處理數十億訊息。 Notion 的整個產品都是基於 Postgres 建構的。
但問題是:他們不再像 2005 年那樣使用 Postgres。
別再花錢買 Redis 和 RabbitMQ 了。 Postgres 原生支援LISTEN
/ NOTIFY
,處理作業佇列比大多數專用解決方案都好:
-- Simple job queue in pure Postgres
CREATE TABLE job_queue (
id SERIAL PRIMARY KEY,
job_type VARCHAR(50),
payload JSONB,
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
processed_at TIMESTAMP
);
-- ACID-compliant job processing
BEGIN;
UPDATE job_queue
SET status = 'processing', processed_at = NOW()
WHERE id = (
SELECT id FROM job_queue
WHERE status = 'pending'
ORDER BY created_at
FOR UPDATE SKIP LOCKED
LIMIT 1
)
RETURNING *;
COMMIT;
這讓你無需任何額外的基礎設施就能實現 Exactly-Once 的處理。不妨試試用 Redis 來實現,輕鬆搞定。
在 UserJot 中,我正是使用這種模式來處理回饋提交、發送通知和更新路線圖專案。只需一次事務,即可保證一致性,無需訊息代理的複雜性。
Redis 在大多數平台上的最低價格為 20 美元/月。 Postgres JSONB 已包含在您現有的資料庫中,可滿足您的大部分需求:
-- Your Redis alternative
CREATE TABLE kv_store (
key VARCHAR(255) PRIMARY KEY,
value JSONB,
expires_at TIMESTAMP
);
-- GIN index for blazing fast JSON queries
CREATE INDEX idx_kv_value ON kv_store USING GIN (value);
-- Query nested JSON faster than most NoSQL databases
SELECT * FROM kv_store
WHERE value @> '{"user_id": 12345}';
@>
運算子是 Postgres 的秘密武器。它比大多數 NoSQL 查詢更快,而且資料保持一致。
Elasticsearch 集群價格昂貴且複雜。 Postgres 內建的全文搜尋功能非常出色:
-- Add search to any table
ALTER TABLE posts ADD COLUMN search_vector tsvector;
-- Auto-update search index
CREATE OR REPLACE FUNCTION update_search_vector()
RETURNS trigger AS $$
BEGIN
NEW.search_vector := to_tsvector('english',
COALESCE(NEW.title, '') || ' ' ||
COALESCE(NEW.content, '')
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Ranked search results
SELECT title, ts_rank(search_vector, query) as rank
FROM posts, to_tsquery('startup & postgres') query
WHERE search_vector @@ query
ORDER BY rank DESC;
這可以處理模糊匹配、詞幹提取和相關性排名。
對於 UserJot 的回饋搜尋,此功能可讓使用者跨標題、描述和評論即時查找功能請求。無需 Elasticsearch 叢集 - 只需使用 Postgres 即可發揮其優勢。
忘掉複雜的 WebSocket 基礎架構吧。 Postgres LISTEN
/ NOTIFY
無需任何附加服務即可為您提供即時更新:
-- Notify clients of changes
CREATE OR REPLACE FUNCTION notify_changes()
RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('table_changes',
json_build_object(
'table', TG_TABLE_NAME,
'action', TG_OP,
'data', row_to_json(NEW)
)::text
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
您的應用程式會監聽這些通知並向使用者推播更新。無需 Redis 的發布/訂閱機制。
我們來算一下。一個典型的「現代」堆疊的成本是:
Redis:20美元/月
訊息隊列:25美元/月
搜尋服務:50美元/月
監控 3 項服務:30 美元/月
總計:每月 125 美元
但這還只是託管成本。真正的痛點在於:
營運開銷:
三種不同的服務用於監控、更新和除錯
不同的縮放模式和故障模式
需要維護多種配置
單獨的備份和災難復原程序
每項服務的安全考量不同
開發複雜性:
不同的客戶端庫和連線模式
協調多個服務的部署
系統間資料不一致
複雜的測試場景
不同的效能調優方法
如果您自行託管,請新增伺服器管理、安全性修補程式以及 Redis 決定消耗所有記憶體時不可避免的凌晨 3 點偵錯工作階段。
Postgres 使用您已經管理的單一服務來處理所有這些。
大多數人可能沒有意識到:單一 Postgres 實例就能處理大量資料。我們指的是每天數百萬筆交易、數 TB 的資料以及數千個並發連接。
真實世界的例子:
Airbnb:單一 Postgres 集群處理數百萬個預訂
Robinhood:數十億筆金融交易
GitLab:Postgres 上的整個 DevOps 平台
Postgres 的架構魅力非凡。它被設計成具備極佳的垂直擴展能力,而當你最終需要水平擴展時,它也有以下成熟的方案可供選擇:
用於查詢擴充功能的讀取副本
大表分區
並發連接池
分散式設定的邏輯複製
大多數企業從未達到這些限制。在處理數百萬用戶或複雜的分析工作負載之前,單一實例可能就足夠了。
將此與管理所有以不同方式擴展的單獨服務進行比較 - 您的 Redis 可能會耗盡內存,而您的訊息隊列則會遇到吞吐量問題,並且您的搜尋服務需要完全不同的硬體。
現代開發中最大的陷阱是架構式的「太空人」。當我們設計系統時,面對的是我們從未遇到過的問題,我們面對的是從未見過的流量,我們可能永遠無法達到的規模。
過度設計循環:
“我們可能有一天需要擴大規模”
新增 Redis、佇列、微服務、多個資料庫
花費數月時間除錯整合問題
向 47 位用戶推出
每月支付 200 美元購買可在 5 美元 VPS 上執行的基礎設施
同時,您的競爭對手的發貨速度更快,因為他們在需要分散式系統之前並沒有管理它。
更好的方法:
從 Postgres 開始
監控實際的瓶頸,而不是想像的瓶頸
當達到實際極限時擴展特定元件
僅在解決實際問題時才增加複雜性
你的用戶並不關心你的架構。他們關心的是你的產品是否有效,是否能解決他們的問題。
別誤會我的意思──專用工具自有其用處。但你可能在以下情況之前不需要它們:
您每分鐘處理 100,000 多個作業
您需要亞毫秒級的快取回應
您正在對數 TB 的資料進行複雜的分析
您有數百萬並髮用戶
您需要具有特定一致性要求的全域資料分佈
如果您在 dev.to 上閱讀此文,那麼您可能還沒有到達那裡。
讓我大吃一驚的是:Postgres 可以同時充當您的主資料庫、快取、佇列、搜尋引擎和即時系統。同時也能在所有方面保持 ACID 事務。
-- One transaction, multiple operations
BEGIN;
INSERT INTO users (email) VALUES ('[email protected]');
INSERT INTO job_queue (job_type, payload)
VALUES ('send_welcome_email', '{"user_id": 123}');
UPDATE kv_store SET value = '{"last_signup": "2024-01-15"}'
WHERE key = 'stats';
COMMIT;
嘗試在 Redis、RabbitMQ 和 Elasticsearch 上執行此操作,不要哭泣。
Postgres 並不引人注目。它沒有華麗的網站,也沒有在 TikTok 上爆紅。但幾十年來,在其他資料庫興衰更迭之際,它一直默默地支撐著網路。
選擇簡單、可靠且有效的技術是有道理的。
僅從 Postgres 開始- 抵制加入其他資料庫的衝動
使用 JSONB 實現靈活性- 借助 SQL 的強大功能,您可以獲得無模式的優勢
在 Postgres 中實現隊列——節省資金和複雜性
只有在達到實際極限時才加入專用工具- 而不是想像中的極限
UserJot 的建構是這理念的完美測試案例。它是一個回饋和路線圖工具,需要:
提交回饋時即時更新
針對數千個功能請求進行全文搜尋
發送通知的後台作業
快取經常存取的路線圖
用於用戶偏好和設定的鍵值存儲
我的整個後端只有一個 Postgres 資料庫。沒有 Redis,沒有 Elasticsearch,沒有訊息佇列。從使用者驗證到即時 WebSocket 通知,一切都由 Postgres 處理。
結果如何?我的功能交付速度更快,需要除錯的部件更少,而且基礎設施成本也降到了最低。當使用者提交回饋、搜尋功能或取得路線圖變更的即時更新時,一切都由 Postgres 完成。
這不再只是理論上的。它正在實際生產中,透過真實的用戶和真實的資料發揮作用。
Postgres 或許好得過頭了。它功能強大,以至於大多數其他資料庫對於 90% 的應用程式來說都顯得多餘。業界一直在說服我們,所有事情都需要專門的工具,但或許我們只是把事情弄得比實際需要的更難。
你的新創公司不必成為分散式系統的樣板。它需要為真正的人解決真正的問題。 Postgres 讓你專注於此,而不是照顧基礎設施。
因此,下次有人建議加入 Redis 來“提高性能”或加入 MongoDB 來“提高靈活性”時,請問他們:“您是否真的先嘗試過在 Postgres 中執行此操作?”
答案可能會讓你大吃一驚。我知道,當我完全在 Postgres 上建立UserJot時,它就一直執行順暢。
您使用 Postgres 的經驗如何?除了傳統的關係型資料之外,您是否成功運用過它?我一直很想知道其他開發者是如何使用它的。如果您想了解 Postgres 真正無所不能的範例,請查看UserJot——它證明了您真的可以只用一個資料庫建立一個完整的 SaaS 系統。
原文出處:https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc