Latar belakang masalah:
Sekitar pukul 17:12 pada tanggal 1 bulan 9, kami menerima keluhan dari staf implementasi bahwa sebagian perangkat tidak dapat diperbarui secara normal, tidak menerima perintah yang dikirim konsol, dan mengalami masalah lainnya. Rekan kerja memeriksa log proyek control (selanjutnya disebut control) dan menemukan bahwa control tidak menerima informasi bayangan perangkat yang dilaporkan, sehingga tidak mengirimkan perintah. Proyek control terhubung langsung dengan perangkat dan mengirimkan sejumlah perintah serta informasi konfigurasi berdasarkan informasi yang dilaporkan perangkat, termasuk pembaruan, pelaporan log, dan sebagainya. Sebelum IoT diluncurkan, control mengandalkan laporan heartbeat untuk memperoleh informasi terkini perangkat; setelah IoT diluncurkan, control mengandalkan informasi bayangan perangkat
untuk memperoleh informasi terkini perangkat, control akan berlangganan informasi bayangan perangkat, tetapi informasi bayangan itu diteruskan oleh layanan bayangan(disingkat IoT). Ia tidak terhubung langsung dengan pelaporan bayangan perangkat. Untuk rincian alurnya, lihat dua gambar di bawah ini:
Aplikasi(control)memperoleh status perangkat

Aplikasi(control)mengirimkan perintah perangkat

Setelah mengetahui bahwa control tidak menerima pesan bayangan, saya segera membuka konsol rabbitmq untuk memeriksa apakah ada pesan dan memastikan dua hal:1.apakah perangkat telah melaporkan pesan 2.apakah rabbitmq berfungsi normal, gambar 1、gambar 2 di bawah adalah dua tangkapan layar konsol rabbitmq saat itu, dari Gambar 1 Dapat dipastikan dengan jelas bahwa perangkat memang mengirimkan pesan, tetapi banyak pesan berstatus unacked(Ini menunjukkan bahwa pesan sudah dikirim kepada konsumen, hanya saja konsumen belum mengirim ack. Secara teori, setelah menunggu beberapa saat, kondisinya akan kembali normal), untuk mengetahui antrean mana yang mengalami penumpukan pesan unacked, silakan lihat Gambar 2,“spacebridgeiot-shadow” memang digunakan untuk menerima informasi bayangan yang dilaporkan perangkat. Karena pesan menumpuk di antrean, wajar jika pesan tidak diteruskan ke control. Setelah mengamati selama beberapa waktu, kami mendapati jumlah unacked menjadi 0, tetapi jumlah total tidak banyak berubah. Kesannya, pesan unacked kembali ke antrean pesan untuk menunggu dikirim. Benar saja, beberapa menit kemudian muncul lagi banyak pesan unacked, lalu beberapa menit setelahnya pesan-pesan unacked itu kembali ke antrean. Pihak control masih belum menerima pesan. Saat memeriksa log di sisi IoT, ternyata tidak ada pesan bayangan yang masuk. Di konsol rabbitmq, kami memeriksa “spacebridgeiot-shadow” Ternyata antrean ini sudah tidak memiliki konsumen, seperti Gambar 3 seperti yang ditampilkan. Saat memeriksa log rabbitmq pada tahap ini, memang terdapat pesan kesalahan, seperti Gambar 4 seperti yang ditunjukkan, rabbitmq secara aktif menutup koneksi.
Gambar1:gambaran umum rabbitmq

Gambar2:diagram statistik antrean rabbitmq

Gambar 3:Gambaran umum spacebridgeiot-shadow

Gambar 4:Pesan kesalahan rabbitmq

Solusi sementara:
Karena saat itu sudah banyak keluhan masuk, digunakan solusi yang cukup kasar, yaitu “menghapus pesan yang menumpuk”, dan setelah dihapus ternyata semuanya kembali normal(Catatan:Masalah di lingkungan produksi harus diselesaikan secepat mungkin. Tidak ada waktu bagi kita untuk menganalisis log lalu menyelesaikannya dengan teratur, semuanya harus cepat)。

Mereproduksi masalah melalui lingkungan lokal:
1.Tumpuk sejumlah besar pesan(setidaknya puluhan ribu)di antrean “mirrorTestQueue” RabbitMQ pada lingkungan 10.200.41.166
2.Hentikan konsumen mirrorTestQueue, lalu jalankan kembali setelah penumpukan selesai
3.Penumpukan selesai, mulai ulang konsumen
Sesuai dugaan kami, dalam beberapa detik ribuan pesan dikirimkan ke konsumen. Setelah berlangsung beberapa menit, rabbitmq secara aktif menutup koneksi dengan konsumen, dan saat itu konsumen antrean tidak terlihat di konsol. Karena konsumen kami dikonfigurasi untuk melakukan pemulihan otomatis, setelah beberapa saat koneksinya akan tersambung kembali secara otomatis,
Namun, tak lama kemudian koneksinya kembali terputus, hampir sama persis dengan masalah yang kami temui di lingkungan produksi. Apa sebenarnya yang menyebabkan masalah ini?Sejujurnya, saat itu saya belum punya gambaran, dan setelah mencari ke sana kemari di internet pun saya tidak menemukan jawaban yang benar-benar memuaskan(Saat itu saya belum memahami inti masalahnya, kata kunci pencariannya terlalu umum),kemudian
Kami menduga mungkin ada masalah di lapisan TCP, jadi kami memutuskan untuk mencoba menangkap paket guna melihat apakah ada petunjuk. Benar saja, keberuntungan berpihak pada kami. Tanpa banyak bicara, langsung saja lihat gambarnya.


Sebelum 13:06:25.643428, rabbitmq terus mengirim pesan ke konsumen, hingga pada 13:06:25.643428 jendela TCP konsumen mulai penuh. Kondisi ini berlangsung sekitar 30 detik, lalu rabbitmq secara aktif memutus koneksi(mengirim paket RST). Setelah konsumen tersambung kembali, jendelanya kembali penuh dan koneksi kembali diputus setelah sekitar 30 detik.


Rasanya cukup teratur, setiap kali berlangsung 30s, sepertinya ini parameter yang dapat dikonfigurasi. Kira-kira dapat dirangkum sebagai “jendela TCP penuh menyebabkan server secara aktif mereset koneksi dengan RST, dan polanya juga teratur”
Kali ini saya mengganti kata kunci pencarian dan menemukan Jawaban, rabbitmq memiliki parameter bernama tcp_listen_options.send_timeout adalah parameter untuk mengendalikan batas waktu penulisan, setelah penulisan melewati batas waktu, RST tcp akan terpicu(https://github.com/rabbitmq/rabbitmq-java-client/issues/341),ubah sedikit dan coba lihat hasilnya:
1. Ubah batas waktu penulisan menjadi 10s
tcp_listen_options.send_timeout = 10000
2.Tangkap paket untuk melihat apakah sudah berfungsi


Dari jendela penuh hingga koneksi ditutup berlangsung sekitar 10 s.
Tinjauan ulang gejala:
Karena konsumen rabbitmq tidak mengatur prefetch, rabbitmq mengirim terlalu banyak pesan sekaligus kepada konsumen, sehingga jendela tcp konsumen menjadi penuh dan kemudian memicu tcp_listen_options.send_timeout pada rabbitmq. Setelah batas waktu penulisan ini mencapai ambang tertentu, rabbitmq akan memutus koneksi tcp konsumen.
Solusi pamungkas:
Penghapusan pesan sebelumnya hanyalah solusi terpaksa. Meski menyelesaikan masalah, cara itu terlalu kasar, sehingga kita perlu mencari solusi yang lebih elegan. Karena terlalu banyak pesan yang didorong ke konsumen membuat jendela tcp penuh, kita sebaiknya mengatur laju penerimaan:saat terhubung ke rabbitmq, cukup beri tahu agar tidak mengirim terlalu banyak pesan kepada kita.(Teks berikut dikutip dari https://blog.csdn.net/james_searcher/article/details/70308565)rabbitmq memiliki atribut bernama prefetch, yang berarti jumlah maksimum pesan tanpa konfirmasi penerimaan yang dapat dikonsumsi oleh satu konsumen. Bagaimana memahaminya?mq menyediakan buffer untuk setiap consumer, dengan ukuran sebesar prefetch. Setiap kali menerima sebuah pesan, MQ mendorong pesan tersebut ke buffer, lalu meneruskannya ke klien. Saat menerima pesan ack (consumer mengirimkan perintah baseack), mq mengosongkan satu tempat di buffer, lalu memasukkan pesan baru. Namun, jika buffer saat itu penuh, MQ akan memasuki keadaan terblokir. Lebih konkretnya, misalkan nilai prefetch ditetapkan sebesar 10 dan terdapat dua consumer. Artinya, setiap consumer akan mengambil lebih awal 10 pesan dari queue ke cache lokal untuk menunggu dikonsumsi. Pada saat yang sama, jumlah unacked pada channel tersebut menjadi 20. Urutan pengiriman Rabbit adalah mengirimkan terlebih dahulu 10 message hingga penuh ke consumer1, lalu mengirimkan 10 message ke consumer2. Jika saat itu ada message baru yang perlu dikirimkan, terlebih dahulu diperiksa apakah jumlah unacked pada channel sama dengan 20. Jika ya, pesan tidak akan dikirimkan ke consumer dan message tetap berada di queue. Setelah salah satu consumer melakukan ack terhadap satu pesan, jumlah unacked menjadi 19. Rabbit kemudian memeriksa consumer mana yang jumlah unacked-nya kurang dari 10, lalu mengirimkan pesan ke consumer tersebut.
Secara konkret dalam kode, bentuknya adalah

Bagaimana menilai nilai ini?Ada artikel resmi rabbitmq yang menjelaskannya dengan baik, jadi tidak akan saya uraikan lebih lanjut. Di sistem kami, nilai yang saat ini ditetapkan adalah 20.
https://www.rabbitmq.com/blog/2012/05/11/some-queuing-theory-throughput-latency-and-bandwidth/
Penutup:
Kami masih berada pada tahap pemula dalam menggunakan rabbitmq. Sebelum menggunakannya, pastikan untuk banyak membaca dokumentasi API rabbitmq, memahami penggunaan API yang umum, dan melakukan lebih banyak eksperimen di lingkungan lokal.