01. citusdb 快速教程

多租户应用程序

在本教程中,我们将使用一个示例广告分析数据集来演示如何使用 Citus 为多租户应用程序提供支持。

本教程假设您已经安装并运行了 Citus。如果没有运行 Citus,可以使用 Single-Node Citus 中的一个选项在本地设置 Citus。

数据模型和示例数据

我们将演示为一个广告分析应用程序建立数据库,公司可以用来查看,更改,分析和管理他们的广告和活动(见一个应用程序的例子)。这样的应用程序具有典型的多租户系统的良好特征。来自不同租户的数据存储在一个中央数据库中,每个租户都有自己数据的独立视图。

我们将使用三个 Postgres 表来表示这些数据。首先,您需要下载这些表的示例数据:

1
2
3
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

创建表

然后,可以使用标准的 PostgreSQL CREATE TABLE 命令创建表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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 中那样

1
2
3
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_distribution_table 并指定要分片的表和要分片的列。在这种情况下,我们将分割 company_id 上的所有表。

1
2
3
SELECT create_distributed_table('companies', 'id');
SELECT create_distributed_table('campaigns', 'company_id');
SELECT create_distributed_table('ads', 'company_id');

将公司标识符上的所有表分片可以让 Citus 将这些表放在一起,并允许在集群中使用主键、外键和复杂连接等特性。您可以在这里了解更多关于这种方法的好处。

然后,可以使用标准的 PostgreSQL copy 命令将我们下载的数据加载到表中。如果将文件下载到其他位置,请确保指定了正确的文件路径。

1
\copy companies from 'companies.csv' with csv;
1
\copy campaigns from 'campaigns.csv' with csv;
1
\copy ads from 'ads.csv' with csv;

行查询

现在我们已经将数据加载到表中,让我们继续并运行一些查询。Citus 支持标准的 INSERT、UPDATE 和 DELETE 命令,用于在分布式表中插入和修改行,这是面向用户的应用程序的典型交互方式。

例如,可以通过运行以下命令插入新公司:

1
INSERT INTO companies VALUES (5000, 'New Company', 'https://randomurl/image.png', now(), now());

如果您希望将公司所有活动的预算加倍,可以运行 UPDATE 命令:

1
2
3
UPDATE campaigns
SET monthly_budget = monthly_budget*2
WHERE company_id = 5;

这种操作的另一个示例是运行跨多个表的事务。假设你想删除一个活动及其所有相关的广告,你可以通过运行:

1
2
3
4
BEGIN;
DELETE FROM campaigns WHERE id = 46 AND company_id = 5;
DELETE FROM ads WHERE campaign_id = 46 AND company_id = 5;
COMMIT;

事务中的每个语句都会导致协调程序和多节点 Citus 中的工作程序之间的往返。对于多租户工作负载,在分布式函数中运行事务更有效。对于较大的事务,效率提高变得更加明显,但是我们可以使用上面的小事务作为例子。

首先创建一个执行删除操作的函数:

1
2
3
4
5
6
7
8
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 安装除外,它在协调器上运行所有内容)。它将在任何 worker 持有与 company_id 值相对应的表 ads 和 campaigns 的 Shards 上运行该函数。

1
2
3
4
5
6
7
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 运行分析查询。对于一家公司来说,一个有趣的查询是查看其最大预算活动的细节。

1
2
3
4
5
SELECT name, cost_model, state, monthly_budget
FROM campaigns
WHERE company_id = 5
ORDER BY monthly_budget DESC
LIMIT 10;

我们还可以跨多个表运行连接查询,以查看关于运行获得最多点击和印象的活动的信息。

1
2
3
4
5
6
7
8
9
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 ads.campaign_id = campaigns.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 为简单的多租户应用程序供电的教程。作为下一步,您可以查看 Multi-Tenant Apps 部分,了解如何为多租户建模自己的数据。

实时分析应用

在本教程中,我们将演示如何使用 Citus 摄取事件数据,并对该数据实时运行分析查询。为此,我们将使用一个示例 Github 事件数据集。

本教程假设您已经安装并运行了 Citus。如果没有运行 Citus,可以使用 Single-NodeCitus 中的一个选项在本地设置 Citus。

数据模型和示例数据

我们将演示如何为实时分析应用程序构建数据库。这个应用程序将插入大量的事件数据,并启用对这些数据的分析查询,其延迟不到一秒。在我们的示例中,我们将使用 Github 事件数据集。这个数据集包括 Github 上的所有公共事件,比如 commits、forks、new issues 和对这些问题的 comments。

我们将使用两个 Postgres 表来表示这些数据。首先,您需要下载这些表的示例数据:

1
2
curl https://examples.citusdata.com/tutorial/users.csv > users.csv
curl https://examples.citusdata.com/tutorial/events.csv > events.csv

创建表

首先,您可以首先使用 psql 连接到 Citus 协调器。

如果您正在使用本机 Postgres,正如我们的 Single-NodeCitus 指南中所安装的那样,协调节点将在端口 9700 上运行。

1
psql -p 9700

然后,可以使用标准的 PostgreSQL CREATE TABLE 命令创建表。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 字段。

1
2
CREATE INDEX event_type_index ON github_events (event_type);
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops);

分发表

我们将使用 citus 扩展直接加载数据。 首先需要确保已经在数据库中创建了扩展:

1
CREATE EXTENSION citus;

现在,我们将继续告诉 Citus 将这些表分布到集群中的各个节点。为此,可以运行 create_distribution_table 并指定要分片的表和要分片的列。在这种情况下,我们将分片 user_id 上的所有表。将用户标识符上的所有表分片使 Citus 可以将这些表共存在一起,并允许高效的连接和分布式汇总。

1
2
SELECT create_distributed_table('github_users', 'user_id');
SELECT create_distributed_table('github_events', 'user_id');

create_distributed_table() 是 Azure Cosmos DB for PostgreSQL 提供的 magic 函数,用于跨多台计算机分发表和使用资源。 该函数将表分解为分片,这些分片可以分布在各个节点,以提高存储和计算性能。

重要
需要分发表才能利用 citusdb 性能功能。 如果不分发表,则工作器节点无法帮助运行涉及这些表的查询。

加载数据

使用标准的 PostgreSQL COPY 命令将我们下载的数据加载到表中。如果将文件下载到其他位置,请确保指定了正确的文件路径。

1
2
\copy github_users from 'users.csv' with csv
\copy github_events from 'events.csv' with csv

实时分析-行查询

现在我们已经将数据加载到表中,让我们继续并运行一些查询。首先,让我们检查一下我们的分布式数据库中有多少用户。

1
SELECT count(*) FROM github_users;

现在,让我们分析数据中的 Github 推送事件。我们将首先使用每个推送事件中不同的提交数来计算每分钟的提交数。

1
2
3
4
5
6
7
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 命令来摄取和修改数据。例如,可以通过运行以下命令更新用户的显示登录名:

1
UPDATE github_users SET display_login = 'no1youknow' WHERE user_id = 24305673;

除了运行查询之外,citus 还会将数据定义更改应用于分布式表的分片:

1
2
-- DDL commands that are also parallelized
ALTER TABLE github_users ADD COLUMN dummy_column integer;

这样,我们的教程就结束了。作为下一步,您可以查看 Real-Time Apps 部分,了解如何建模自己的数据并支持实时分析应用程序。