ApsaraMQ for RabbitMQ menyediakan SDK untuk framework Spring. Topik ini menjelaskan cara mengintegrasikan Spring SDK untuk mengirim dan menerima pesan.
Prasyarat
-
Anda telah membuat resource seperti instans, vhost, exchange, dan queue di Konsol ApsaraMQ for RabbitMQ. Untuk informasi selengkapnya, lihat Langkah 2: Buat resource.
-
Spring Boot 2.1.2.RELEASE atau versi yang lebih baru telah diinstal.
Proyek demo
Klik SpringBootDemo.zip untuk mengunduh proyek demo.
Langkah 1: Konfigurasi parameter
Dalam file application.properties atau application.yml, atur parameter konfigurasi. Contoh berikut menggunakan file application.properties.
# Titik akhir. Dapatkan titik akhir di halaman Detail Instans pada Konsol ApsaraMQ for RabbitMQ.
spring.rabbitmq.host=XXXXXX.amqp.aliyuncs.com
# Port yang digunakan untuk terhubung ke ApsaraMQ for RabbitMQ.
spring.rabbitmq.port=5672
# Username statis instans. Lihat username di halaman Akun Statis pada Konsol ApsaraMQ for RabbitMQ.
spring.rabbitmq.username=******
# Password statis instans. Lihat password di halaman Akun Statis pada Konsol ApsaraMQ for RabbitMQ.
spring.rabbitmq.password=******
# Virtual host, yang menyediakan isolasi logis. Lihat virtual host di halaman Vhosts pada Konsol ApsaraMQ for RabbitMQ.
spring.rabbitmq.virtual-host=test_vhost
# Mode acknowledgment (Ack) pesan.
# 1. none: Setelah konsumen menerima pesan, server menganggap pesan telah berhasil diproses, terlepas dari apakah konsumsi berhasil atau tidak. Ini adalah mode autoAck di RabbitMQ.
# 2. auto: Klien secara otomatis mengirim ack setelah pesan berhasil dikonsumsi. Jika pemrosesan pesan gagal, klien mengirim nack atau melemparkan exception. Anda tidak perlu memanggil Channel.basicAck() secara eksplisit.
# 3. manual: Kirim Ack secara manual. Anda harus memanggil Channel.basicAck() secara eksplisit setelah pesan berhasil dikonsumsi.
spring.rabbitmq.listener.simple.acknowledge-mode=manual
# Atur mode cache ke CONNECTION. ApsaraMQ for RabbitMQ menggunakan arsitektur terdistribusi. Dalam mode CONNECTION, klien dapat terhubung ke beberapa node layanan di kluster secara lebih seimbang. Metode ini dapat mencegah hot spot beban secara efektif dan meningkatkan efisiensi pengiriman serta konsumsi pesan.
spring.rabbitmq.cache.connection.mode=connection
# Sesuaikan nilai sesuai kebutuhan.
spring.rabbitmq.cache.connection.size=50
# Sesuaikan nilai sesuai kebutuhan.
spring.rabbitmq.cache.channel.size=1
# Jumlah maksimum pesan yang belum diakui (Ack) yang dapat diproses oleh satu konsumen sekaligus (QoS). Server ApsaraMQ for RabbitMQ menggunakan min{prefetch, 100} sebagai nilai QoS. Jika kemampuan pemrosesan konsumen rendah, kurangi nilai ini.
spring.rabbitmq.listener.simple.prefetch=100
# Jumlah minimum konsumen konkuren untuk listener RabbitMQ. Sesuaikan nilai sesuai kebutuhan.
spring.rabbitmq.listener.simple.concurrency=10
# Jumlah maksimum konsumen konkuren untuk listener RabbitMQ. Saat laju konsumsi cukup tinggi, klien akan menjalankan max-concurrency konsumen untuk mengonsumsi pesan.
spring.rabbitmq.listener.simple.max-concurrency=20
Praktik Terbaik Koneksi dan Channel
ApsaraMQ for RabbitMQ menggunakan arsitektur multi-node terdistribusi di backend. Untuk menghindari bottleneck performa pada satu node di sisi server, ikuti praktik terbaik berikut saat mengonfigurasi koneksi klien.
-
Gunakan mode CONNECTION: Konfigurasikan klien untuk membuat beberapa koneksi TCP ke server. Dalam mode CONNECTION, satu klien mendistribusikan koneksi ke beberapa node layanan backend, sehingga memanfaatkan resource dari banyak node dalam kluster. Disarankan untuk mengonfigurasi jumlah koneksi (CONNECTION) per klien pada level puluhan, disesuaikan dengan volume traffic klien.
-
Hindari pembuatan dan pemutusan koneksi yang sering: Jangan sering membuat dan menutup koneksi. Siklus koneksi yang sering mengurangi efisiensi pengiriman dan konsumsi pesan. Pertahankan koneksi persisten alih-alih membuat koneksi untuk setiap operasi.
-
Batasi jumlah channel per koneksi: Atur jumlah channel yang dapat dibuat pada satu koneksi tidak lebih dari 50. Terlalu banyak channel pada satu koneksi dapat menyebabkan lonjakan traffic TCP mendadak. Ditambah dengan kemungkinan pengurutan ulang paket, hal ini dapat memicu mekanisme Linux Netfilter Conntrack untuk mengklasifikasikan paket sebagai INVALID, sehingga klien secara aktif mengirim RST untuk mereset koneksi.
Anda dapat mengonfigurasi mode koneksi dan jumlah CONNECTION/CHANNEL menggunakan parameter berikut:
-
spring.rabbitmq.cache.connection.mode– Atur keconnectionuntuk mode CONNECTION. -
spring.rabbitmq.cache.connection.size– Jumlah koneksi. Disarankan: level puluhan. -
spring.rabbitmq.cache.channel.size– Jumlah channel per koneksi. Disarankan: tidak lebih dari 50.
Anda dapat menambahkan konfigurasi opsional berikut sesuai kebutuhan:
Langkah 2: Gunakan SDK untuk mengirim dan menerima pesan
Produksi pesan
Dalam RabbitMQService, peroleh RabbitTemplate melalui dependency injection dan panggil metode send-nya untuk mengirim pesan.
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
@Service
public class RabbitMQService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void sendMessage(String exchange, String routingKey, String content) {
// Atur MessageId.
String msgId = UUID.randomUUID().toString();
MessageProperties messageProperties = new MessageProperties();
messageProperties.setMessageId(msgId);
// Buat Message.
Message message = new Message(content.getBytes(StandardCharsets.UTF_8), messageProperties);
/*
* Panggil antarmuka send() untuk mengirim pesan.
* exchange: nama exchange.
* routingKey: kunci routing.
* message: isi pesan.
* correlationData digunakan untuk publisher confirms.
*/
rabbitTemplate.send(exchange, routingKey, message, null);
}
}
Konsumsi pesan
Gunakan anotasi @RabbitListener untuk mengonsumsi pesan:
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
public class MessageListener {
/**
* Menerima pesan.
* @param message Pesan.
* @param channel Channel.
* @throws IOException
* Ganti queues dengan nama antrian yang telah Anda buat.
*/
@RabbitListener(queues = "myQueue")
public void receiveFromMyQueue(Message message, Channel channel) throws IOException {
// Masukkan logika bisnis untuk konsumsi pesan.
...
// Anda harus mengembalikan Ack dalam periode validitas Ack (timeout konsumsi). Jika tidak, konfirmasi tidak valid dan pesan akan dikirim ulang.
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
}
Berikut adalah konfigurasi opsional umum untuk RabbitListener:
Catatan penting
Verifikasi apakah klien Anda menggunakan metode receiveAndConvert dari RabbitTemplate untuk konsumsi pesan.
Metode ini menerima parameter seperti nama antrian dan durasi timeout. Saat timeout ditentukan, logika pemrosesan internal memiliki masalah berikut: sebelum mengonsumsi pesan, metode ini terlebih dahulu mengirim perintah BasicCancel untuk membatalkan langganan konsumen, lalu mengirim Ack untuk mengonfirmasi pesan.
Namun, saat ApsaraMQ for RabbitMQ menerima permintaan BasicCancel, server segera membatalkan konsumen yang bersangkutan dan memasukkan kembali semua pesan yang belum diakui ke antrian. Akibatnya, Ack yang dikirim klien setelah itu menjadi tidak valid — server tidak menganggapnya sebagai acknowledgment yang sah, melainkan mengirim ulang pesan-pesan tersebut, sehingga menyebabkan konsumsi duplikat di sisi klien.
Selain itu, jika antrian memiliki throughput pesan yang tinggi, operasi cancel dan requeue yang sering dapat menyebabkan akumulasi pesan, yang selanjutnya memengaruhi stabilitas konsumsi.