Saturday, March 11, 2017

AWS SQS

云端队列服务,客户端polling获取。用于不同系统间通信和解耦。

使用场景

SQS是非实时处理任务,将同步变异步解耦削峰,是一个分布式的FIFO队列。需要创建一个叫QueueName的队列,然后通过SQSclient发消息到此队列,另一个SQSclient从此队列收消息。


架构


队列(保存多个消息) 在多个 Amazon SQS 服务器上冗余存储消息。

短轮询
Wait time set to 0. 采样方式获取信息,因为采用冗余,这次获取不了某信息,下次将会获得。

Queue参数
Delivery delay: 延时一段时间sender的SQS client才发送到云端Queue中
Receive message wait time: recevier的SQS客户端每隔多长时间会从云端Queue中poll信息。默认为
20s,即使空的信息也会poll。会看到客户端的latency就会是这个数。用SNS可以将Poll变成Push模式。
Retention period: msg保留时长1min-14天


sendMessage, receiveMessage API的latency是几十到低几百毫秒。


最佳实践

常与SNS连用。
DynamoDB stream->SQS/SNS->Elastic search
System 1->SQS->System 2

Queue Actions 中,选择 Subscribe Queue to SNS Topic (或 Subscribe Queues to SNS Topic)。

队列操作中,选择Configure Trigger for Lambda Function (为 函数配置触发器)。
SQS作为触发器,会有5个线程每20秒poll一次,所以一分钟是15个 empty receives. 一天是21600个SQS
request,free tier是1百万次,如果超过,基本上是1个SQS用2蚊一个月。

底层API

final SendMessageResult sendMessageResult = sqs.sendMessage(
new SendMessageRequest(myQueueUrl, "This is my message text."));
final String messageId = sendMessageResult.getMessageId();


SendMessageRequest request = new SendMessageRequest(myQueueUrl, "This is my message
text.");
request.setDelaySeconds(5);


final ReceiveMessageRequest receiveMessageRequest = new
 ReceiveMessageRequest(myQueueUrl);
final List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages();
for (final Message message : messages) {
    System.out.println("Message");
    System.out.println("  MessageId: " + message.getMessageId());
    System.out.println("  ReceiptHandle: " + message.getReceiptHandle());
    System.out.println("  MD5OfBody: " + message.getMD5OfBody());
    System.out.println("  Body: " + message.getBody());
    for (final Entry<String, String> entry : message.getAttributes().entrySet()) {
        System.out.println("Attribute");
        System.out.println("  Name: " + entry.getKey());
        System.out.println("  Value: " + entry.getValue());
} }

功能


标准队列
无限吞吐量 – 标准 队列每个 操作支持接近无限的每 秒事务数 (TPS)。 
(含重)至少传送一次 – 消息至少传送一次,但偶尔会传送 消息的多个副本。
标准 队列每个 操作支持接近无限的每秒事务数 (TPS)。 标准队列支 持至少一次消息传递。但是,
由于存在允许近乎无限吞吐量的高度分布式架构,偶尔会有一条消息的多个副本不按顺序传送。标准
队列会尽最大努力进行排序,保证了消息大致按其发送的顺序进行传递。亲身经历,即使我发了两条
信息到SQS,但看到message in flight是6,重复了2倍。如果lambda是heavy计算且会写入S3或DB的
话,最好用FIFO。

In flight
当一个信息被一个lambda pickup,该message就会被移到in flight,当可见性超时,就会从in flight移回
queue中。


FIFO 队列
高吞吐量 – 默认情况下,借助批处 理,FIFO 队列每秒支持多达 3000 条消息。
(去重)仅传输一次处理 – 消息传递一次并在使用者处理 并删除它之前保持可用。不会将重复项引入
到队列 中。这个通过指定dedupeID(messageGroupId specified by sender)实现或者enable
先进先出传递 – 严格保持消息的发送和接收顺序。

吞吐量很重要时用标准队列,当事件的顺序重要时用FIFO。

可见性超时: 收到消息后,消息将立即保留在队列中。为防止其他使用者再次处理消息,Amazon 
SQS 设置了可见性超 时,这是 Amazon SQS 防止其他使用者接收和处理消息的时间段。消息的
默认可见性超时为 30 秒。最小值 为 0 秒。最大值为 12 小时。 这是console的配置,针对所有信息。
API可针对单个或多个信息。

一般设置为lambda timeout的6倍,因为2次retry
To allow your function time to process each batch of records, set the source queue's visibility timeout to at least 6 times the timeout that you configure on your function.

延迟队列

延迟队列可让您将针对队列的新消息传递操作推迟特定的秒数。如果您创建延迟队列,则发送到该
队列的任何消息在延迟期间对用户都保持不可见。

死信队列Dead letter queue:死信队列是其他(源)队列可将其作为无法成功处理(使用)的消息的目标的队列。当消息的 ReceiveCount 超出队列的 maxReceiveCount 时,Amazon SQS 会将该消息移到死信队列。FIFO 队列的死信队列也必须为 FIFO 队列。同样,标准 队列的死信队列也必须为 标准 队列。 死信队列的主要任务是处理消息失败。利用死信队列,您可以留出和隔离无法正确处理的消息以确定其处理 失败的原因。

我做过一个的例子是用sqs触发lambda,只要在lambda中throw exception就可以让msg等待可见性时段,SQS会自动将它放回原队列中,让它重试,这是maxReceiveCount+1。当超过maxReceiveCount时,msg会被放入DLQ,所以若maxReceiveCount设置比较大,会lambda会多次运行。Retention period要多于maxReceiveCount,否则,msg会被删除而没有机会进入DLQ。SQS-Lambda的可视时间设置为15分钟(=lambda的timeout时间),若maxReceiveCount=2,要等30分钟,msg会被放入DLQ。DLQ每poll一次(包括打开UI),count就会+1. msg被成功处理后,会被自动删除,不需要consumer做。Lambda最好不要有cache(class variable甚至是static),因为如果某段时间内,若lambda没有收到任何request,含lambda的容器才会重启,cache才有机会被refresh。所以若一直有request,cache永远不会被更新。
总结:
1. Lambda不需要retry,因为maxReceiveCount就是retry
2. retention period和maxReceiveCount共同决定retry次数。默认值分别为4天和500,若lambda时间为15分钟,500是一个非常大的值,lambda会跑4天,所以我的经验是设置rentention为12小时,maxReceives为3.

使用 Amazon S3 管理大型 Amazon SQS 消息。只适用于Java SDK


Kinesis的区别:Kinesis是实时的且可用于大数据。


官网
Github的Java例子
SQS->Lambda
Lambda中的cache

No comments:

Post a Comment