Статьи

Микросервисные сообщения: событие, которое изменило все

Неизвестное событие

В управляемых событиями микросервисных архитектурах сообщение обычно несет смысл только для производителя события и конечного потребителя (ей). Любое общее промежуточное программное обеспечение, брокер, шлюз или кэш не могут воздействовать на контент, потому что они этого не понимают.

Какая трата возможностей.

Но что, если сообщение о событии можно понять?

Что, если универсальное промежуточное программное обеспечение микросервиса может интерпретировать его для обновления базы данных, или кэш может использовать его для обновления самого себя, или клиент может автоматически обновлять свое собственное состояние?

В этой статье будет показан полный пример, написанный на Go, но он применим к любому другому языку, демонстрирующий силу, которую вы получаете от использования сообщений с определенным значением и целью; как одно событие может изменить все.

В примере будут использованы следующие части:

  • Протокол RES — простой протокол на основе JSON, который определяет сообщения о событиях для общих мутаций данных.
  • Сервер NATS — брокер сообщений, ориентированный на простоту и производительность.
  • Resgate — шлюз API реального времени, построенный на протоколе RES.
  • go-res — пакет Go для написания сервисов с использованием протокола RES.
  • BadgerDB — встраиваемая, быстрая база данных значений ключей для Go.

Пример основан на примере редактирования текста из пакета go-res . Страница примера на GitHub содержит инструкции по его запуску.

Объем примера

Протокол RES определяет, что такое ресурс, и как его представить в JSON. В этом примере мы будем служить очень простой ресурс:

ПОЛУЧИТЬ: /api/example/greeting

{ "message": "Hello, World!" }

Кроме того, мы добавим метод для обновления ресурса:

ПОСЛЕ: /api/example/greeting/set

Тело:

{ "message": "Hello, Resgate.io!" }

Наконец, все изменения должны быть сохранены в базе данных — BadgerDB в этом примере.

Синхронизация клиентов в режиме реального времени и самообновляющийся кеш — это дополнительные бонусы, которые мы получаем от Resgate.

Код

Вот как выглядит весь сервис:

package main

import (
	"log"

	"github.com/dgraph-io/badger"
	res "github.com/jirenius/go-res"
	"github.com/jirenius/go-res/middleware"
)

type Greeting struct {
	Message string `json:"message"`
}

func main() {
	opts := badger.DefaultOptions
	opts.Dir = "./db"
	opts.ValueDir = "./db"
	opts.Truncate = true
	db, err := badger.Open(opts)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	s := res.NewService("example")
	s.Handle("greeting",
		res.Model,
		res.Access(res.AccessGranted),
		middleware.BadgerDB{
			DB:      db,
			Type:    Greeting{},
			Default: Greeting{"Hello, World!"},
		},
		res.Set(func(r res.CallRequest) {
			var p Greeting
			r.ParseParams(&p)
			r.ChangeEvent(map[string]interface{}{
				"message": p.Message,
			})
			r.OK(nil)
		}),
	)

	s.ListenAndServe("nats://localhost:4222")
}

Давайте разберемся с этим.

Объясняя Сервис

Мы определяем нашу модель данных; простой объект JSON с одним свойством:

type Greeting struct {
    Message string `json:"message"`
}

Затем несколько котлов для создания базы данных BadgerDB:

opts := badger.DefaultOptions
opts.Dir = "./db"
opts.ValueDir = "./db"
opts.Truncate = true // For Windows users
db, err := badger.Open(opts)
if err != nil {
	log.Fatal(err)
}
defer db.Close()

После этого настало время создать экземпляр службы. Мы даем ему пространство имен "example":

s := res.NewService("example")

Затем мы добавляем ресурс в сервис, который называется "greeting"(путь URL будет /api/example/greeting). Чтобы помочь промежуточному программному обеспечению, мы указываем, что это Модель (объект JSON), и что любой должен иметь к ней доступ:

s.Handle("greeting",
	res.Model,
	res.Access(res.AccessGranted),
	/* ... */
)

Затем мы добавляем наше промежуточное ПО BadgerDB. Промежуточное программное обеспечение будет делать две вещи:

  • Обслуживать ресурс из базы данных (или использовать, Defaultесли не найден).
  • Обновите сохраненные данные о любом событии.
middleware.BadgerDB{
	DB:      db,
	Type:    Greeting{},
	Default: Greeting{"Hello, World!"},
},

Мы также добавили обработчик для вызова setметода. При обработке запроса мы проанализируем предоставленное тело JSON, чтобы получить новое приветственное сообщение, и, прежде чем ответить OKна запрос, мы отправим… СОБЫТИЕ

res.Set(func(r res.CallRequest) {
	var p Greeting
	r.ParseParams(&p)
	r.ChangeEvent(map[string]interface{}{
		"message": p.Message,
	})
	r.OK(nil)
}),

Наконец, мы говорим ему подключиться к серверу NATS и начать обслуживание ресурса через Resgate:

s.ListenAndServe("nats://localhost:4222")

Событие изменения

Сообщение о событии, которое все понимают

Этого мало ChangeEventдостаточно. Любая технология, знакомая с протоколом RES, будет знать, что это значит и как использовать его для обновления состояния ресурса. Это приведет к следующему:

  • Промежуточное программное обеспечение BadgerDB обновит сохраненные данные.
  • Шлюз API, Resgate, обновит свой кеш, используя только событие.
  • Все клиенты, подключенные к Resgate через WebSocket и подписанные на ресурс, автоматически обновят свое внутреннее состояние (и, надеюсь, их реактивные представления).

Все это с простым событием — не нужно никакого дополнительного кода.

Заключение

Используя протокол, который определяет, как представлять данные, вместе с заранее определенными событиями, используемыми для их изменения, мы можем значительно сократить объем кода, необходимый для обслуживания и обновления этих данных.

Нет необходимости в пользовательском коде для чтения и хранения данных в базе данных. Нет необходимости отправлять события в отдельный поток для обновления клиента. Нет необходимости в коде на стороне клиента для интерпретации события и обновления состояния.

Кроме того, мы можем получить такие преимущества, как повышение эффективности кэширования, плавное обновление состояния клиента и упрощение масштабирования с помощью общих синхронизаций между репликами микросервисов.

Посетите resgate.io для получения дополнительной информации о протоколе RES, Resgate и связанных ресурсах, включая демонстрационные версии результирующего API в реальном времени.


Примечание: Go Gopher был разработан Рене Френч .