Я маю вільний час під час новорічних свят і шукаю щось цікаве, щоб втекти від повсякденної рутини. У своєму щоденному житті я пишу код на JavaScript/TypeScript та Python.
Аеропорт Балі
Кілька місяців тому я вивчав Go і працював над проектом з використанням цієї мови, і сьогодні я повертаюся до програмування на Go (якщо чесно, я дуже люблю Go). Тому я вирішив дослідити кілька цікавих проектів під час свят і поринути в тему черг повідомлень.
Перше, що я зробив — це дослідження структури проектів на Go. Я натрапив на репозиторій https://github.com/golang-standards/project-layout, який надає інсайти щодо стандартної структури проектів для Go. (Хоча, чесно кажучи, офіційного стандарту для структури проектів у Go немає.)
Структура проекту
Після цього я створив новий проект для RESTful API. API досить просте, з функцією, що дозволяє користувачам реєструвати нові акаунти. Користувачі, які успішно зареєструються, отримають привітальний електронний лист.
cmd
— головне додатокdb
— для зберігання міграційinternal
— приватний код додатка, такий як конфігураціяstore
— директорія для написання коду додатка. Усередині неї ми маємо use case і репозиторій.
Архітектура, яку я використовую — це мікросервіси, що складаються з двох сервісів:
- Перший сервіс обробляє реєстрацію користувачів.
- Другий сервіс надсилає привітальний лист користувачу.
По суті, ми могли б досягти цього за допомогою монолітної архітектури або одного сервісу. Але чому ми розділили це на різні сервіси? Просто тому, що ми хочемо зменшити зв’язок між сервісами.
Розподілення на сервіси дозволяє зменшити ризик відмов, наприклад, коли сервер на бекенді перевантажений, не може обробляти запити та, зрештою, виходить з ладу або аварійно завершується. Рішення цієї проблеми — усунути залежності між компонентами в архітектурі додатка. Як це зробити?
Ми можемо використовувати чергу повідомлень. Черги повідомлень — це форма асинхронної комунікації між сервісами, яку часто використовують в архітектурах мікросервісів.
Ідея використання черги повідомлень не обмежується лише мікросервісами. У нашому випадку (надсилання листів) може бути не потрібно відправляти листа миттєво або в реальному часі. Натомість ми можемо застосувати асинхронний підхід, саме тому ми вибрали використання черги повідомлень.
Ми можемо використовувати інструменти для черг повідомлень, такі як RabbitMQ. Однак, використовуючи RabbitMQ, нам потрібно самостійно керувати інфраструктурою. Якщо ви не хочете займатися управлінням програмного забезпечення або підтримкою інфраструктури, ви можете вибрати Amazon SQS.
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 черга: гарантує точно одноразову доставку та зберігає порядок повідомлень. Використовуйте це, якщо потрібно забезпечити доставку повідомлень у правильному порядку.
Оскільки порядок повідомлень не є пріоритетним у цьому випадку, ми використаємо стандартну чергу.
Панель керування чергами 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
.
У другому сервісі виконайте команду go run main.go
.
Другий сервіс буде слухати Amazon SQS.
Якщо є повідомлення, сервіс негайно споживає його. У повідомленні буде адреса електронної пошти користувача, який успішно зареєструвався. Після цього другий сервіс використовує цю електронну пошту як отримувача.
Натисніть на кінцеву точку localhost:3000/api/v1/user
.
Напишіть тіло запиту, як у цьому прикладі.
Тіло запиту містить ім'я користувача та електронну пошту.
Запустіть HTTP запит, і якщо він буде успішним, ви отримаєте відповідь, як на цьому зображенні.
Далі, перейдіть до вашого другого сервісу та спостерігайте за логами в терміналі.
Коли в Amazon SQS з'явиться повідомлення, сервіс одразу його споживає та виконує своє завдання, а саме — надсилає електронний лист.
Щоб переконатися, що електронний лист було надіслано, ми можемо перевірити поштову скриньку (для цього тестування ми використовуємо Mailtrap).
Класно!
Користувач успішно отримує привітальний електронний лист.
У консолі AWS ви також можете моніторити вашу чергу, перейшовши за цим посиланням: https://console.aws.amazon.com/sqs/. Перейдіть до однієї з ваших черг, а потім виберіть вкладку Моніторинг.
Моніторинг Amazon SQS
Додатково ви можете інтегрувати Amazon SQS з Amazon CloudWatch, щоб моніторити більш детальні метрики та активувати ведення логів для кращої видимості.
Дякую за прочитане ~~
Хочете зв'язатися?
https://www.linkedin.com/in/arasopraza/
https://github.com/arasopraza
Tweets by arsyopraza
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