VShard - горизонтальное масштабирование в Tarantool

Шпилевой Владислав

Tarantool

План доклада

  1. Зачем?
  2. Shard
  3. VShard
  4. Использование
  5. Ребалансировка
  6. Прокси
  7. Auto read failover
  8. Write failover
  9. Мониторинг

Зачем масштабировать?

Место

Вычисления

Горизонтальное масштабирование

Репликация

ABCD

ABCD

ABCD

ABCD

Горизонтальное масштабирование

Шардинг

A

B

C

D

Шардинг

Range

0

1900

1970

2018

2001

1895

1965

SELECT * FROM movie WHERE year > 1950;

Шардинг

Hash

Lord of The Rings

The Arrival of a Train

Операция Ы

SELECT * FROM movie WHERE name = "Lord of The Rings";

Tarantool Shard

function shard_function(primary_key)
    return guava(crc32(primary_key))
end
            
            

Первый шардинг в Tarantool

Request

old hash

new hash

Нет локальности

Медленный решардинг

Нестабильные чтения

SELECT

master

Tarantool Shard

format = {{'id', 'unsigned'},
          {'email', 'string'}}
box.schema.create_space('customer', {format = format})

format = {{'id', 'unsigned'},
          {'customer_id', 'unsigned'},
          {'balance', 'number'}}
box.schema.create_space('account', {format = format})
            
            
user {100, 'foo@mail.ru'}
account {1, 100, 123}

100 != 1 → разные хеши → разные узлы

Tarantool VShard

Buckets

Replicaset

Data       →       Bucket              Storage

User defined map

Internal map

format = {{'id', 'unsigned'},
          {'email', 'string'},
          {'bucket_id', 'unsigned'}}
box.schema.create_space('customer', {format = format})

format = {{'id', 'unsigned'},
          {'customer_id', 'unsigned'},
          {'balance', 'number'},
          {'bucket_id', 'unsigned'}}
box.schema.create_space('account', {format = format})

Локальность по bucket_id

Связка данных

user { 100, 'bar@mail.ru', 5 }

account {1, 100, 123, 5 }

Использование

5

Можно еще раз? Что это дает?

Связка данных

Использование

customer {1, 'bar@mail.ru'}

account {1, 1, 100}

account {2, 1, 200}

account {3, 1, 300}

SELECT * FROM accounts WHERE customer_id = 1;

3 запроса

customer {1, 'bar@mail.ru', 5}

account {1, 1, 100, 5}

account {2, 1, 200, 5}

account {3, 1, 300, 5}

1 запрос

...

...

5

Shard

VShard

Использование

function create_user(email)
    local customer_id = next_id()
    local bucket_id = crc32(customer_id)
    box.space.customer:insert(customer_id, email, bucket_id)
end

function add_account(customer_id)
    local id = next_id()
    local bucket_id = crc32(customer_id)
    box.space.account:insert(id, customer_id, 0, bucket_id)
end

Как масштабировать?

Использование

#

= Const

Реконфигурация

vshard.storage.cfg(new_config)

Failover

Rebalancer

Zookeeper

new_cfg.sharding[new_uuid] = {
    uuid = new_uuid,
    replicas = {
        {
            name = new_replica1,
            uri = 'example.com:113',
            uuid = replica1_uuid,
            master = true,
        },
        {
            name = new_replica2,
            uri = 'example.com:114',
            uuid = replica2_uuid,
        }
    }
}

vshard.storage.cfg(new_cfg)

Ребалансировка

  • вычислить баланс
  • построить маршруты бакетов
  • отправить маршруты

Routes

Routes

vshard.storage.info()

100

200

#

= 1000

#

= 2000

new_cfg.sharding[uuid1].weight = 100
new_cfg.sharding[uuid2].weight = 200
vshard.storage.cfg(new_cfg)
            

Data

Ребалансировка

Read

Write

Сеть

Read

Write

Read

Как не блокировать запись?

Write

Bucket Pin

box.begin()
vshard.storage.bucket_pin(10)
vshard.storage.bucket_pin(11)
box.commit()
--
-- Do anything with these buckets.
--
box.begin()
vshard.storage.bucket_unpin(10)
vshard.storage.bucket_unpin(11)
box.commit()

Replicaset Lock

new_cfg.sharding[uuid].lock = true
vshard.storage.cfg(new_cfg)

Что осталось?

  • Нет локальности
  • Решардинг замедляет все
  • Нестабильные чтения

?

Прокси

bucket_id  storage

vshard.router

Прокси

r = vshard.router
accounts = r.call(bucket_id,
                  'get_accounts',
                  {customer_id})
function get_accounts(customer_id)
    local customer =
        box.space.accounts.index.customer
    return customer:select({customer_id})
end

Routing

?

Развернуть

функцию на

стораджах

Auto read failover

Write

Read

Зона 1

Зона 2

Зона ...

Зона K - 1

Зона K

Зона N

Зона 1 Зона 2 ... Зона K
Зона 1 w(1, 1) w(1, 2) w(1, i) w(1, K)
Зона 2 w(2, 1) w(2, 2) w(2, i) w(2, K)
... w(j, 1) w(j, 2) w(j, i) w(j, K)
Зона K w(K, 1) w(K, 2) w(K, i) w(K, K)

Auto read failover

new_cfg.weights = {
    [1] = {
        [1] = 0,
        [2] = 100,
        [3] = 200,
    },
    [2] = {
        [1] = 300,
        [2] = 0,
        [3] = 400,
    },
    [3] = {
        [1] = 500,
        [2] = 600,
        [3] = 0,
    }
}
new_cfg.zone = 1
vshard.router.cfg(new_cfg)

Зона 1

Зона 2

Зона 3

100

200

300

400

500

600

Write failover

replicas = new_cfg.sharding[uud].replicas
replicas[old_master_uuid].master = false
replicas[new_master_uuid].master = true
vshard.storage.cfg(new_cfg)

Read

Write

Be Master

Write

Write

Sync

Read

Write

Мониторинг

vshard.storage.info()
---
- replicasets:
    <replicaset_2>:
      uuid: <replicaset_2>
      master:
        uri: storage@127.0.0.1:3303
    <replicaset_1>:
      uuid: <replicaset_1>
      master: missing
  bucket:
    receiving: 0
    active: 0
    total: 0
    garbage: 0
    pinned: 0
    sending: 0
  status: 2
  replication:
    status: slave
  alerts:
  - ['MISSING_MASTER', 'Master is not configured for '
                       'replicaset <replicaset_1>']
vshard.storage.buckets_info()

Мониторинг

vshard.router.info()
---
- replicasets:
    <replicaset_2>:
      replica: &0
        status: available
        uri: storage@127.0.0.1:3303
        uuid: 1e02ae8a-afc0-4e91-ba34-843a356b8ed7
      bucket:
        available_rw: 500
      uuid: <replicaset_2>
      master: *0
    <replicaset_1>:
      replica: &1
        status: available
        uri: storage@127.0.0.1:3301
        uuid: 8a274925-a26d-47fc-9e1b-af88ce939412
      bucket:
        available_rw: 400
      uuid: <replicaset_1>
      master: *1
  bucket:
    unreachable: 0
    available_ro: 800
    unknown: 200
    available_rw: 700
  status: 1
  alerts:
  - ['UNKNOWN_BUCKETS', '200 buckets are not discovered']

Итоги

... локальность данных,

... гранулярный решардинг,

... auto read failover