مورد عجیب GoLang و RabbitMQ

امروز که مثل چند روز گذشته داشتم روی کد سرور چت آریو کار می‌کردم به مورد عجیبی خوردم که تا دیروز توی کد وجود نداشت.

ابتدا توضیح مختصری در مورد نحوه کار سرور چت آریو می‌گم که بیشتر موضوع رو درک کنید. ما برای اینکه بتونیم تراکنش‌های بالای چند هزار مسیج در ثانیه رو به اصطلاح هندل کنیم از سیستم RabbitMQ در کنار چندتا تکنولوژی دیگه استفاده می‌کنیم. همچنین در نسخه جدید هم تصمیم بر این شد که از زبان Golang استفاده کنیم. همچنین برای ارتباط بین Go و RabbitMQ از این کلاینت AMQP استفاده می‌کنیم.

و اما مشکلی که ابتدا بهش اشاره کردم این بود که حین کار سرور رو زیر بار گذاشته بودم برای تست متوجه میشدم که مثلا مسیج چند هزارم به بعد کانالی که با استفاده از اون مسیج رو به صف می‌فرستادم ناگهان بسته میشه. با بررسی لاگها به مشکل زیر رسیدم:

Server closed connection: UNEXPECTED_FRAME - expected content body, got non content body frame instead, code=505, class_id=60, method_id=40

و اما مشکل کار چی بود؟ نکته ساده‌ای وجود داشت که هرکسی که با RabbitMQ کار می‌کنه خوبه که بهش آگاه باشه اینه که همه channel هایی که برای ارسال یا دریافت مسیج به صف استفاده می‌شن بهتره که به صورت یک طرفه استفاده بشن. یعنی اینکه هر کدوم فقط برای ارسال یا فقط برای دریافت در نظر گرفته بشن. نکته مهم دیگری که اینجا اتفاق میوفتاد امکان رخ دادن به اصطلاح Race Condition زمانی بود که می‌خواستم توی مثلا ۲ تا goroutine مسیجی رو ارسال کنم که با پیغام خطای بالا کانال ارتباط بسته می‌شد و سرور کرش می‌کرد.

راه حل هم خیلی ساده این بود که برای هر Goroutine یک channel اختصاصی ایجاد بشه و ارسال و دریافت از طریق اون انجام بشه.