Skip to content

Latest commit

 

History

History
274 lines (236 loc) · 19 KB

doc_ru.md

File metadata and controls

274 lines (236 loc) · 19 KB

Go-Vshsard Полная документация

Содержание

Цели и задачи библиотеки

Стандартная конфигурация кластера с шардированием происходит следующим образом:

  1. Устанавливается кластер шардов. Представим что это 2 репликасета(мастер реплика).
  2. Устанавливается прокси роутер на tarantool, на котором так же необходимо дописывать логику для походов в storage, который занимается тем что следит где какой бакет находится и ходить напрямую.

Тем самым мы избавляемся от дополнительной точки отказа, а так же уменьшаем число сетевых походов. Так же это позволяет адаптировать работу с шардами к комьюнити Golang. Увеличить поддержку, удобство отладки и производительность.

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

Теория

Tarantool

Tarantool — платформа in-memory вычислений с гибкой схемой данных для эффективного создания высоконагруженных приложений. Включает в себя базу данных и сервер приложений на Lua. Подробнее ознакомиться можно на официальном сайте Tarantool.

Шардирование

Подробнее про технологию виртуального шардирования а так же про библиотеку vhsard вы можете найти в https://www.youtube.com/watch?v=_9zUB0vmRxM А так же внутри оригинальной библиотеки vshard.

ETCD

etcd — это быстрая, надёжная и устойчивая к сбоям key-value база данных. В Tarantool etcd является основным источником конфигурации production решений. Подробнее об использовании etcd в качестве источника конфигурации вы можете ознакомиться в библиотеке moonlibs config для версий tarantool ниже 3 (где используется etcd v2) и в официальной документации для Tarantool 3+ (где используется etcd v3).

Начало работы с библиотекой

Подготовка окружения

Для работы с библиотекой вам понадобятся вам необходимо следующее окружение:

  • Go: любая из двух последних мажорных версий releases.
  • Сетевой доступ до шардированного кластера Tarantool.
  • Доступность источника топологии(источником топологии может быть etcd, файл, или другие).

Для локального запуска кластера:

  • Tarantool (библиотека проверена для версий 2.8+, документация написана поверх версии 2.11) в качетсве предустановленной программы на вашем ПК, в случае если вы собираетесь запускать кластер локально. Либо сетевое подключение до вашего кластера.
  • tt - для установки зависимостей.

Конфигурация и использование

В качетсве примера конфигурации и использования рассмотрим расширенный пример на основе README.

package main

import (
  "context"
  "fmt"
  "strconv"
  "time"

  "github.com/google/uuid"
  "github.com/tarantool/go-tarantool/v2"
  vshardrouter "github.com/tarantool/go-vshard-router/v2"
  "github.com/tarantool/go-vshard-router/v2/providers/static"
)

func main() {
  // Создаем фоновый контекст нашего сервиса контекст
  ctx := context.Background()

  // Создаем объект роутера. Он принимает 2 аргумента - контекст, а так же конфигурацию.
  directRouter, err := vshardrouter.NewRouter(ctx, vshardrouter.Config{
    // TopologyProvider - обязательный параметр.
    // Провайдер топологии является одним из основных атрибутов.
    // Существуют стандартные провайдеры топологии, описанные в README.md.
    // Однако никто не мешает вам создать свой собственный, соблюдая интерфейс.
    // В данном случае используется статический провайдер топологии,
    // он принимает топологию в захардкоженном виде.
    TopologyProvider: static.NewProvider(map[vshardrouter.ReplicasetInfo][]vshardrouter.InstanceInfo{
      // Название репликасета является идентификатором поэтому оно обязательно должно присуствовать.
      {Name: "replcaset_1", UUID: uuid.New()}: {
        // Название инстанса является идентификатором поэтому оно обязательно должно присуствовать.
        {Addr: "127.0.0.1:1001", Name: "1_1"},
        {Addr: "127.0.0.1:1002", Name: "1_2"},
      },
      {Name: "replcaset_2", UUID: uuid.New()}: {
        {Addr: "127.0.0.1:2001", Name: "2_1"},
        {Addr: "127.0.0.1:2002", Name: "2_2"},
      },
    }),
    // TotalBucketCount - обязательный параметр.
    // TotalBucketCount - указывает количество бакетов, которое было указано при бутстрапе кластера,
    // либо, которое необходимо для дальнейшего бутстрапа кластера.
    TotalBucketCount: 128000,
    // DiscoveryTimeout - не обязетальный параметр. По дефолту 1 мин.
    // Реиндексация расположения бакетов происходит фоновой горутиной.
    // Время между работой этой горутины по крону называется DiscoveryTimeout.
    DiscoveryTimeout: time.Minute,
    // DiscoveryWorkStep - не обязательный параметр. По дефолту 10 мс.
    // DiscoveryWorkStep это время интервала ожидания между запросами батча бакетов из репликасетов.
    DiscoveryWorkStep: time.Millisecond * 10,
    // DiscoveryMode - не обязательный параметр. По дефолту DiscoveryModeOn.
    // 	DiscoveryMode - тип дискаверинга(процесса резолва бакетов).
    //	Существуют типы DiscoveryModeOn, DiscoveryModeOnce.
    // DiscoveryModeOn - работает каждый промежуток DiscoveryTimeout.
    // DiscoveryModeOnce - дискаверит бакеты только при старте.
    DiscoveryMode: vshardrouter.DiscoveryModeOn,
    // PoolOpts - не обязательный параметр. Дефолтные настройки можно найти в go-tarantool.
    // PoolOpts - настройки пула подключения к репликасету.
    // Они задаются для всех репликасетов одновременно.
    PoolOpts: tarantool.Opts{
      Timeout: time.Second,
    },
    // Loggerf - не обязательный параметр. По дефолту используется empty logger, который не пишет логирование.
    // Loggerf - интерфейс которым вы можете обернуть свой логгер или предложить готовые обертки логгеров нам в PR.
    Loggerf: vshardrouter.StdoutLoggerf{LogLevel: vshardrouter.StdoutLogDebug},
    // Metrics - не обязательный параметр.  По дефолту используется EmptyMetrics, который не пишет метрик.
    // Metrics - интерфейс которым вы можете обернуть свою логику логирования в prometheus/graphite и другие системы.
    Metrics: &vshardrouter.EmptyMetrics{},
    // User - не обязательный параметр. Дефолтные настройки можно найти в go-tarantool pool.
    // User - юзернейм для подключения tarantool pool.
    User: "",
    // Password - не обязательный параметр. Дефолтные настройки можно найти в go-tarantool pool.
    // Password - пароль для подключения tarantool pool.
    Password: "",
    // BucketGetter - не обязательный параметр. По дефолту nil.
    // BucketGetter - функиця логики sugar для удобства использования.
    // Если вы не хотите задумываться на тему вычиления бакета при каждом запросе - вы можете написать middleware,
    // в которой по определенному ключу в контексте писать bucket id внутрь контекста.
    // Данная функция помогает sugar логики роутера понять bucket_id без вашего явного вызова.
    // Вы можете не задумываться на тему бакета, а например подготовливать bucket_id из user_id в запросе, а
    // в дальнейшем использовать роутер как go-tarantool pool.
    BucketGetter: func(ctx context.Context) uint64 {
      return 0
    },
    // RequestTimeout - не обязательный параметр. По дефолту 500ms.
    // RequestTimeout - таймаут вызова go-vshard.
    // Не стоит путать его с таймаутом вызова пула.
    // Таймаут вызова через go-vshard применяется на время переадресации бакета из 1го репликасета в другой
    // в случае миграции и других изменениях и проблем карты бакетов.
    RequestTimeout: time.Minute,
  })
  // Обрабатываем ошибку в случае неправильного создания роутера
  if err != nil {
    panic(err)
  }

  // В данном случае приведен пример структуры, которую мы будем отправлять в tarantool.
  // ID является ключом шардирования.
  user := struct{ ID uint64 }{ID: 123}

  // Вычисляем bucket_id из id пользователя.
  bucketID := vshardrouter.BucketIDStrCRC32(strconv.FormatUint(user.ID, 10), directRouter.RouterBucketCount())

  // Вызываем Balanced RO метод на получение некоторой информации.
  resp, err := directRouter.CallBRO(
    // Контекст необходим для обработки его закрытия и прекращения запроса.
    // А также для того чтобы использовать ваш обогащенный логер.
    ctx,
    // BucketID - идентификатор бакета, который дает роутеру понять куда направлять запрос.
    bucketID,
    // Наименовение функции, которую мы будем вызывать.
    "storage.api.get_user_info",
    // Аргументы, которые мы передаем в tarantool.
    []interface{}{&struct {
      BucketID uint64                 `msgpack:"bucket_id" json:"bucket_id,omitempty"`
      Body     map[string]interface{} `msgpack:"body"`
    }{
      BucketID: bucketID,
      Body: map[string]interface{}{
        "user_id": "123456",
      },
    }},
    // Таймаут обработки вызова go-vshard.
    vshardrouter.CallOpts{Timeout: time.Second * 2},
  )
  // Обрабатываем ошибку, если она произошла.
  if err != nil {
    panic(err)
  }

  // Подготавливаем структуру для ответа.
  info := &struct {
    BirthDay int
  }{}

  // Распаршиваем данные в нашу структуру. 
  // Важно чтобы были использованы указатели, поскольку только в таком случае декодер сможет распрасить данные.
  err = resp.GetTyped(&[]interface{}{info})
  // Обрабатываем ошибку, если она произошла.
  if err != nil {
    panic(err)
  }

  // Так же мы можем получить ответ в виде слайса интефрейсов, в котором будет лежать ответ.
  interfaceResult, err := resp.Get()
  // Обрабатываем ошибку, если она произошла.
  if err != nil {
    panic(err)
  }

  // Логирование правильных ответов.
  fmt.Printf("interface result: %v", interfaceResult)
  fmt.Printf("get typed result: %v", info)
}

Провайдеры топологии

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

В качестве источника топологии tarantool, вам доступны следующие:

  • etcd (для конфигурации основанной на moonlibs/config, подходит для tarantool версии ниже 3 и etcd v2)
  • static (для случая, когда вам необходимо что-то быстро протестировать и в ручную в коде забить информацию о топологии в вашем кластере. Выше в примере мы рассмавтривали именно его).
  • viper (дает широкие возможности использования любого источника топологии, даже тех, которые еще не поддержаны в самом tarantool. Так, любой источник конфигурации, который поддерживает viper вы можете использовать в качестве провайдера)
    • etcd v3
    • consul
    • files

Использование модулей go-tarantool

Мы стараемся максимально обеспечить совместимость с интерфейсами go-tarantool там, где это необходимо. В данном разделе мы расмотрим полезные примеры использования модулей go-tarantool, которые позволяет сделать нам совместимость интерфейсов.

Box

Модуль go-tarantool, позволяющий получать доступ к builtin методам Tarantool, не описывая интерфейсов самому.

Проверка состояния кластера.

// Проверим что всем мастера всех репликасетов находятся в состоянии RO=false.
// Проходимся по всем репликасетам внутри кластера.
for _, rs := range router.RouteAll() {
	// Поскольку модуль box рабоатет в рамках подключения к 1му инстансу,
	// мы можем использовать адаптер, чтобы указать пулу использовать 1 инстанс репликасета в RW.
	// В этом поможет нам адаптер go-tarantool.
	adapter := pool.NewConnectorAdapter(rs.Pooler(), pool.RW)
	// Создадим экземпляр box из go-tarantool.
	b := box.New(adapter)
	
	// Получим информацию из нашего инстанса.
	info, err := b.Info()
	if err != nil { 
		panic(err)
	}
	
	// Проверим, что мастер действительно находится в состоянии RO=false.
	if info.RO == false {
		panic("master non master 0_0")
	}
}