我有一个应用程序可以将简单的SQS消息发送到多个队列。以前,这个发送是连续发生的,但是现在我们需要发送更多队列,我决定通过在线程池(最多10个线程)中进行所有发送来并行化它。
但是,我注意到当我在工作中抛出更多线程时,sqs.sendMessage延迟似乎会增加!
我在下面创建了一个示例程序来重现问题(请注意numIterations
只是为了获取更多数据,这只是用于演示目的的代码的简化版本)。
在相同区域的EC2实例上运行并使用7个队列,我通常得到平均结果大约12-15ms,1个线程,21-25ms,7个线程 - 几乎是延迟的两倍!
即使从我的笔记本电脑远程运行(创建此演示时),我的平均延迟时间约为90毫秒,1个线程,约120毫秒,7个线程。
public static void main(String[] args) throws Exception {
AWSCredentialsProvider creds = new AWSStaticCredentialsProvider(new BasicAWSCredentials(A, B));
final int numThreads = 7;
final int numQueues = 7;
final int numIterations = 100;
final long sleepMs = 10000;
AmazonSQSClient sqs = new AmazonSQSClient(creds);
List<String> queueUrls = new ArrayList<>();
for (int i=0; i<numQueues; i++) {
queueUrls.add(sqs.getQueueUrl("testThreading-" + i).getQueueUrl());
}
Queue<Long> resultQueue = new ConcurrentLinkedQueue<>();
sqs.addRequestHandler(new MyRequestHandler(resultQueue));
runIterations(sqs, queueUrls, numThreads, numIterations, sleepMs);
System.out.println("Average: " + resultQueue.stream().mapToLong(Long::longValue).average().getAsDouble());
System.exit(0);
}
private static void runIterations(AmazonSQS sqs, List<String> queueUrls, int threadPoolSize, int numIterations, long sleepMs) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(threadPoolSize);
List<Future<?>> futures = new ArrayList<>();
for (int i=0; i<numIterations; i++) {
for (String queueUrl : queueUrls) {
final String message = String.valueOf(i);
futures.add(executor.submit(() -> sendMessage(sqs, queueUrl, message)));
}
Thread.sleep(sleepMs);
}
for (Future<?> f : futures) {
f.get();
}
}
private static void sendMessage(AmazonSQS sqs, String queueUrl, String messageBody) {
final SendMessageRequest request = new SendMessageRequest()
.withQueueUrl(queueUrl)
.withMessageBody(messageBody);
sqs.sendMessage(request);
}
// Use RequestHandler2 to get accurate timing metrics
private static class MyRequestHandler extends RequestHandler2 {
private final Queue<Long> resultQueue;
public MyRequestHandler(Queue<Long> resultQueue) {
this.resultQueue = resultQueue;
}
public void afterResponse(Request<?> request, Response<?> response) {
TimingInfo timingInfo = request.getAWSRequestMetrics().getTimingInfo();
Long start = timingInfo.getStartEpochTimeMilliIfKnown();
Long end = timingInfo.getEndEpochTimeMilliIfKnown();
if (start != null && end != null) {
long elapsed = end-start;
resultQueue.add(elapsed);
}
}
}
我确定这是一些奇怪的客户端配置问题,但默认的ClientConfiguration应该能够处理50个并发连接。
有什么建议吗?
更新:看起来这个问题的关键是我遗漏了原始简化版本的问题 - 发送的批次邮件之间存在延迟(与处理相关)。如果延迟是~2s,则延迟问题不存在,但当批次之间的延迟为~10s时, 是个问题。我为ClientConfiguration.validateAfterInactivityMillis
尝试了不同的值而没有效果。