Покращення вашої серверної системи за допомогою Amazon SQS

Я маю вільний час під час новорічних свят і шукаю щось цікаве, щоб втекти від повсякденної рутини. У своєму щоденному житті я пишу код на JavaScript/TypeScript та Python.

pic

Аеропорт Балі

Кілька місяців тому я вивчав Go і працював над проектом з використанням цієї мови, і сьогодні я повертаюся до програмування на Go (якщо чесно, я дуже люблю Go). Тому я вирішив дослідити кілька цікавих проектів під час свят і поринути в тему черг повідомлень.

Перше, що я зробив — це дослідження структури проектів на Go. Я натрапив на репозиторій https://github.com/golang-standards/project-layout, який надає інсайти щодо стандартної структури проектів для Go. (Хоча, чесно кажучи, офіційного стандарту для структури проектів у Go немає.)

pic

Структура проекту

Після цього я створив новий проект для RESTful API. API досить просте, з функцією, що дозволяє користувачам реєструвати нові акаунти. Користувачі, які успішно зареєструються, отримають привітальний електронний лист.

  • cmd — головне додаток
  • db — для зберігання міграцій
  • internal — приватний код додатка, такий як конфігурація
  • store — директорія для написання коду додатка. Усередині неї ми маємо use case і репозиторій.

Архітектура, яку я використовую — це мікросервіси, що складаються з двох сервісів:

  1. Перший сервіс обробляє реєстрацію користувачів.
  2. Другий сервіс надсилає привітальний лист користувачу.

По суті, ми могли б досягти цього за допомогою монолітної архітектури або одного сервісу. Але чому ми розділили це на різні сервіси? Просто тому, що ми хочемо зменшити зв’язок між сервісами.

pic

Розподілення на сервіси дозволяє зменшити ризик відмов, наприклад, коли сервер на бекенді перевантажений, не може обробляти запити та, зрештою, виходить з ладу або аварійно завершується. Рішення цієї проблеми — усунути залежності між компонентами в архітектурі додатка. Як це зробити?

Ми можемо використовувати чергу повідомлень. Черги повідомлень — це форма асинхронної комунікації між сервісами, яку часто використовують в архітектурах мікросервісів.

Ідея використання черги повідомлень не обмежується лише мікросервісами. У нашому випадку (надсилання листів) може бути не потрібно відправляти листа миттєво або в реальному часі. Натомість ми можемо застосувати асинхронний підхід, саме тому ми вибрали використання черги повідомлень.

Ми можемо використовувати інструменти для черг повідомлень, такі як RabbitMQ. Однак, використовуючи RabbitMQ, нам потрібно самостійно керувати інфраструктурою. Якщо ви не хочете займатися управлінням програмного забезпечення або підтримкою інфраструктури, ви можете вибрати Amazon SQS.

pic

Amazon SQS

Amazon Simple Queue Service (Amazon SQS) надає безпечну, надійну та доступну хостингову чергу, що дозволяє інтегрувати та зменшувати зв’язок між розподіленими програмними системами та компонентами.

Чому ми використовуємо Amazon SQS?

Тому що ми хочемо спростити нашу інфраструктуру та уникнути її управління. Amazon SQS надає простий та надійний спосіб для клієнтів зменшити зв’язок і з’єднувати компоненти (мікросервіси) разом, використовуючи черги.

Особливості Amazon SQS

  • Amazon SQS має два типи: Standard і FIFO (First In, First Out).
    Необмежена кількість повідомлень і черг.
  • Шифрування повідомлень, захист вмісту повідомлень у чергах Amazon SQS за допомогою ключів, що керуються в AWS Key Management Service (AWS KMS).
  • Інтеграція з іншими сервісами Amazon.
  • Пакети: надсилайте, отримуйте або видаляйте повідомлення пакетами до 10 повідомлень або 256 КБ.

Попередні вимоги

  • Обліковий запис AWS
  • Ключі доступу AWS

Для зручності ви можете використовувати стартовий проект: https://github.com/arasopraza/go-rest

Отже, давайте перейдемо до коду ~~

У першому проекті RESTful API встановіть конфігурацію AWS та SDK сервісу SQS v2 для Go за допомогою наступної команди:

go get github.com/aws/aws-sdk-go-v2/config  
go get github.com/aws/aws-sdk-go-v2/service/sqs

Далі створіть нову директорію всередині директорії internal, яку назвемо “sqs”.

Всередині цієї директорії створіть новий файл з назвою “sqs.go”.

Тепер напишіть цей код:

Функція NewClient ініціалізує клієнт для SQS і завантажує конфігурацію, яку ми маємо локально. Функція SendMessage відповідає за збереження повідомлення в SQS.

У файлі main.go імпортуємо клієнт SQS таким чином:

queueUrl := os.Getenv("SQS_URL")  
sqsClient := sqs.NewClient(queueUrl)

Переконайтеся, що ви вже створили чергу в Amazon SQS.

Amazon SQS підтримує два типи черг: стандартні черги та FIFO черги. Ось основні відмінності між ними:

  • Стандартна черга: гарантує принаймні одноразову доставку, що означає, що ваше повідомлення може бути отримано більше одного разу. Використовуйте це, якщо порядок повідомлень не є пріоритетом.
  • FIFO черга: гарантує точно одноразову доставку та зберігає порядок повідомлень. Використовуйте це, якщо потрібно забезпечити доставку повідомлень у правильному порядку.

Оскільки порядок повідомлень не є пріоритетним у цьому випадку, ми використаємо стандартну чергу.

pic

Панель керування чергами Amazon SQS

Далі відкрийте ваш use case. У цьому випадку ми напишемо use case наступним чином:

У цьому сценарії ми хочемо надіслати електронний лист після того, як користувач успішно зареєструється. Отже, ми додаємо клієнт SQS як залежність для use case користувача.

У функції CreateUser, після того як користувач успішно зареєструється, ми викликаємо сервіс SQS і надсилаємо повідомлення до Amazon SQS, яке містить електронну пошту користувача. Електронна пошта користувача, надіслана до Amazon SQS, буде оброблена нашим другим сервісом.

Налаштування другого сервісу

Створіть другий сервіс для надсилання привітального листа користувачу. Цей сервіс дуже простий — він виконує лише одне завдання: надсилає електронний лист.

Подібно до першого сервісу, потрібно встановити залежності. Запустіть цю команду для встановлення необхідних залежностей:

go get github.com/aws/aws-sdk-go-v2/config  
go get github.com/aws/aws-sdk-go-v2/service/sqs

Перше, що ми робимо, — налаштовуємо електронну пошту за допомогою пакету net/smtp.

Створіть файл під назвою send_email.go всередині нової директорії з назвою “actions”. Напишіть код таким чином:

Далі створіть новий файл get_message.go всередині директорії actions.

Відкрийте файл і напишіть код наступним чином:

package actions  

import (  
 "context"  
 "log"  

 "github.com/aws/aws-sdk-go-v2/aws"  
 "github.com/aws/aws-sdk-go-v2/service/sqs"  
 "github.com/aws/aws-sdk-go-v2/service/sqs/types"  
)  

type SqsActions struct {  
 SqsClient *sqs.Client  
}  

func (actor SqsActions) GetMessages(ctx context.Context, queueUrl string, maxMessages int32, waitTime int32) ([]types.Message, error) {  
 var messages []types.Message  
 result, err := actor.SqsClient.ReceiveMessage(ctx, &sqs.ReceiveMessageInput{  
 QueueUrl: aws.String(queueUrl),  
 MaxNumberOfMessages: maxMessages,  
 WaitTimeSeconds: waitTime,  
 })  
 if err != nil {  
 log.Printf("Не вдалося отримати повідомлення з черги %v.
Ось чому: %v\n", queueUrl, err)  
 } else {  
 messages = result.Messages  
 }  
 return messages, err  
}  

func (actor SqsActions) DeleteMessage(ctx context.Context, queueUrl string, receiptHandle string) (*sqs.DeleteMessageOutput, error) {  
 return actor.SqsClient.DeleteMessage(ctx, &sqs.DeleteMessageInput{  
 QueueUrl: aws.String(queueUrl),  
 ReceiptHandle: aws.String(receiptHandle),  
 })  
}

Ми створюємо дві функції, GetMessages і DeleteMessage. Функція GetMessages отримує повідомлення з вказаної черги SQS. Функція DeleteMessage видаляє конкретне повідомлення з черги SQS за допомогою його обробного хендла після його споживання.

Пам'ятайте: повідомлення в стандартній черзі Amazon SQS можуть бути доставлені більше одного разу через спроби повторної доставки або затримки. Тому важливо видаляти повідомлення після його споживання, щоб запобігти множинним доставкам.

Далі створіть файл main.go і напишіть код таким чином:

package main  

import (  
 "context"  
 "log"  

 "github.com/joho/godotenv"  
)  

func main() {  
 ctx := context.Background()  

 err := godotenv.Load("../.env")  
 if err != nil {  
 log.Fatal(err)  
 }  
}

Далі, у файлі main.go, додайте функцію processMessage.

func processMessage(sqsActions actions.SqsActions, queueUrl string) error {  
 messages, err := sqsActions.GetMessages(context.Background(), queueUrl, int32(10), int32(20))  
 if err != nil {  
 log.Fatalf("Не вдалося отримати повідомлення: %v", err)  
 }  

 // // Перевірте, чи немає повідомлень у черзі  
 if len(messages) == 0 {  
 fmt.Println("У черзі немає нових повідомлень.")  
 return nil  
 }  

 // // Вивести повідомлення  
 for _, message := range messages {  
 err = actions.SendMail(*message.Body)  
 if err != nil {  
 log.Fatal(err.Error())  
 continue  
 }  

 _, err = sqsActions.DeleteMessage(context.Background(), queueUrl, *message.ReceiptHandle)  
 if err != nil {  
 log.Printf("Не вдалося видалити повідомлення: %v", err)  
 } else {  
 log.Printf("Повідомлення видалено: %s", *message.Body)  
 }  

 fmt.Printf("Електронний лист успішно надіслано для повідомлення: %s\n", *message.Body)  
 }  

 return nil  
}

Далі, в функції main.go, напишіть наступне:

sdkConfig, err := config.LoadDefaultConfig(ctx, config.WithRegion("ap-southeast-1"))  
 if err != nil {  
 fmt.Println(err)  
 return  
 }  

 // Створіть клієнт SQS  
 sqsClient := sqs.NewFromConfig(sdkConfig)  

 // Створіть екземпляр SqsActions  
 sqsActions := actions.SqsActions{SqsClient: sqsClient}  

 // Визначте параметри  
 queueUrl := os.Getenv("SQS_URL")  

 log.Println("Сервіс споживача працює...")  
 for {  
 err := processMessage(sqsActions, queueUrl)  
 if err != nil {  
 log.Printf("Помилка обробки повідомлень: %v", err)  
 }  
 time.Sleep(5 * time.Second)  
 }

Ми налаштовуємо конфігурацію SDK та клієнт Amazon SQS. Потім викликаємо функцію processMessage, щоб отримати повідомлення з Amazon SQS.

Ось повний код для main.go

Тестування

Зрештою, ми можемо запустити наші сервіси.

У першому сервісі виконайте команду make run app.

pic

У другому сервісі виконайте команду go run main.go.

pic

Другий сервіс буде слухати Amazon SQS.

Якщо є повідомлення, сервіс негайно споживає його. У повідомленні буде адреса електронної пошти користувача, який успішно зареєструвався. Після цього другий сервіс використовує цю електронну пошту як отримувача.

Натисніть на кінцеву точку localhost:3000/api/v1/user.
Напишіть тіло запиту, як у цьому прикладі.

pic

Тіло запиту містить ім'я користувача та електронну пошту.

Запустіть HTTP запит, і якщо він буде успішним, ви отримаєте відповідь, як на цьому зображенні.

pic

Далі, перейдіть до вашого другого сервісу та спостерігайте за логами в терміналі.

pic

Коли в Amazon SQS з'явиться повідомлення, сервіс одразу його споживає та виконує своє завдання, а саме — надсилає електронний лист.

Щоб переконатися, що електронний лист було надіслано, ми можемо перевірити поштову скриньку (для цього тестування ми використовуємо Mailtrap).

pic

Класно!

Користувач успішно отримує привітальний електронний лист.

У консолі AWS ви також можете моніторити вашу чергу, перейшовши за цим посиланням: https://console.aws.amazon.com/sqs/. Перейдіть до однієї з ваших черг, а потім виберіть вкладку Моніторинг.

pic

Моніторинг Amazon SQS

Додатково ви можете інтегрувати Amazon SQS з Amazon CloudWatch, щоб моніторити більш детальні метрики та активувати ведення логів для кращої видимості.

Дякую за прочитане ~~

Хочете зв'язатися?  
https://www.linkedin.com/in/arasopraza/  
https://github.com/arasopraza  
  
https://arsyopraza.com

Посилання:

[

Приклади Amazon SQS із використанням AWS SDK для Go

Використовуйте приклади коду Amazon SQS для написання власних Go застосунків.

docs.aws.amazon.com

](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/using-sqs-with-go-sdk.html?source=post_page-----2e4e5f32a75b--------------------------------)

[

Що таке AWS SDK для Go v2?

Дізнайтеся більше про AWS SDK для Go v2

docs.aws.amazon.com

](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/welcome.html?source=post_page-----2e4e5f32a75b--------------------------------)

[

sqs

Пакет sqs надає клієнт API, операції та параметри для Amazon Simple Queue Service.

pkg.go.dev

](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/sqs?source=post_page-----2e4e5f32a75b--------------------------------#pkg-overview)

Перекладено з: Enhancing Your Back-End System with Amazon SQS

Leave a Reply

Your email address will not be published. Required fields are marked *