教程:使用弹性群集设计微服务

本教程使用 Azure Database for PostgreSQL 作为多个微服务的存储后端。 本教程演示了此类群集的示例设置及基本操作。 学习如何做到:

  • 先决条件
  • 为微服务创建角色
  • 使用 psql 实用工具创建角色和分布式架构
  • 为示例服务创建表
  • 配置服务
  • 运行服务
  • 浏览数据库

先决条件

通过以下方式之一创建弹性群集:

为微服务创建角色

可以在弹性群集中动态放置分布式架构。 系统可以在可用节点中将其重新均衡为整个单元,因此无需手动分配即可提高群集资源的效率。

将架构分片应用到微服务设计模式时,请为每个相应的微服务创建数据库架构。 此外,在连接到数据库时为每个微服务使用不同的 ROLE。 每个用户连接时,其角色名称将位于search_path的开头。 如果角色名称与架构名称匹配,则无需任何其他应用程序更改即可设置正确的search_path。

在此示例中,使用三个微服务:

  • 用户
  • time
  • ping

为每个服务创建数据库角色:

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

使用 psql 实用工具创建分布式架构

使用 psql 连接到弹性群集后,可以完成一些基本任务。

可以通过两种方式分发架构:

  • 手动调用 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.pyping/app.pytime/app.py文件,为弹性群集提供连接配置

# Database configuration
db_config = {
    'host': 'EXAMPLE.postgres.database.chinacloudapi.cn',
    '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 为节点 1,localhost:7002 为节点 2。

可以看到,时间服务位于节点 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)

根据预期,架构被移动,并且我们有一个更均衡的群集。 此操作对于应用程序是透明的。 你甚至不需要重启它们,它们继续为查询提供服务。

后续步骤