教學課程:設計具有彈性叢集的微服務

在這個教學中,你會使用 適用於 PostgreSQL 的 Azure 資料庫 作為多個微服務的儲存後端。 教學示範了此類叢集的範例設置與基本操作。 學習怎麼做:

  • 先決條件
  • 建立微服務的角色
  • 使用 psql 公用程式來建立角色和分散式結構描述
  • 建立範例服務的資料表
  • 設定 服務
  • 執行服務
  • 探索資料庫

先決條件

以下列其中一種方式建立彈性叢集:

建立微服務的角色

你可以在彈性叢集中動態放置分散式結構。 系統能將叢集整體重新平衡,跨越可用節點,讓你在叢集資源上效率提升,無需手動分配。

當你對微服務設計模式套用結構分片時,你會為每個對應的微服務建立資料庫架構。 另外,連接資料庫時,每個微服務都要用一個不同的 ROLE。 當每位使用者連線時,他們的角色名稱會放在search_path的開頭。 如果角色名稱與結構名稱相符,你不需要額外更改應用程式來設定正確的search_path。

在此範例中,使用三個微服務:

  • 使用者
  • time
  • ping

為每個服務建立資料庫角色:

CREATE USER user_service;
CREATE USER time_service;
CREATE USER ping_service;

使用 psql 公用程式來建立分散式結構描述

當你用 psql 連接 elastic 叢集後,可以完成一些基本任務。

你可以用兩種方式分發一個綱要:

  • 藉由手動呼叫 citus_schema_distribute(schema_name) 函式:
CREATE SCHEMA AUTHORIZATION user_service;
CREATE SCHEMA AUTHORIZATION time_service;
CREATE SCHEMA AUTHORIZATION ping_service;

SELECT citus_schema_distribute('user_service');
SELECT citus_schema_distribute('time_service');
SELECT citus_schema_distribute('ping_service');

此方法也可讓您將現有的一般結構描述轉換成分散式結構描述。

備註

您只能散發不包含分散式和參考資料表的結構描述。

  • 透過啟用 citus.enable_schema_based_sharding 設定變數。 你可以更改當前會話的變數,或從協調節點的參數中永久更改。 當你把參數設為 ON,所有建立的結構預設都會被分配。
SET citus.enable_schema_based_sharding TO ON;

CREATE SCHEMA AUTHORIZATION user_service;
CREATE SCHEMA AUTHORIZATION time_service;
CREATE SCHEMA AUTHORIZATION ping_service;

執行以下指令以列出目前分散的結構模式:

SELECT * FROM citus_schemas;
 schema_name | colocation_id | schema_size | schema_owner
-------------+---------------+-------------+--------------
 user_service |             5 | 0 bytes     | user_service
 time_service |             6 | 0 bytes     | time_service
 ping_service |             7 | 0 bytes     | ping_service
(3 rows)

建立範例服務的資料表

你現在可以連接每個微服務的彈性叢集。 在以下範例中,彈性叢集資料庫命名為 Citus。 在 psql 會話中,你可以用 \c 指令切換到另一個使用者。

\c citus user_service
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    email VARCHAR(255) NOT NULL
);
\c citus time_service
CREATE TABLE query_details (
    id SERIAL PRIMARY KEY,
    ip_address INET NOT NULL,
    query_time TIMESTAMP NOT NULL
);
\c citus ping_service
CREATE TABLE ping_results (
    id SERIAL PRIMARY KEY,
    host VARCHAR(255) NOT NULL,
    result TEXT NOT NULL
);

設定 服務

在本教學課程中,我們使用一組簡單的服務。 取得方式是複製此公用存放庫:

git clone https://github.com/citusdata/citus-example-microservices.git
$ tree
.
├── LICENSE
├── README.md
├── ping
│   ├── app.py
│   ├── ping.sql
│   └── requirements.txt
├── time
│   ├── app.py
│   ├── requirements.txt
│   └── time.sql
└── user
    ├── app.py
    ├── requirements.txt
    └── user.sql

不過,在執行服務之前,請編輯 user/app.py、 ping/app.py和 time/app.py 檔案,以提供彈性叢集的 連線組態 :

# Database configuration
db_config = {
    'host': 'EXAMPLE.postgres.database.azure.com',
    'database': 'postgres',
    'password': 'SECRET',
    'user': 'ping_service',
    'port': 5432
}

進行變更之後,請儲存所有修改過的檔案,然後移至執行服務的下一個步驟。

執行服務

切換至每個應用程式目錄,並在其自己的 Python 環境中予以執行。

cd user
pipenv install
pipenv shell
python app.py

針對時間和 Ping 服務重複命令,之後,您就可以使用 API。

建立一些使用者:

curl -X POST -H "Content-Type: application/json" -d '[
  {"name": "John Doe", "email": "john@example.com"},
  {"name": "Jane Smith", "email": "jane@example.com"},
  {"name": "Mike Johnson", "email": "mike@example.com"},
  {"name": "Emily Davis", "email": "emily@example.com"},
  {"name": "David Wilson", "email": "david@example.com"},
  {"name": "Sarah Thompson", "email": "sarah@example.com"},
  {"name": "Alex Miller", "email": "alex@example.com"},
  {"name": "Olivia Anderson", "email": "olivia@example.com"},
  {"name": "Daniel Martin", "email": "daniel@example.com"},
  {"name": "Sophia White", "email": "sophia@example.com"}
]' http://localhost:5000/users

列出已建立的使用者:

curl http://localhost:5000/users

取得目前時間:

Get current time:

針對 example.com,執行 Ping:

curl -X POST -H "Content-Type: application/json" -d '{"host": "example.com"}' http://localhost:5002/ping

探索資料庫

既然您已呼叫一些 API 函數、已儲存資料,且您可以檢查 citus_schemas 是否反映預期內容:

SELECT * FROM citus_schemas;
 schema_name | colocation_id | schema_size | schema_owner
-------------+---------------+-------------+--------------
 user_service |             1 | 112 kB      | user_service
 time_service |             2 | 32 kB       | time_service
 ping_service |             3 | 32 kB       | ping_service
(3 rows)

當你建立結構時,並沒有指定要在哪些機器上建立架構。 這會自動完成。 您可以使用下列查詢來查看每個結構描述所在的位置:

  SELECT nodename,nodeport, table_name, pg_size_pretty(sum(shard_size))
  FROM citus_shards
  GROUP BY nodename,nodeport, table_name;
nodename  | nodeport |         table_name         | pg_size_pretty
-----------+----------+---------------------------+----------------
 localhost |     7001 | time_service.query_details | 32 kB
 localhost |     7002 | user_service.users         | 112 kB
 localhost |     7002 | ping_service.ping_results  | 32 kB

為了簡潔說明此頁面上的範例輸出,而不是使用 nodename 作為 IP 位址,我們會將其取代為 localhost。 假設 localhost:7001 是節點一,而 localhost:7002 是節點二。

您可以看到時間服務落在節點 localhost:7001,而使用者和 Ping 服務共用第二個節點 localhost:7002 上的空間。 範例應用程式很簡單,資料大小也不算大,但假設你受到節點間儲存空間使用率不均的影響。 讓兩個較小的時間和 ping 服務運行在同一個節點上,而大型的用戶服務運行在獨立的節點上會更合理。

您可以輕鬆地依磁碟大小重新平衡叢集:

SELECT citus_rebalance_start();
NOTICE:  Scheduled 1 moves as job 1
DETAIL:  Rebalance scheduled as background job
HINT:  To monitor progress, run: SELECT * FROM citus_rebalance_status();
 citus_rebalance_start
-----------------------
                     1
(1 row)

完成後,您可以檢視我們的新布局樣子:

  SELECT nodename,nodeport, table_name, pg_size_pretty(sum(shard_size))
  FROM citus_shards
  GROUP BY nodename,nodeport, table_name;
 nodename  | nodeport |         table_name        | pg_size_pretty
-----------+----------+---------------------------+----------------
 localhost |     7001 | time_service.query_details | 32 kB
 localhost |     7001 | ping_service.ping_results  | 32 kB
 localhost |     7002 | user_service.users         | 112 kB
(3 rows)

根據預期,已移動結構描述,而且我們有一個更平衡的叢集。 此作業對於應用程式而言是透明的。 你甚至不需要重啟,它們會繼續處理查詢。

後續步驟