[英]Send 35000 jms messages per minute
我們有一個 spring 啟動應用程序,用於對另一個組件執行負載測試。 我們每分鍾最多需要發送 35000 條 JMS 消息,因此我使用調度程序每分鍾運行一次任務。
問題是當我保持低強度時,它設法在指定的時間間隔(一分鍾)內發送消息。 但是當強度很高時,發送大量消息需要超過 1 分鍾的時間。 對以下實施有何建議?
調度員 class
@Component
public class MessageScheduler {
private final Logger log = LoggerFactory.getLogger(getClass());
private static ScheduledExecutorService executorService = Executors.newScheduledThreadPool(16);
private final static int TIME_PERIOD = ConfigFactory.getConfig().getInt("messages.period").orElse(60000);
@Autowired
JmsSender sender;
public void startScheduler() {
Runnable runnableTask = sender::sendMessagesChunk;
executorService.scheduleAtFixedRate(runnableTask, 0, TIME_PERIOD,
TimeUnit.MILLISECONDS);
}
}
Class 用於發送消息
@Component
public class JmsSender {
@Autowired
TrackingManager manager;
private final Logger log = LoggerFactory.getLogger(getClass());
private final static int TOTAL_MESSAGES = ConfigFactory.getConfig().getInt("total.tracking.messages").orElse(10);
private final static int TIME_PERIOD = ConfigFactory.getConfig().getInt("messages.period").orElse(60000);
private static int failedPerPeriod=0;
private static int totalFailed=0;
private static int totalMessageCounter=0;
public void sendMessagesChunk() {
log.info("Started at: {}", Instant.now());
log.info("Sending messages with intensity {} messages/minute", TOTAL_MESSAGES);
for (int i=0; i<TOTAL_MESSAGES; i++) {
try {
long start = System.currentTimeMillis();
MessageDTO msg = manager.createMessage();
send(msg);
long stop = System.currentTimeMillis();
if (timeOfDelay(stop-start)>=0L) {
Thread.sleep(timeOfDelay(stop-start));
}
} catch (Exception e) {
log.info("Error : " + e.getMessage());
failedPerPeriod++;
}
}
totalMessageCounter += TOTAL_MESSAGES;
totalFailed += failedPerPeriod;
log.info("Finished at: {}", Instant.now());
log.info("Success rate(of last minute): {} %, Succeeded: {}, Failed: {}, Success rate(in total): {} %, Succeeded: {}, Failed: {}"
,getSuccessRatePerPeriod(), getSuccededPerPeriod(), failedPerPeriod,
getTotalSuccessRate(), getTotalSucceded(), totalFailed);
failedPerPeriod =0;
}
private long timeOfDelay(Long elapsedTime){
return (TIME_PERIOD / TOTAL_MESSAGES) - elapsedTime;
}
private int getSuccededPerPeriod(){
return TOTAL_MESSAGES - failedPerPeriod;
}
private int getTotalSucceded(){
return totalMessageCounter - totalFailed;
}
private double getSuccessRatePerPeriod(){
return getSuccededPerPeriod()*100D / TOTAL_MESSAGES;
}
private double getTotalSuccessRate(){
return getTotalSucceded()*100D / totalMessageCounter;
}
private void send(MessageDTO messageDTO) throws Exception {
requestContextInitializator();
JmsClient client = JmsClientBuilder.newClient(UriScheme.JmsType.AMQ);
client.target(new URI("activemq:queue:" + messageDTO.getDestination()))
.msgTypeVersion(messageDTO.getMsgType(), messageDTO.getVersion())
.header(Header.MSG_VERSION, messageDTO.getVersion())
.header(Header.MSG_TYPE, messageDTO.getMsgType())
.header(Header.TRACKING_ID, UUID.randomUUID().toString())
.header(Header.CLIENT_ID, "TrackingJmsClient")
.post(messageDTO.getPayload());
}
你應該解決兩個問題:
顯然,如果您的send
方法太慢,將超過最大時間。
發送消息的更快方法是使用某種批量操作。 沒關系,如果你的MQ API不支持批量操作,你就不能使用它! 因為第二個限制(“統一”)。
您可以異步發送消息,但如果您的MQ API為其創建線程而不是“非阻塞”異步,則可能存在內存問題。
使用javax.jms.MessageProducer.send
可以異步發送消息,但是將為每個消息創建一個新的線程(將創建大量內存和服務器線程)。
另一個加速可能只創建一個JMS客戶端(您的send
方法)。
要達到第二個要求,你應該修復你的timeOfDelay
函數,這是錯誤的。 實際上,您應該考慮send
函數的概率分布來估計正確的值,但是,您可以簡單地做:
long accTime = 0L;
for (int i=0; i<TOTAL_MESSAGES; i++) {
try {
long start = System.currentTimeMillis();
MessageDTO msg = manager.createMessage();
send(msg);
long stop = System.currentTimeMillis();
accTime += stop - start;
if(accTime < TIME_PERIOD)
Thread.sleep((TIME_PERIOD - accTime) / (TOTAL_MESSAGES - i));
} catch (Exception e) {
log.info("Error : " + e.getMessage());
failedPerPeriod++;
}
}
35000 msg/min 低於 600 msg/sec。 這不算“很多”,應該是相對容易清除的目標。 主要想法是“重用”所有重量級 JMS 對象:連接、session 和目的地。 單線程應該足夠了。
ConnectionFactory connFactory = .... // initialize connection factory
@Cleanup Connection conn = connFactory.createConnection();
@Cleanup Session session = conn.createSession(true, Session.SESSION_TRANSACTED);
Queue q = session.createQueue("example_destiation");
@Cleanup MessageProducer producer = session.createProducer(q);
for (String payload: messagesToSend) {
TextMessage message = session.createTextMessage(payload);
producer.send(msg);
session.commit();
}
額外的加速是可能的:
NON_PERSISTENT、ACKOWLEDGE、ASYNC 傳送示例:
@Cleanup Connection conn = connFactory.createConnection();
@Cleanup Session session = conn.createSession(false, Session.DUPS_OK_ACKNOWLEDGE);
Queue q = session.createQueue("example_destiation");
@Cleanup MessageProducer producer = session.createProducer(q);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
producer.setAsync(new ExmpleSendListener());
for (String payload: messagesToSend) {
TextMessage message = session.createTextMessage(payload);
producer.send(msg);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.