Java 模式以持续侦听AWS SQS消息
我有一个名为Java 模式以持续侦听AWS SQS消息,java,amazon-web-services,sdk,amazon-sqs,Java,Amazon Web Services,Sdk,Amazon Sqs,我有一个名为QueueService的简单类,其中包含一些方法,这些方法包装了AWS SQS SDK for Java中的方法。例如: public ArrayList<Hashtable<String, String>> receiveMessages(String queueURL) { List<Message> messages = this.sqsClient.receiveMessage(queueURL).getMessages(
QueueService
的简单类,其中包含一些方法,这些方法包装了AWS SQS SDK for Java中的方法。例如:
public ArrayList<Hashtable<String, String>> receiveMessages(String queueURL) {
List<Message> messages = this.sqsClient.receiveMessage(queueURL).getMessages();
ArrayList<Hashtable<String, String>> resultList = new ArrayList<Hashtable<String, String>>();
for(Message message : messages) {
Hashtable<String, String> resultItem = new Hashtable<String, String>();
resultItem.put("MessageId", message.getMessageId());
resultItem.put("ReceiptHandle", message.getReceiptHandle());
resultItem.put("Body", message.getBody());
resultList.add(resultItem);
}
return resultList;
}
这是正确的方法吗?我应该在SQS SDK中使用异步消息接收方法吗?您缺少一些东西:
- 使用
并设置等待时间以启用长轮询receiveMessages(ReceiveMessageRequest)
- 将AWS调用包装在try/catch块中。特别要注意
,如果飞行中的消息太多,则可能会从OverLimitException
引发该异常receiveMessages()
- 将
循环的整个主体包装在它自己的try/catch块中,记录捕获到的任何异常(不应该有——这是为了确保应用程序不会因为AWS更改了API或您忽略了处理预期异常而崩溃)while
至于使用异步客户机:您有什么特别的理由使用它吗?如果没有,则不要:单个接收方线程更易于管理。如果要使用SQS然后使用lambda来处理请求,则可以按照中给出的步骤进行操作,或者始终使用lambda而不是SQS,并为每个请求调用lambda 据我所知,Amazon SQS无法支持主动侦听器模型,其中Amazon SQS将“推送”消息到您的侦听器,或者在有消息时调用您的消息侦听器 因此,您必须始终轮询消息。轮询支持两种轮询机制:短轮询和长轮询。每种方法都有各自的优点和缺点,但是在大多数情况下,长轮询是您通常使用的方法,尽管默认的方法是短轮询。就网络流量而言,长轮询机制肯定更有效,更具成本效益(因为Amazon根据请求数量向您收费),而且当您希望以时间敏感的方式处理消息时(尽快处理),长轮询机制也是首选机制 关于长轮询和短轮询,有更多的复杂之处值得了解,在这里解释这些有点困难,但是如果你愿意,你可以通过下面的博客阅读更多的细节。它还有一些代码示例,应该会有所帮助 就while(true)循环而言,我认为这要视情况而定。 如果您使用长轮询,并且可以将等待时间设置为(最多)20秒,那么如果没有消息,您轮询SQS的频率不会超过20秒。如果有消息,您可以决定是频繁轮询(在消息到达时立即处理消息)还是始终按时间间隔处理消息(例如每n秒) 另一点需要注意的是,您可以在一个receiveMessages请求中读取多达10条消息,因此这也将减少您向SQS拨打的电话数量,从而降低成本。正如上面的博客详细解释的那样,您可能会请求阅读10条消息,但即使队列中有那么多消息,它也可能不会返回10条消息 不过,一般来说,如果您希望在运行时关闭轮询,我会说您需要构建适当的钩子和异常处理,以防使用while(true)类型的结构
另一个要考虑的问题是,您是否希望在主应用程序线程中查询SQL,或者希望生成另一个线程。因此,另一种选择可能是创建一个ScheduledThreadPoolExecutor,主线程为一个线程,以安排一个线程定期(每隔几秒钟)轮询SQS,并且您可能不需要while(true)结构。
使用异步客户机的原因是,将来会有一个应用程序(.jar)AWS Lambda中托管的服务将使用SQS服务包装器检查队列中是否有新消息要处理。由于Lambda通过事件触发或函数调用来收费,因此我认为只有在有新消息时才执行的侦听器(使用sqs+jws)会更便宜。如果我在最后一点上错了,请您纠正我好吗?异步客户端唯一要做的就是将每个非异步请求包装在一个可调用的
中,然后在一个内部线程池上运行它。我不确定“SQS服务包装器”是什么,但SQS目前不是受支持的事件源。大多数人使用SNS,有些人使用Kinesis。使用“SQS服务包装器”,我指的是我创建的类,它包装了SQS SDK的一些方法。我找到了一种设置侦听器lo的方法,该侦听器lo在队列中有新消息时触发。我应该更深入地研究文档。谢谢。我读过这篇文章,它使用了一个带有Cloudwatch的时间表,触发一个Lambda函数轮询队列。我试图避免时间调度器。今年SQS可以触发Lambda这在2017年是真的,尽管2018年6月28日,从SQS触发Lambda成为可能:@pzrq还值得注意的是,如果您使用SQS FIFO队列,您无法从SQS触发Lambda。自2019年11月起,还支持从SQS FIFO触发Lambda,但不保证只交付一次
while(true) {
messages = queueService.receiveMessages(queueURL);
for(Hashtable<String, String> message: messages) {
String receiptHandle = message.get("ReceiptHandle");
String messageBody = message.get("MessageBody");
System.out.println(messageBody);
queueService.deleteMessage(queueURL, receiptHandle);
}
}