NOX73 / embry

Demonstation distributed cache system

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Распределенный кеш приложения

Задание

Необходимо реализовать package для распределённого кеша приложения. Интерфейс: middleware с передачей анонимной функции для получения данных:

func Get(key string, result interface{}, executionLimit, expire time.Duration, getter func()) (error)

Данные представляют собой нормально сериализуемые json структуры. Сложность в том, чтобы в нормальных условиях гарантировать уникальность вызова функции в распределённой системе в пределах expire (т.е. все прочие вызовы должны запросить кеш).

Реализация

Использован банальный memcahed для хранения кеша + схема лока для гарантирования уникальности вычисления значения ключа.

Лок реализован на атомарной оперции add из memcached.

Демонстрационная инсталяция состоит из 3ех memcached серверов и клиента, который эмулирует конкурентный доступ к ним.

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

Минусы

  • библиотека клиент gomemcache использует для распределение ключей по кластеру модуль от хеша ключа, поэтому будет сложно добавить в кластер новые ноды. Решение: поискать или написать клиент который использует алгоритм consistent hashing.
  • executionLimit учитывает только случай с непопаданием в кеш, она не учитывает случай когда getter Будет выполняться долго. Решение: завернуть в горутину.
  • не делались никакие оптимизации кода клиента (аллокации памяти и прочее)
  • не учитывается распределение запросов к ключам. Решение: Теоретически схема с consisstent hashing позволит лучше решать эту проблему разбиением горячх участков хеш таблицы на разные ноды.
  • не реализована fault tolerance. Решение: все что нужно для него сделать - трекать сломанные ноды и убирать их из списка серверов, их часть таблицы подхватят другие ноды.
  • не измерял скорость ответа и пропускную способность, бенчмарки тоже не делал, поскольку клиентского кода минимум и все упирается в производительность memcached (котороый ну ооочень быстрый).
  • все хранится в памяти. Но для создания производительного решения этот вариант лучший.
  • Полинг memcache если не удалось захватить лок на запись. Решение: поставить таймауты между запросами, либо переделать лок на что-то с pub-sub, redis например.
  • нет тестов и код местами не очень.

Плюсы

  • Нет единой точки отказа
  • Хорошая масштабируемость
  • Производительность ограничена производительность одной ноды с memcache (если не брать в расчет сеть)
  • Просто лучше чем сложно :)

Запустить

понадобится:

запустить:

fig up

настройки:

в main.go можно поменять несколько констант, кажется все интуитивно понятно:

const (
	MaxExecutionTime = time.Minute
	ExpireKeyTime    = 10 * time.Second
	WorkersCount     = 10
  // for factorial calculation
	MaxNum           = 100010
	MinNum           = 100000
)

отключен сторинг значения факториала в memcache (слишком большое число :)), иначе все ресурсы трятяться на перегон данных. Можно включить так:

type Result struct {
	Num int `json:"num"`
	Value *big.Int `json:"value"`
}

демо

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

About

Demonstation distributed cache system


Languages

Language:Go 100.0%