多租戶應用程序
在本教程中,我們將使用示例廣告分析數據集來演示如何使用 Citus
來支持您的多租戶應用程序。
注意
本教程假設您已經安裝並運行了
Citus
。 如果您沒有運行Citus
,則可以使用單節點Citus
中的選項之一在本地設置Citus
。https://docs.citusdata.com/en/v10.2/installation/single_node.html#development
數據模型和示例數據
我們將演示為廣告分析應用程序構建數據庫,公司可以使用該應用程序來查看、更改、分析和管理他們的廣告和活動(請參閱示例應用程序)。這樣的應用程序具有典型的多租戶系統的良好特性。 來自不同租戶的數據存儲在一個中央數據庫中,每個租戶都有自己數據的獨立視圖。
我們將使用三個 Postgres 表來表示這些數據。 要開始使用,您需要下載這些表的示例數據:
curl https://examples.citusdata.com/tutorial/companies.csv > companies.csv
curl https://examples.citusdata.com/tutorial/campaigns.csv > campaigns.csv
curl https://examples.citusdata.com/tutorial/ads.csv > ads.csv
如果您使用 Docker,則應使用 docker cp
命令將文件復制到 Docker
容器中。
docker cp companies.csv citus:.
docker cp campaigns.csv citus:.
docker cp ads.csv citus:.
創建表
首先,您可以先使用 psql
連接到 Citus coordinator
。
如果您使用原生 Postgres
,如我們的單節點 Citus
指南中安裝的那樣,coordinator
節點將在端口 9700
上運行。
psql -p 9700
如果您使用 Docker,您可以通過使用 docker exec
命令運行 psql
進行連接:
docker exec -it citus_master psql -U postgres
然后,您可以使用標准 PostgreSQL CREATE TABLE
命令創建表。
CREATE TABLE companies (
id bigint NOT NULL,
name text NOT NULL,
image_url text,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL
);
CREATE TABLE campaigns (
id bigint NOT NULL,
company_id bigint NOT NULL,
name text NOT NULL,
cost_model text NOT NULL,
state text NOT NULL,
monthly_budget bigint,
blacklisted_site_urls text[],
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL
);
CREATE TABLE ads (
id bigint NOT NULL,
company_id bigint NOT NULL,
campaign_id bigint NOT NULL,
name text NOT NULL,
image_url text,
target_url text,
impressions_count bigint DEFAULT 0,
clicks_count bigint DEFAULT 0,
created_at timestamp without time zone NOT NULL,
updated_at timestamp without time zone NOT NULL
);
接下來,您可以像在 PostgreSQL
中一樣在每個表上創建主鍵索引:
ALTER TABLE companies ADD PRIMARY KEY (id);
ALTER TABLE campaigns ADD PRIMARY KEY (id, company_id);
ALTER TABLE ads ADD PRIMARY KEY (id, company_id);
分布表和加載數據
我們現在將繼續告訴 Citus
將這些表分布在集群中的不同節點上。為此,您可以運行 create_distributed_table
並指定要分片的表和要分片的列。在這種情況下,我們將對 company_id
上的所有表進行分片。
SELECT create_distributed_table('companies', 'id');
SELECT create_distributed_table('campaigns', 'company_id');
SELECT create_distributed_table('ads', 'company_id');
對公司標識符上的所有表進行分片允許 Citus
將表放在一起,並允許跨集群使用主鍵、外鍵和復雜連接等功能。您可以在此處了解有關此方法的好處的更多信息。
- https://docs.citusdata.com/en/stable/sharding/data_modeling.html#colocation
- https://www.citusdata.com/blog/2016/10/03/designing-your-saas-database-for-high-scalability/
然后,您可以繼續使用標准 PostgreSQL \COPY
命令將我們下載的數據加載到表中。 如果您將文件下載到其他位置,請確保指定正確的文件路徑。
\copy companies from 'companies.csv' with csv
\copy campaigns from 'campaigns.csv' with csv
\copy ads from 'ads.csv' with csv
運行查詢
現在我們已經將數據加載到表中,讓我們繼續運行一些查詢。 Citus
支持標准的 INSERT
、UPDATE
和 DELETE
命令,用於在分布式表中插入和修改行,這是面向用戶的應用程序的典型交互方式。
例如,您可以通過運行插入一個新公司:
INSERT INTO companies VALUES (5000, 'New Company', 'https://randomurl/image.png', now(), now());
如果您想將公司所有活動的預算翻倍,您可以運行 UPDATE
命令:
UPDATE campaigns
SET monthly_budget = monthly_budget*2
WHERE company_id = 5;
這種操作的另一個例子是運行跨越多個表的事務。 假設您要刪除一個廣告系列及其所有相關廣告,您可以通過運行以原子方式執行:
BEGIN;
DELETE FROM campaigns WHERE id = 46 AND company_id = 5;
DELETE FROM ads WHERE campaign_id = 46 AND company_id = 5;
COMMIT;
事務中的每個語句都會導致多節點 Citus
中的 coordinator
和 worker
之間的往返。 對於多租戶工作負載,在分布式函數中運行事務效率更高。 對於較大的事務,效率提升變得更加明顯,但我們可以使用上面的小事務作為示例。
首先創建一個執行刪除的函數:
CREATE OR REPLACE FUNCTION
delete_campaign(company_id int, campaign_id int)
RETURNS void LANGUAGE plpgsql AS $fn$
BEGIN
DELETE FROM campaigns
WHERE id = $2 AND campaigns.company_id = $1;
DELETE FROM ads
WHERE ads.campaign_id = $2 AND ads.company_id = $1;
END;
$fn$;
接下來使用 create_distributed_function
指示 Citus
直接在 worker
上而不是在 coordinator
上運行該函數(除了在單節點 Citus
安裝上,它在 coordinator
上運行所有東西)。它將在任何持有與值 company_id
相對應的 ads
和 campaigns
表的分片的 worker
上運行該函數。
SELECT create_distributed_function(
'delete_campaign(int, int)', 'company_id',
colocate_with := 'campaigns'
);
-- you can run the function as usual
SELECT delete_campaign(5, 46);
除了事務操作,您還可以使用標准 SQL
運行分析查詢。 公司運營的一個有趣查詢是查看有關其具有最大預算的活動的詳細信息。
SELECT name, cost_model, state, monthly_budget
FROM campaigns
WHERE company_id = 5
ORDER BY monthly_budget DESC
LIMIT 10;
我們還可以跨多個表運行連接查詢,以查看有關運行獲得最多點擊次數和展示次數的廣告系列的信息。
SELECT campaigns.id, campaigns.name, campaigns.monthly_budget,
sum(impressions_count) as total_impressions, sum(clicks_count) as total_clicks
FROM ads, campaigns
WHERE ads.company_id = campaigns.company_id
AND campaigns.company_id = 5
AND campaigns.state = 'running'
GROUP BY campaigns.id, campaigns.name, campaigns.monthly_budget
ORDER BY total_impressions, total_clicks;
至此,我們結束了使用 Citus
為簡單的多租戶應用程序提供支持的教程。 下一步,您可以查看多租戶應用程序部分,了解如何為自己的多租戶數據建模。
實時應用程序分析
在本教程中,我們將演示如何使用 Citus
獲取事件數據並在人類實時的數據上運行分析查詢。 為此,我們將使用一個示例 Github
事件數據集。
數據模型和樣本數據
我們將演示為實時分析應用程序構建數據庫。 該應用程序將插入大量事件數據,並以亞秒級延遲對這些數據進行分析查詢。在我們的示例中,我們將使用 Github
事件數據集。該數據集包括 Github
上的所有公共事件,例如提交(commits)
、分叉(forks)
、新問題(new issues)
以及對這些問題的評論(comments)
。
我們將使用兩個 Postgres
表來表示這些數據。要開始使用,您需要下載這些表的示例數據:
curl https://examples.citusdata.com/tutorial/users.csv > users.csv
curl https://examples.citusdata.com/tutorial/events.csv > events.csv
如果您使用 Docker,則應使用 docker cp
命令將文件復制到 Docker
容器中。
docker cp users.csv citus:.
docker cp events.csv citus:.
創建表
首先,您可以先使用 psql
連接到 Citus
協調器。
如果您使用原生 Postgres,如我們的單節點 Citus
指南中安裝的那樣,coordinator
節點將在端口 9700
上運行。
psql -p 9700
如果您使用的是 Docker,則可以通過使用 docker exec
命令運行 psql
進行連接:
docker exec -it citus psql -U postgres
然后,您可以使用標准 PostgreSQL CREATE TABLE
命令創建表。
CREATE TABLE github_events
(
event_id bigint,
event_type text,
event_public boolean,
repo_id bigint,
payload jsonb,
repo jsonb,
user_id bigint,
org jsonb,
created_at timestamp
);
CREATE TABLE github_users
(
user_id bigint,
url text,
login text,
avatar_url text,
gravatar_id text,
display_login text
);
接下來,您可以像在 PostgreSQL
中那樣為事件數據創建索引。在本例中,我們還將創建一個 GIN
索引以更快地查詢 jsonb
字段。
CREATE INDEX event_type_index ON github_events (event_type);
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops);
分布表和加載數據
我們現在將繼續告訴 Citus
將這些表分布到集群中的節點上。為此,您可以運行 create_distributed_table
並指定要分片的表和要分片的列。在這種情況下,我們將對 user_id
上的所有表進行分片。
SELECT create_distributed_table('github_users', 'user_id');
SELECT create_distributed_table('github_events', 'user_id');
對用戶標識符上的所有表進行分片允許 Citus
將這些表放在一起,並允許有效的連接和分布式匯總。
然后,您可以繼續使用標准 PostgreSQL \COPY
命令將我們下載的數據加載到表中。 如果您將文件下載到其他位置,請確保指定正確的文件路徑。
\copy github_users from 'users.csv' with csv
\copy github_events from 'events.csv' with csv
運行查詢
現在我們已經將數據加載到表中,讓我們繼續運行一些查詢。 首先,讓我們檢查一下分布式數據庫中有多少用戶。
SELECT count(*) FROM github_users;
現在,讓我們分析一下我們數據中的 Github 推送事件。 我們將首先通過使用每個推送事件中不同提交的數量來計算每分鍾的提交數量。
SELECT date_trunc('minute', created_at) AS minute,
sum((payload->>'distinct_size')::int) AS num_commits
FROM github_events
WHERE event_type = 'PushEvent'
GROUP BY minute
ORDER BY minute;
我們還有一個用戶表。我們還可以輕松地將用戶加入事件,並找到創建最多存儲庫的前十名用戶。
SELECT login, count(*)
FROM github_events ge
JOIN github_users gu
ON ge.user_id = gu.user_id
WHERE event_type = 'CreateEvent' AND payload @> '{"ref_type": "repository"}'
GROUP BY login
ORDER BY count(*) DESC LIMIT 10;
Citus
還支持用於攝取和修改數據的標准 INSERT
、UPDATE
和 DELETE
命令。 例如,您可以通過運行以下命令來更新用戶的顯示登錄:
UPDATE github_users SET display_login = 'no1youknow' WHERE user_id = 24305673;
至此,我們的教程結束了。下一步,您可以查看實時應用程序部分,了解如何為自己的數據建模並為實時分析應用程序提供動力。