Требование
В настоящее время я создаю систему разрешений.Одним из требований является его горизонтальное масштабирование.
Для достижения этой цели мы сделали следующее:
Существует одна таблица "разрешения скомпилированного ресурса", которая выглядит примерно так:
| user_id | resource_id | reason |
| 1 | 1 | 1 |
| 1 | 2 | 3 |
| 2 | 1 | 2 |
Структура этой таблицы обозначает пользователь 1 имеет доступ к ресурсу 1 & 2 , а пользователь 2 имеет доступ только к ресурсу 1 .
Столбец «причина» - это побитовое число, в котором биты включены, в зависимости от того, «почему» они имеют такое разрешение.Двоичный бит «1» означает, что они являются администратором, а двоичный бит «2» означает, что они создали ресурс.
Таким образом, пользователь 1 имеет доступ к ресурсу 1, поскольку он является администратором.У него есть доступ к ресурсу 2, потому что он администратор, и он создал этот ресурс.Если бы он больше не был администратором, у него все равно был бы доступ к билету 2, но не к билету 1.
Чтобы выяснить, что нужно добавить в эту таблицу, мы используем класс «patcher», который программно обходит пользователейи ресурсы, переданные ему, и логически просматривает все таблицы БД, необходимые для определения того, какие строки необходимо добавить и какие строки необходимо удалить из таблицы.
Как мы пытаемся масштабировать и проблема
Чтобы по горизонтали масштабировать это, мы разделяем логику на куски и даем ее нескольким «работникам» в асинхронной очереди
Кажется, что это масштабируется только до того, как больше не ускоряетсяили иногда даже происходит блокировка строки, что замедляет ее.
Существует ли какой-то особый тип блокировки строки, который мы можем использовать, чтобы позволить ему масштабироваться бесконечно?
Мы подходим к этому с совершенно неправильной точки зрения?У нас есть много «Причин» и много сложной логики разрешений, которые нам нужны, чтобы иметь возможность достаточно быстро перекомпилировать
Запросы SQL, которые выполняются одновременно, для справки
Когда мы «добавляем» причины:
INSERT INTO `compiled_permissions` (`user_id`, `resource_id`, `reason`) VALUES ((1,1,1), (1,2,3), (2,1,2)) ON DUPLICATE KEY UPDATE `reason` = `reason` | VALUES(`reason`);
Когда мы «удаляем» причины:
UPDATE `compiled_permissions` SET `reason` = `reason` & ~ (CASE
(user_id = 1 AND resource_id = 1 THEN 2 ... CASE FOR EVERY "REASON REMOVAL")
ELSE `reason`
END)
WHERE (`user_id`, `resource_id`) IN ((1,1),(1,2) .. ETC )