Orchestrate Microservices vs Choreography Microservices
在 协作微服务: AWS Step Functions Lambda 的一文当中, AWS Step Functions BookingWorkflowOrchestrator, 以 Orchestrate 的方式协作了多个的微服务。
AWS Step Functions 以 Orchestrate 的方式来协作多个的微服务, 是相当成熟且有效的。
但是, 要能以 AWS Step Functions Orchestrate 的方式, 来协作多个的微服务的前提是:
- 我们必需要能非常明确的知道如何的将系统的行为 (业务流) 转化为 AWS Step Functions Orchestrate 逻辑上的代码。
也就是说, 当我们无法能很明确的掌握系统的行为 (业务流) 上的变化的时候, 我们将会陷入维护、修改 AWS Step Functions Orchestrate 逻辑上的代码的灾难当中。
所以, 本文将探讨另一种协作多个微服务的方式; AWS Step Functions Choreography。
当我们在开发微服务的时候, 我们还无法能很明确完全的掌握系统的行为 (业务流) 上的变化的时候, 我们就应该要使用 AWS Step Functions Choreography 的方式, 来协作多个微服务间的协作, 使得我们能免于因系统的行为 (业务流) 上的变化, 而陷入在 AWS Step Functions 中维护、修改微服务协作间的逻辑的灾难当中。
AWS Step Functions Choreography Microservices
当 AWS Step Functions 执行完某个状态的时候, AWS Step Functions 便会丢出个 “事件” 到 Amazon SNS (Amazon Simple Notification Service) 当中。
而对这个由 AWS Step Functionsn 所丢出的事件有兴趣的微服务, 便可经由 Amazon SNS (Amazon Simple Notification Service) 取得这个事件所内含的信息, 然后, 以 “异步” 的方式, 来完成微服务自身所需完成的任务。
AWS Step Functions Choreography; 使得我们在开发微服务的时候, 我们仅需掌握部分的系统的行为 (业务流); 将我们在开发的当下所掌握到的部分的系统的行为 (业务流) 所需的微服务, 以 “订阅 (Subscribe)” 的方式, 使得多个微服务间能以 “异步” 的方式来进行协作。
AWS Step Functions Choreography; 当系统的行为 (业务流) 发生改变时, 我们也能很容易的以 “取消订阅 (Un-subscribe)” 的方式, 来将不需要再存在于系统的行为 (业务流) 的微服务, 给移出系统的行为 (业务流) 当中。
AWS Step Functions Choreography; 当系统的行为 (业务流) 发生改变时, 我们也能很容易的以 “订阅 (Subscribe)” 的方式, 来将所需要的微服务加入到新的系统的行为 (业务流) 当中。
客户成功的预订酒店与旅游景点门票的服务后, 以 AWS Step Functions Choreography 协作其他的微服务
在 协作微服务: AWS Step Functions Lambda 的一文当中, AWS Step Functions 以 Orchestrate 的方式, 使得微服务; BookHotelClient, BookMuseumClient; 可共同的完成, 为客户预订酒店与旅游景点门票的服务。
在本文中, 我们将新增加一个状态; NotifySuccess。

状态 BookHotelState, BookMuseumState 执行完后; 确定客户成功的预订酒店与旅游景点门票的服务; 将执行状态; NotifySuccess。
状态 BookMuseumState 的代码如下:
"BookMuseumState": {
"Type": "Task",
"Next": "NotifySuccess",
状态 BookHotelState, BookMuseumState 执行完后; 确定客户成功的预订酒店与旅游景点门票的服务; 状态 NotifySuccess 将会丢出 “订单完成” 的事件到 Amazon SNS。
状态; NotifySuccess; 的代码如下:
"NotifySuccess": {
"Type": "Task",
"End": true,
"Resource": "arn:aws:states:::sns:publish",
"Parameters": {
"TopicArn": "arn:aws:sns:[region]:[accountId]:OrderCompletedTopic",
"Message.$": "$.purchase.buyer_id",
"MessageAttributes": {
"my_attribute_no_1": {
"DataType": "String",
"StringValue.$": "$.hotel.start_date"
},
"my_attribute_no_2": {
"DataType": "String",
"StringValue.$": "$.hotel.end_date"
},
"my_attribute_no_3": {
"DataType": "String",
"StringValue.$": "$.hotel.reservation_id"
},
"my_attribute_no_4": {
"DataType": "String",
"StringValue.$": "$.hotel.name"
},
"my_attribute_no_5": {
"DataType": "String",
"StringValue.$": "$.museum.when"
},
"my_attribute_no_6": {
"DataType": "String",
"StringValue.$": "$.museum.reservation_id"
},
"my_attribute_no_7": {
"DataType": "String",
"StringValue.$": "$.museum.name"
}
}
}
},
从 AWS CloudWatch 的日志当中, 可检视由状态 NotifySuccess 所丢出的 “订单完成” 的事件的内容。

微服务 InvoicingBuilderFunction 如何的取得 “订单完成” 事件的内容 ?
- 微服务 InvoicingBuilderFunction 订阅了 SNS 的 Topic; OrderCompletedTopic。
- 状态; NotifySuccess会将 “订单完成” 的事件丢到 SNS 的 Topic; OrderCompletedTopic。
- 微服务 InvoicingBuilderFunction 将会由 SNS 的 Topic; OrderCompletedTopic 中, 取得 “订单完成” 事件的内容, 并将事件的内容写到 AWS S3 Bucket 当中。
创建 Amazon SNS (Amazon Simple Notification Service) 的 “主题 (Topic)”
Amazon SNS 的 Topic 主要是用来储存由 AWS Step Functions 所丢出的事件。

如上图所示, 创建了一特定的 SNS的Topic; OrderCompletedTopic。
微服务 InvoicingBuilderFunction 订阅了Amazon SNS 的 Topic; OrderCompletedTopic

在 Step Function BookingWorkflowOrchestrator 中, 加入角色 OrderWorkerflowRole

角色 OrderWorkerflowRole 的 inline policy OrderCompletedPublish 的设定如下图:

角色 OrderWorkerflowRole 使得Step Function BookingWorkflowOrchestrator 能有足够的权限可以丢出 “订单完成” 的事件到 SNS 的 Topic OrderCompletedTopic。
创建 IAM Users
- 创建的 IAM Users; a9-developer; 的 Policies 是: AWSLambdaBasicExecutionRole, AmazonS3FullAccess。

- 创建 IAM Users; a9-developer; 的 Access key; 此 Access Key 将在微服务 InvoicingBuilderFunction 的代码中, 创建 AWS S3 Bucket。

微服务 InvoicingBuilderFunction 的代码如下:
const AWS = require('aws-sdk');
let s3 = new AWS.S3({
accessKeyId: 'MY_ACCESS_KEY_ID',
secretAccessKey: 'MY_SECRET_ACCESS_KEY'
});
async function createOrderReceipt(message_id, message) {
let s3Bucket = 'MY_BUKET';
let objectKey = `${message_id}.json`;
let objectData = message;
let objectType = 'application/json';
try {
let params = {
Bucket: s3Bucket,
Key: objectKey,
Body: objectData,
ContentType: objectType
};
await s3.putObject(params).promise();
console.log(`File uploaded successfully at https:/` + s3Bucket + `.s3.amazonaws.com/` + objectKey );
} catch (error) {
console.error(JSON.stringify(error));
}
}
exports.handler = async(event, context, callback) => {
for (let i = 0; i < event.Records.length; i++) {
let sns_record = event.Records[i].Sns;
await createOrderReceipt(sns_record.MessageId, sns_record.Message);
}
};
测试 Step Function BookingWorkflowOrchestrator
测试的输入如下:
{
"purchase": {
"buyer_id": "mariano"
},
"hotel": {
"start_date": "2020-03-13",
"end_date": "2020-03-15"
},
"museum": {
"museum_name": "tate gallery",
"when": "2020-03-14"
}
}
最终, 由微服务 InvoicingBuilderFunction 写入到 S3 Bucket 的 object 的 JSON的内容如下:

完整的代码, 请参考: