日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
分布式PostgreSQL集群(Citus)官方示例-多租戶應(yīng)用程序?qū)崙?zhàn)

如果您正在構(gòu)建軟件即服務(wù) (SaaS) 應(yīng)用程序,您可能已經(jīng)在數(shù)據(jù)模型中內(nèi)置了租賃的概念。通常,大多數(shù)信息與租戶/客戶/帳戶相關(guān),并且數(shù)據(jù)庫表捕獲這種自然關(guān)系。

成都創(chuàng)新互聯(lián)網(wǎng)站設(shè)計(jì),為客戶量身定制各類網(wǎng)站建設(shè)業(yè)務(wù),包括企業(yè)型、電子商務(wù)型、響應(yīng)式網(wǎng)站設(shè)計(jì)、行業(yè)門戶型等各類網(wǎng)站,實(shí)戰(zhàn)經(jīng)驗(yàn)豐富,成功案例眾多。以客戶利益為出發(fā)點(diǎn),成都創(chuàng)新互聯(lián)網(wǎng)站制作為客戶規(guī)劃、按需定制制作符合企業(yè)需求、帶有營(yíng)銷價(jià)值的網(wǎng)絡(luò)建站方案認(rèn)真對(duì)待每一個(gè)客戶,我們不用口頭的語言來吹擂我們的優(yōu)秀,上1000家的成功案例見證著我們的成長(zhǎng)。

對(duì)于 SaaS 應(yīng)用程序,每個(gè)租戶的數(shù)據(jù)可以一起存儲(chǔ)在單個(gè)數(shù)據(jù)庫實(shí)例中,并與其他租戶保持隔離和不可見。這在三個(gè)方面是有效的。首先,應(yīng)用程序改進(jìn)適用于所有客戶端。其次,租戶之間共享數(shù)據(jù)庫可以有效地使用硬件。最后,為所有租戶管理單個(gè)數(shù)據(jù)庫比為每個(gè)租戶管理不同的數(shù)據(jù)庫服務(wù)器要簡(jiǎn)單得多。

但是,傳統(tǒng)上,單個(gè)關(guān)系數(shù)據(jù)庫實(shí)例難以擴(kuò)展到大型多租戶應(yīng)用程序所需的數(shù)據(jù)量。當(dāng)數(shù)據(jù)超過單個(gè)數(shù)據(jù)庫節(jié)點(diǎn)的容量時(shí),開發(fā)人員被迫放棄關(guān)系模型的優(yōu)勢(shì)。

Citus 允許用戶編寫多租戶應(yīng)用程序,就好像他們連接到單個(gè) PostgreSQL 數(shù)據(jù)庫一樣,而實(shí)際上該數(shù)據(jù)庫是一個(gè)水平可擴(kuò)展的機(jī)器集群??蛻舳舜a需要最少的修改,并且可以繼續(xù)使用完整的 SQL 功能。

本指南采用了一個(gè)示例多租戶應(yīng)用程序,并描述了如何使用 Citus 對(duì)其進(jìn)行建模以實(shí)現(xiàn)可擴(kuò)展性。在此過程中,我們研究了多租戶應(yīng)用程序的典型挑戰(zhàn),例如將租戶與嘈雜的鄰居隔離、擴(kuò)展硬件以容納更多數(shù)據(jù)以及存儲(chǔ)不同租戶的數(shù)據(jù)。PostgreSQL 和 Citus 提供了應(yīng)對(duì)這些挑戰(zhàn)所需的所有工具,所以讓我們開始構(gòu)建吧。

讓我們做一個(gè)應(yīng)用程序 - 廣告分析

我們將為跟蹤在線廣告效果并在頂部提供分析儀表板的應(yīng)用程序構(gòu)建后端。它非常適合多租戶應(yīng)用程序,因?yàn)橛脩魧?duì)數(shù)據(jù)的請(qǐng)求一次只涉及一家公司(他們自己的)。Github 上提供了完整示例應(yīng)用程序的代碼。

citus-example-ad-analytics:

  • https://github.com/citusdata/citus-example-ad-analytics。

讓我們從考慮這個(gè)應(yīng)用程序的簡(jiǎn)化 schema 開始。該應(yīng)用程序必須跟蹤多家公司,每家公司都運(yùn)行廣告活動(dòng)。廣告系列有許多廣告,每個(gè)廣告都有其點(diǎn)擊次數(shù)和展示次數(shù)的關(guān)聯(lián)記錄。

這是示例 schema。稍后我們將進(jìn)行一些小的更改,這使我們能夠在分布式環(huán)境中有效地分發(fā)和隔離數(shù)據(jù)。

CREATE TABLE companies (
id bigserial PRIMARY KEY,
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 bigserial PRIMARY KEY,
company_id bigint REFERENCES companies (id),
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 bigserial PRIMARY KEY,
campaign_id bigint REFERENCES campaigns (id),
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
);
CREATE TABLE clicks (
id bigserial PRIMARY KEY,
ad_id bigint REFERENCES ads (id),
clicked_at timestamp without time zone NOT NULL,
site_url text NOT NULL,
cost_per_click_usd numeric(20,10),
user_ip inet NOT NULL,
user_data jsonb NOT NULL
);
CREATE TABLE impressions (
id bigserial PRIMARY KEY,
ad_id bigint REFERENCES ads (id),
seen_at timestamp without time zone NOT NULL,
site_url text NOT NULL,
cost_per_impression_usd numeric(20,10),
user_ip inet NOT NULL,
user_data jsonb NOT NULL
);

我們可以對(duì) schema 進(jìn)行一些修改,這將在像 Citus 這樣的分布式環(huán)境中提高性能。要了解如何,我們必須熟悉 Citus 如何分發(fā)數(shù)據(jù)和執(zhí)行查詢。

擴(kuò)展關(guān)系數(shù)據(jù)模型

關(guān)系數(shù)據(jù)模型非常適合應(yīng)用程序。它保護(hù)數(shù)據(jù)完整性,允許靈活查詢,并適應(yīng)不斷變化的數(shù)據(jù)。傳統(tǒng)上唯一的問題是關(guān)系數(shù)據(jù)庫不被認(rèn)為能夠擴(kuò)展到大型 SaaS 應(yīng)用程序所需的工作負(fù)載。開發(fā)人員必須忍受 NoSQL 數(shù)據(jù)庫 — 或后端服務(wù)的集合 — 才能達(dá)到這個(gè)規(guī)模。

使用 Citus,您可以保留數(shù)據(jù)模型并使其可擴(kuò)展。Citus 對(duì)應(yīng)用程序來說似乎是一個(gè) PostgreSQL 數(shù)據(jù)庫,但它在內(nèi)部將查詢路由到可并行處理請(qǐng)求的可調(diào)整數(shù)量的物理服務(wù)器(節(jié)點(diǎn))。

多租戶應(yīng)用程序有一個(gè)很好的特性,我們可以利用它:查詢通??偸且淮握?qǐng)求一個(gè)租戶的信息,而不是多個(gè)租戶的信息。例如,當(dāng)銷售人員在 CRM 中搜索潛在客戶信息時(shí),搜索結(jié)果是特定于他的雇主的;其他企業(yè)的線索和注釋不包括在內(nèi)。

由于應(yīng)用程序查詢僅限于單個(gè)租戶,例如商店或公司,因此快速進(jìn)行多租戶應(yīng)用程序查詢的一種方法是將給定租戶的所有數(shù)據(jù)存儲(chǔ)在同一節(jié)點(diǎn)上。這最大限度地減少了節(jié)點(diǎn)之間的網(wǎng)絡(luò)開銷,并允許 Citus 有效地支持所有應(yīng)用程序的連接(joins)、鍵約束(key constraints)和事務(wù)(transactions)。有了這個(gè),您可以跨多個(gè)節(jié)點(diǎn)進(jìn)行擴(kuò)展,而無需完全重新編寫或重新構(gòu)建您的應(yīng)用程序。

我們?cè)?Citus 中通過確保 schema 中的每個(gè)表都有一個(gè)列來清楚地標(biāo)記哪個(gè)租戶擁有哪些行來做到這一點(diǎn)。在廣告分析應(yīng)用程序中,租戶是公司,因此我們必須確保所有表都有一個(gè) company_id 列。

當(dāng)為同一公司標(biāo)記行時(shí),我們可以告訴 Citus 使用此列來讀取和寫入同一節(jié)點(diǎn)的行。在 Citus 的術(shù)語中,company_id 將是分布列,您可以在分布式數(shù)據(jù)建模中了解更多信息。

分布式數(shù)據(jù)建模:

  • https://docs.citusdata.com/en/v10.2/sharding/data_modeling.html#distributed-data-modeling。

準(zhǔn)備表和攝取數(shù)據(jù)

在上一節(jié)中,我們確定了多租戶應(yīng)用程序的正確分布列:公司 ID(company_id)。即使在單機(jī)數(shù)據(jù)庫中,通過添加公司 ID 對(duì)表進(jìn)行非規(guī)范化也是很有用的,無論是為了行級(jí)安全還是為了額外的索引。正如我們所看到的,額外的好處是包括額外的列也有助于多機(jī)器擴(kuò)展。

到目前為止,我們創(chuàng)建的 schema 使用單獨(dú)的 id 列作為每個(gè)表的主鍵。Citus 要求主鍵和外鍵約束包括分布列。這一要求使得在分布式環(huán)境中執(zhí)行這些約束更加有效,因?yàn)橹恍铏z查單個(gè)節(jié)點(diǎn)即可保證它們。

在 SQL 中,此要求轉(zhuǎn)化為通過包含 company_id 來組合主鍵和外鍵。這與多租戶情況兼容,因?yàn)槲覀冋嬲枰氖谴_保每個(gè)租戶的唯一性。

綜上所述,這里是為按 company_id 分配表準(zhǔn)備的更改。

CREATE TABLE companies (
id bigserial PRIMARY KEY,
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 bigserial, -- was: PRIMARY KEY
company_id bigint REFERENCES companies (id),
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,
PRIMARY KEY (company_id, id) -- added
);
CREATE TABLE ads (
id bigserial, -- was: PRIMARY KEY
company_id bigint, -- added
campaign_id bigint, -- was: REFERENCES campaigns (id)
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,
PRIMARY KEY (company_id, id), -- added
FOREIGN KEY (company_id, campaign_id) -- added
REFERENCES campaigns (company_id, id)
);
CREATE TABLE clicks (
id bigserial, -- was: PRIMARY KEY
company_id bigint, -- added
ad_id bigint, -- was: REFERENCES ads (id),
clicked_at timestamp without time zone NOT NULL,
site_url text NOT NULL,
cost_per_click_usd numeric(20,10),
user_ip inet NOT NULL,
user_data jsonb NOT NULL,
PRIMARY KEY (company_id, id), -- added
FOREIGN KEY (company_id, ad_id) -- added
REFERENCES ads (company_id, id)
);
CREATE TABLE impressions (
id bigserial, -- was: PRIMARY KEY
company_id bigint, -- added
ad_id bigint, -- was: REFERENCES ads (id),
seen_at timestamp without time zone NOT NULL,
site_url text NOT NULL,
cost_per_impression_usd numeric(20,10),
user_ip inet NOT NULL,
user_data jsonb NOT NULL,
PRIMARY KEY (company_id, id), -- added
FOREIGN KEY (company_id, ad_id) -- added
REFERENCES ads (company_id, id)
);

您可以了解有關(guān)在多租戶架構(gòu)遷移中遷移您自己的數(shù)據(jù)模型的更多信息 。

多租戶架構(gòu)遷移:

  • https://docs.citusdata.com/en/v10.2/develop/migration_mt_schema.html#mt-schema-migration。

自己試試

本指南旨在讓您可以在自己的 Citus 數(shù)據(jù)庫中進(jìn)行操作。本教程假設(shè)您已經(jīng)安裝并運(yùn)行了 Citus。如果您沒有運(yùn)行 Citus,則可以使用單節(jié)點(diǎn) Citus 中的選項(xiàng)之一在本地安裝設(shè)置 Citus。

單節(jié)點(diǎn) Citus:

  • https://docs.citusdata.com/en/v10.2/installation/single_node.html#development。

您將使用 psql 運(yùn)行 SQL 命令并連接到 Coordinator 節(jié)點(diǎn):

  • Docker:docker exec -it citus_master psql -U postgres。

此時(shí),您可以在自己的 Citus 集群中隨意下載并執(zhí)行 SQL 以創(chuàng)建模式。一旦模式準(zhǔn)備好,我們就可以告訴 Citus 在工作人員上創(chuàng)建分片。從協(xié)調(diào)器節(jié)點(diǎn)運(yùn)行:

此時(shí),您可以通過下載 schema.sql并執(zhí)行 SQL 來創(chuàng)建 schema,在你自己的 Citus 集群中進(jìn)行操作。一旦 schema 準(zhǔn)備好,我們可以告訴 Citus 在 workers 上創(chuàng)建 shards。從 coordinator 節(jié)點(diǎn)運(yùn)行:

schema.sql:

  • https://examples.citusdata.com/mt_ref_arch/schema.sql。
SELECT create_distributed_table('companies',   'id');
SELECT create_distributed_table('campaigns', 'company_id');
SELECT create_distributed_table('ads', 'company_id');
SELECT create_distributed_table('clicks', 'company_id');
SELECT create_distributed_table('impressions', 'company_id');

create_distributed_table 函數(shù)通知 Citus 表應(yīng)該分布在節(jié)點(diǎn)之間,并且應(yīng)該計(jì)劃對(duì)這些表的未來傳入查詢以進(jìn)行分布式執(zhí)行。該函數(shù)還在工作節(jié)點(diǎn)上為表創(chuàng)建分片,這些分片是 Citus 用于將數(shù)據(jù)分配給節(jié)點(diǎn)的低級(jí)別數(shù)據(jù)存儲(chǔ)單元。

create_distributed_table:

  • https://docs.citusdata.com/en/v10.2/develop/api_udf.html#create-distributed-table。

下一步是從命令行將樣本數(shù)據(jù)加載到集群中。

# download and ingest datasets from the shell
for dataset in companies campaigns ads clicks impressions geo_ips; do
curl -O https://examples.citusdata.com/mt_ref_arch/${dataset}.csv
done

如果您使用 Docker,則應(yīng)使用 docker cp 命令將文件復(fù)制到 Docker 容器中。

for dataset in companies campaigns ads clicks impressions geo_ips; do
docker cp ${dataset}.csv citus:.
done

作為 PostgreSQL 的擴(kuò)展,Citus 支持使用 COPY 命令進(jìn)行批量加載。使用它來攝取您下載的數(shù)據(jù),如果您將文件下載到其他位置,請(qǐng)確保指定正確的文件路徑?;氐?psql 里面運(yùn)行這個(gè):

\copy companies from 'companies.csv' with csv
\copy campaigns from 'campaigns.csv' with csv
\copy ads from 'ads.csv' with csv
\copy clicks from 'clicks.csv' with csv
\copy impressions from 'impressions.csv' with csv

集成應(yīng)用程序

好消息是:一旦您完成了前面概述的輕微 schema 修改,您的應(yīng)用程序就可以用很少的工作量進(jìn)行擴(kuò)展。你只需將應(yīng)用程序連接到 Citus,讓數(shù)據(jù)庫負(fù)責(zé)保持查詢速度和數(shù)據(jù)安全。

任何包含 company_id filter 的應(yīng)用程序查詢或更新語句將繼續(xù)按原樣工作。如前所述,這種 filter 在多租戶應(yīng)用程序中很常見。使用對(duì)象關(guān)系映射器 (ORM) 時(shí),您可以通過 where 或 filter 等方法識(shí)別這些查詢。

ActiveRecord:

Impression.where(company_id: 5).count

Django:

Impression.objects.filter(company_id=5).count()

基本上,當(dāng)在數(shù)據(jù)庫中執(zhí)行的結(jié)果 SQL 在每個(gè)表(包括 JOIN 查詢中的表)上包含 WHERE company_id = :value 子句時(shí),Citus 將識(shí)別出該查詢應(yīng)該路由到單個(gè)節(jié)點(diǎn),并按原樣在那里執(zhí)行。這確保了所有 SQL 功能都可用。該節(jié)點(diǎn)畢竟是一個(gè)普通的 PostgreSQL 服務(wù)器。

此外,為了更簡(jiǎn)單,您可以使用我們的 Rails 的 activerecord-multi-tenant 庫或 Django 的 django-multitenant 庫,它們會(huì)自動(dòng)將這些過濾器添加到您的所有查詢中,即使是復(fù)雜的查詢。查看我們的 Ruby on Rails 和 Django 遷移指南。

activerecord-multi-tenant:

  • https://github.com/citusdata/activerecord-multi-tenant。

django-multitenant:

  • https://github.com/citusdata/django-multitenant。

Ruby on Rails:

  • https://docs.citusdata.com/en/v10.2/develop/migration_mt_ror.html#rails-migration。

Django:

  • https://docs.citusdata.com/en/v10.2/develop/migration_mt_django.html#django-migration。

本指南與框架無關(guān),因此我們將指出一些使用 SQL 的 Citus 功能。發(fā)揮您的想象力,以了解這些陳述將如何以您選擇的語言表達(dá)。

這是在單個(gè)租戶上運(yùn)行的簡(jiǎn)單查詢和更新。

-- campaigns with highest budget
SELECT name, cost_model, state, monthly_budget
FROM campaigns
WHERE company_id = 5
ORDER BY monthly_budget DESC
LIMIT 10;
-- double the budgets!
UPDATE campaigns
SET monthly_budget = monthly_budget*2
WHERE company_id = 5;

用戶使用 NoSQL 數(shù)據(jù)庫擴(kuò)展應(yīng)用程序的一個(gè)常見痛點(diǎn)是缺少 transactions 和 joins。但是,事務(wù)在 Citus 中的工作方式與您期望的一樣:

-- transactionally reallocate campaign budget money
BEGIN;
UPDATE campaigns
SET monthly_budget = monthly_budget + 1000
WHERE company_id = 5
AND id = 40;
UPDATE campaigns
SET monthly_budget = monthly_budget - 1000
WHERE company_id = 5
AND id = 41;
COMMIT;

作為 SQL 支持的最后一個(gè) demo,我們有一個(gè)包含聚合(aggregates)和窗口(window)函數(shù)的查詢,它在 Citus 中的工作方式與在 PostgreSQL 中的工作方式相同。該查詢根據(jù)展示次數(shù)對(duì)每個(gè)廣告系列中的廣告進(jìn)行排名。

SELECT a.campaign_id,
RANK() OVER (
PARTITION BY a.campaign_id
ORDER BY a.campaign_id, count(*) desc
), count(*) as n_impressions, a.id
FROM ads as a
JOIN impressions as i
ON i.company_id = a.company_id
AND i.ad_id = a.id
WHERE a.company_id = 5
GROUP BY a.campaign_id, a.id
ORDER BY a.campaign_id, n_impressions desc;

簡(jiǎn)而言之,當(dāng)查詢范圍為租戶時(shí),插入、更新、刪除、復(fù)雜的 SQL 和事務(wù)都按預(yù)期工作。

在租戶之間共享數(shù)據(jù)

到目前為止,所有表都通過 company_id 分發(fā),但有時(shí)有些數(shù)據(jù)可以由所有租戶共享,并且不“屬于”特定的任何租戶。例如,所有使用此示例廣告平臺(tái)的公司都可能希望根據(jù) IP 地址獲取其受眾的地理信息。在單機(jī)數(shù)據(jù)庫中,這可以通過 geo-ip 的查找表來完成,如下所示。(一個(gè)真實(shí)的表可能會(huì)使用 PostGIS,但可以使用簡(jiǎn)化的示例。)

CREATE TABLE geo_ips (
addrs cidr NOT NULL PRIMARY KEY,
latlon point NOT NULL
CHECK (-90 <= latlon[0] AND latlon[0] <= 90 AND
-180 <= latlon[1] AND latlon[1] <= 180)
);
CREATE INDEX ON geo_ips USING gist (addrs inet_ops);

為了在分布式設(shè)置中有效地使用此表,我們需要找到一種方法來共同定位 geo_ips 表,不僅針對(duì)一個(gè)公司,而且針對(duì)每個(gè)公司。這樣,在查詢時(shí)不需要產(chǎn)生網(wǎng)絡(luò)流量。我們?cè)?Citus 中通過將 geo_ips 指定為參考表來執(zhí)行此操作。

參考表:

  • https://docs.citusdata.com/en/v10.2/develop/reference_ddl.html#reference-tables。
-- Make synchronized copies of geo_ips on all workers
SELECT create_reference_table('geo_ips');

參考表在所有工作節(jié)點(diǎn)之間復(fù)制,Citus 在修改期間自動(dòng)保持它們同步。請(qǐng)注意,我們調(diào)用 create_reference_table 而不是 create_distributed_table。

create_reference_table:

  • https://docs.citusdata.com/en/v10.2/develop/api_udf.html#create-reference-table。

現(xiàn)在 geo_ips 已建立為參考表,使用示例數(shù)據(jù)加載它:

\copy geo_ips from 'geo_ips.csv' with csv

現(xiàn)在,將點(diǎn)擊與這個(gè)表聯(lián)接(join)起來可以高效地執(zhí)行。例如,我們可以詢問點(diǎn)擊廣告290 的每個(gè)人的位置。

SELECT c.id, clicked_at, latlon
FROM geo_ips, clicks c
WHERE addrs >> c.user_ip
AND c.company_id = 5
AND c.ad_id = 290;

Schema 的在線更改

多租戶系統(tǒng)的另一個(gè)挑戰(zhàn)是保持所有租戶的 schema 同步。任何 schema 更改都需要一致地反映在所有租戶中。在 Citus 中,您可以簡(jiǎn)單地使用標(biāo)準(zhǔn) PostgreSQL DDL 命令來更改表的 schema,Citus 將使用兩階段提交協(xié)議將它們從 coordinator 節(jié)點(diǎn)傳播到 worker。

例如,此應(yīng)用程序中的廣告可以使用文本標(biāo)題。我們可以通過在 coordinator 上發(fā)出標(biāo)準(zhǔn) SQL 來向表中添加一列:

ALTER TABLE ads
ADD COLUMN caption text;

這也會(huì)更新所有 worker。此命令完成后,Citus 集群將接受在新 caption 列中讀取或?qū)懭霐?shù)據(jù)的查詢。

有關(guān) DDL 命令如何通過集群傳播的更完整說明,請(qǐng)參閱修改表。

修改表:

  • https://docs.citusdata.com/en/v10.2/develop/reference_ddl.html#ddl-prop-support。

當(dāng)租戶的數(shù)據(jù)不同時(shí)

鑒于所有租戶共享一個(gè)共同的 schema 和硬件基礎(chǔ)設(shè)施,我們?nèi)绾稳菁{想要存儲(chǔ)其他人不需要的信息的租戶?例如,一個(gè)使用我們廣告數(shù)據(jù)庫的租戶應(yīng)用程序可能希望通過點(diǎn)擊存儲(chǔ)跟蹤 cookie 信息,而另一個(gè)租戶可能關(guān)心 browser agents。傳統(tǒng)上,使用多租戶共享模式方法的數(shù)據(jù)庫采用創(chuàng)建固定數(shù)量的預(yù)分配“自定義”列,或具有外部“擴(kuò)展表”。但是,PostgreSQL 為其非結(jié)構(gòu)化列類型提供了一種更簡(jiǎn)單的方法,尤其是 JSONB。

JSONB:

  • https://www.postgresql.org/docs/current/static/datatype-json.html。

請(qǐng)注意,我們的 schema 在 clicks 中已經(jīng)有一個(gè)名為 user_data 的 JSONB 字段。每個(gè)租戶都可以使用它進(jìn)行靈活的存儲(chǔ)。

假設(shè)公司 5 在字段中包含信息以跟蹤用戶是否在移動(dòng)設(shè)備上。該公司可以查詢以查找誰點(diǎn)擊更多,移動(dòng)訪問者或傳統(tǒng)訪問者:

SELECT
user_data->>'is_mobile' AS is_mobile,
count(*) AS count
FROM clicks
WHERE company_id = 5
GROUP BY user_data->>'is_mobile'
ORDER BY count DESC;

數(shù)據(jù)庫管理員甚至可以創(chuàng)建部分索引來提高單個(gè)租戶查詢模式的速度。這是一項(xiàng)改進(jìn)公司 5 對(duì)移動(dòng)設(shè)備用戶點(diǎn)擊的過濾器的方法:

部分索引:

  • https://www.postgresql.org/docs/current/static/indexes-partial.html。
CREATE INDEX click_user_data_is_mobile
ON clicks ((user_data->>'is_mobile'))
WHERE company_id = 5;

此外,PostgreSQL 支持 JSONB 上的 GIN 索引。在 JSONB 列上創(chuàng)建 GIN index 將為該 JSON 文檔中的每個(gè) key 和 value 創(chuàng)建一個(gè)索引。這加速了許多 JSONB 運(yùn)算符,例如 ?、?| 和 ?&。

GIN 索引:

  • https://www.postgresql.org/docs/current/static/gin-intro.html。

JSONB 運(yùn)算符:

  • https://www.postgresql.org/docs/current/static/functions-json.html#FUNCTIONS-JSONB-OP-TABLE。
CREATE INDEX click_user_data
ON clicks USING gin (user_data);
-- this speeds up queries like, "which clicks have
-- the is_mobile key present in user_data?"
SELECT id
FROM clicks
WHERE user_data ? 'is_mobile'
AND company_id = 5;

擴(kuò)展硬件資源

隨著業(yè)務(wù)的增長(zhǎng)或租戶想要存儲(chǔ)更多數(shù)據(jù),多租戶數(shù)據(jù)庫應(yīng)針對(duì)未來規(guī)模進(jìn)行設(shè)計(jì)。 Citus 可以通過添加新機(jī)器輕松擴(kuò)展,而無需進(jìn)行任何更改或讓應(yīng)用程序停機(jī)。

能夠重新平衡 Citus 集群中的數(shù)據(jù)使您可以增加數(shù)據(jù)大小或客戶數(shù)量并按需提高性能。添加新機(jī)器允許您將數(shù)據(jù)保留在內(nèi)存中,即使它比單臺(tái)機(jī)器可以存儲(chǔ)的數(shù)據(jù)大得多。

此外,如果只有少數(shù)大型租戶的數(shù)據(jù)增加,那么您可以將這些特定租戶隔離到單獨(dú)的節(jié)點(diǎn)以獲得更好的性能。(租戶隔離是 Citus 企業(yè)版的一個(gè)功能。)

要橫向擴(kuò)展您的 Citus 集群,請(qǐng)首先向其中添加一個(gè)新的 worker 節(jié)點(diǎn)。在 Azure Database for PostgreSQL - Hyperscale (Citus) 上,可以使用 Azure Portal 添加所需數(shù)量的節(jié)點(diǎn)。或者,如果您運(yùn)行自己的 Citus 安裝,則可以使用 citus_add_node UDF 手動(dòng)添加節(jié)點(diǎn)。

citus_add_node:

  • https://docs.citusdata.com/en/v10.2/develop/api_udf.html#citus-add-node。

添加節(jié)點(diǎn)后,它將在系統(tǒng)中可用。但是,此時(shí)沒有租戶存儲(chǔ)在上面,Citus 還不會(huì)在那里運(yùn)行任何查詢。要移動(dòng)現(xiàn)有數(shù)據(jù),您可以要求 Citus 重新平衡數(shù)據(jù)。此操作在當(dāng)前活動(dòng)節(jié)點(diǎn)之間移動(dòng)稱為分片的行束,以嘗試均衡每個(gè)節(jié)點(diǎn)上的數(shù)據(jù)量。

SELECT rebalance_table_shards('companies');

Rebalancing 保留了 Table Co-Location,這意味著我們可以告訴 Citus 重新平衡公司表,它會(huì)接受提示并重新平衡由 company_id 分配的其他表。此外,使用 Citus 企業(yè)版,應(yīng)用程序在分片重新平衡期間無需停機(jī)。讀取請(qǐng)求無縫地繼續(xù),并且寫入僅在它們影響當(dāng)前正在運(yùn)行的分片時(shí)才被鎖定。在 Citus 社區(qū)版中,對(duì)分片的寫入在重新平衡期間被阻止,但讀取不受影響。

Table Co-Location:

  • https://docs.citusdata.com/en/v10.2/sharding/data_modeling.html#colocation。

您可以在此處了解有關(guān)分片重新平衡如何工作的更多信息:Scaling Out(添加新節(jié)點(diǎn))。

Scaling Out(添加新節(jié)點(diǎn)):

  • https://docs.citusdata.com/en/v10.2/cloud/performance.html#scaling-out。

與大租戶打交道

本部分使用僅在 Citus Enterprise 中可用的功能。

上一節(jié)描述了隨著租戶數(shù)量的增加而擴(kuò)展集群的通用方法。但是,用戶經(jīng)常有兩個(gè)問題。首先是他們最大的租戶如果變得太大會(huì)發(fā)生什么。第二個(gè)是在單個(gè)工作節(jié)點(diǎn)上托管大型租戶和小型租戶對(duì)性能的影響,以及可以做些什么。

關(guān)于第一個(gè)問題,調(diào)查來自大型 SaaS 站點(diǎn)的數(shù)據(jù)表明,隨著租戶數(shù)量的增加,租戶數(shù)據(jù)的大小通常傾向于遵循 Zipfian 分布。

Zipfian 分布:

  • https://en.wikipedia.org/wiki/Zipf%27s_law。

例如,在一個(gè)包含 100 個(gè)租戶的數(shù)據(jù)庫中,預(yù)計(jì)最大的租戶將占數(shù)據(jù)的 20% 左右。在一個(gè)大型 SaaS 公司更現(xiàn)實(shí)的例子中,如果有 10k 個(gè)租戶,最大的將占數(shù)據(jù)的 2% 左右。即使是 10TB 的數(shù)據(jù),最大的租戶也需要 200GB,這很容易適應(yīng)單個(gè)節(jié)點(diǎn)。

另一個(gè)問題是關(guān)于大型和小型租戶在同一節(jié)點(diǎn)上時(shí)的性能。標(biāo)準(zhǔn)分片重新平衡將提高整體性能,但它可能會(huì)或可能不會(huì)改善大小租戶的混合。再平衡器只是分配分片以均衡節(jié)點(diǎn)上的存儲(chǔ)使用,而不檢查在每個(gè)分片上分配了哪些租戶。

為了改善資源分配并保證租戶的 QoS,將大型租戶移動(dòng)到專用節(jié)點(diǎn)是值得的。 Citus 提供了執(zhí)行此操作的工具。

在我們的例子中,假設(shè)我們的老朋友公司 id=5 非常大。我們可以分兩步隔離此租戶的數(shù)據(jù)。我們將在此處介紹這些命令,您可以咨詢 Tenant Isolation 以了解有關(guān)它們的更多信息。

Tenant Isolation:

  • https://docs.citusdata.com/en/v10.2/admin_guide/cluster_management.html#tenant-isolation。

首先將租戶的數(shù)據(jù)隔離到一個(gè)適合移動(dòng)的專用分片中。CASCADE 選項(xiàng)也將此更改應(yīng)用于我們由 company_id 分發(fā)的其余表。

SELECT isolate_tenant_to_new_shard(
'companies', 5, 'CASCADE'
);

輸出是專用于保存 company_id=5 的分片 ID:

┌─────────────────────────────┐
│ isolate_tenant_to_new_shard │
├─────────────────────────────┤
│ 102240 │
└─────────────────────────────┘

接下來,我們將數(shù)據(jù)通過網(wǎng)絡(luò)移動(dòng)到一個(gè)新的專用節(jié)點(diǎn)。如上一節(jié)所述創(chuàng)建一個(gè)新節(jié)點(diǎn)。記下其主機(jī)名,如 Cloud Console 的 “Nodes” 選項(xiàng)卡中所示。

-- find the node currently holding the new shard
SELECT nodename, nodeport
FROM pg_dist_placement AS placement,
pg_dist_node AS node 網(wǎng)站欄目:分布式PostgreSQL集群(Citus)官方示例-多租戶應(yīng)用程序?qū)崙?zhàn)
當(dāng)前地址:http://www.5511xx.com/article/cdsssdj.html