Отказоустойчивая обработка 10m oauth токенов на tarantool /...
TRANSCRIPT
О чём мы будем рассказывать?Оглянемся назад: что было 3 года назад?
Какие проблемы были?
Master ⟷ Master репликация
8 / 67
О чём мы будем рассказывать?Оглянемся назад: что было 3 года назад?
Какие проблемы были?
Master ⟷ Master репликация
В поисках Ra�'а
9 / 67
О чём мы будем рассказывать?Оглянемся назад: что было 3 года назад?
Какие проблемы были?
Master ⟷ Master репликация
В поисках Ra�'а
Объединяем Ra� и шардинг
10 / 67
О чём мы будем рассказывать?Оглянемся назад: что было 3 года назад?
Какие проблемы были?
Master ⟷ Master репликация
В поисках Ra�'а
Объединяем Ra� и шардинг
Оцениваем результат11 / 67
Зачем?Сборщики почты
Вход внешней почтой
Хранение адресных книг
Выдача действующего access_token
12 / 67
Что такое OAuth токен?
{ "token_type" : "bearer", "access_token" : "XXXXXX", "refresh_token" : "YYYYYY", "expires_in" : 3600}
13 / 67
Что такое OAuth токен?
{ "token_type" : "bearer", "access_token" : "XXXXXX", "refresh_token" : "YYYYYY", "expires_in" : 3600}
15 / 67
Проблемы?25% Outage за 15 минут
50% Outage за 30 минут
100% Outage за 1 час
2015 г. - 100% CPU (много бизнес-логики и индексов)
Вторичная логика влияет на основную задачу18 / 67
M
M
M
M100
Datapro
Dataline
net.box
require 'net.box'
--[[ tarantool to tarantool connector]]
27 / 67
Ra� Leader Elec�on (on lua)local r = self.pool.call(self.FUNC.request_vote, self.term, self.uuid)self._vote_count = self:count_votes(r)
if self._vote_count > self._nodes_count / 2 then log.info("[raft-srv] node %d won elections", self.id) self:_set_state(self.S.LEADER) self:_set_leader({ id=self.id, uuid=self.uuid }) self._vote_count = 0 self:stop_election_timer() self:start_heartbeater()else log.info("[raft-srv] node %d lost elections", self.id) self:_set_state(self.S.IDLE) self:_set_leader(msgpack.NULL) self._vote_count = 0 self:start_election_timer()end
29 / 67
Ref
Ref
M
M
M
Ref
M100
Datapro
Dataline
Leader
Follower Follower
⅓
⅓
⅓
тольколидер
раздаётзадачи
x 1запросов
31 / 67
Ref
Ref
M
M
M
Ref
M100
Datapro
Dataline
Leader
Abandoned FollowerRa�
?
случился split
две ноды ok,одна оторвана
32 / 67
x = 1x = 1
x := 2 x := 3
x = 3 x = 2
x = 2 x = 3
M-Mреплицирует
все изменения
консистентность?
34 / 67
OAuth Token
Refresh-T
Access-T
∞*
1 hToken
Refresh( Refresh-T ) = Access-T1
Refresh( Refresh-T ) = Access-T2
...
:
:
35 / 67
R+A1
Leader Follower
replicate R+A1
splitR+A2 R+A3
split ends
R+A3 R+A2
R+A4 replicate R+A4
Abandoned
refresherработает ис leader и сabandoned
36 / 67
100% CPU Sharding!
Осталась ещё одна проблема
Кто знает что такое шардинг?
Кто делал свой шардинг?
42 / 67
to refresh no need to refreshexpired
60sfirst
order
old agesecondorder
4 minthirdorder
1 hour
expira�on �me index
Refresh
56 / 67
no�fy
put()
index
lookup or wait
waittake() session
stash
disconnect
channel
id status payload�me
pk
57 / 67
queue:putfunction put(data) local t = box.space.queue:auto_increment({ 'r', --[[ status ]] util.time(), --[[ time ]] data --[[ any payload ]] })
return tend
58 / 67
queue:takefunction take(timeout) local start_time = util.time() local q_ind = box.space.tokens.index.queue local _,t
while true do local it = util.iter(q_ind, {'r'}, { iterator = box.index.GE }) _,t = it() if t and t[F.tokens.status] ~= 't' then break end
local left = (start_time + timeout) - util.time() if left <= 0 then return end t = q:wait(left) if t then break end end t = q:taken(t) return tend
59 / 67
queue:takenfunction queue:taken(task) local sid = box.session.id() if self._consumers[sid] == nil then self._consumers[sid] = {} end local k = task[self.f_id] local t = self:set_status(k, 't')
self._consumers[sid][k] = { util.time(), box.session.peer(sid), t } self._taken[k] = sid return tend
60 / 67
queue:on_disconnectfunction on_disconnect() local sid = box.session.id local now = util.time()
if self._consumers[sid] then local consumers = self._consumers[sid] for k,rec in pairs(consumers) do time, peer, task = unpack(rec)
local v = box.space[self.space].index[self.index_primary]:get({k})
if v and v[self.f_status] == 't' then v = self:release(v[self.f_id]) end end self._consumers[sid] = nil endend
61 / 67
ИтогПроблема outage решена
Горизонтальное масштабирование
Проблема N2 сведена к N×const
Релизована логика на очереди под бизнес-задачу
64 / 67
tarantool.orgDocumenta�on:
try.tarantool.orgTry it online:
github.com/tarantoolExplore it:
Ques�ons?
67 / 67