Подтвердить что ты не робот

Генерация распределенного порядкового номера?

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

например. Использование типа Postgres SERIAL http://www.neilconway.org/docs/sequences/

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

4b9b3361

Ответ 1

ОК, это очень старый вопрос, который я сейчас вижу.

Вам нужно будет различать порядковые номера и уникальные идентификаторы, которые (необязательно) сортируются по определенным критериям (обычно время генерации). Истинные порядковые номера подразумевают знание того, что сделали все остальные работники, и как таковые требуют совместного состояния. Нет простого способа сделать это распределенным, широкомасштабным образом. Вы можете посмотреть такие вещи, как сетевые трансляции, диапазоны окон для каждого рабочего и распределенные хеш-таблицы для уникальных идентификаторов работников, но это большая работа.

Уникальные идентификаторы - это еще одно дело, существует несколько хороших способов генерации уникальных идентификаторов децентрализованным образом:

a) Вы можете использовать сервисную службу Twitter Snowflake ID. Снежинка:

  • Сетевое обслуживание, т.е. вы делаете сетевой вызов для получения уникального идентификатора;
  • который создает 64-битные уникальные идентификаторы, упорядоченные по времени генерации;
  • и сервис очень масштабируемый и (потенциально) высокодоступный; каждый экземпляр может генерировать много тысяч идентификаторов в секунду, и вы можете запускать несколько экземпляров в своей LAN/WAN;
  • записанный в Scala, работает на JVM.

b) Вы можете генерировать уникальные идентификаторы на самих клиентах, используя метод , полученный из использовать UUID/GUID.

Ответ 2

У каждого node есть уникальный идентификатор (который может быть как угодно), а затем добавьте его к порядковому номеру.

Например, node 1 генерирует последовательность 001-00001 001-00002 001-00003 и т.д., а node 5 генерирует 005-00001 005-00002

Уникальный: -)

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

Ответ 3

Теперь есть больше вариантов.

Этот вопрос "старый", я попал сюда, поэтому я думаю, что было бы полезно оставить варианты, о которых я знаю (пока):

  • Вы можете попробовать Hazelcast. В нем версия 1.9 включает в себя распределенную реализацию java.util.concurrent.AtomicLong
  • Вы также можете использовать Zookeeper. Он предоставляет методы для создания узлов последовательности (добавляется к именам znode, я предпочитаю использовать номера версий узлов). Будьте осторожны с этим: если вы не хотите пропущенных номеров в вашей последовательности, это может быть не то, что вы хотите.

Приветствия

Ответ 4

Это можно сделать с помощью Redisson. Он реализует распределенную и масштабируемую версию AtomicLong. Вот пример:

Config config = new Config();
config.addAddress("some.server.com:8291");

Redisson redisson = Redisson.create(config);
RAtomicLong atomicLong = redisson.getAtomicLong("anyAtomicLong");
atomicLong.incrementAndGet();

Ответ 5

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

Распределенные системы полагаются на множество небольших взаимодействующих сервисов, и для этой простой задачи вам действительно нужно или вы действительно выиграете от какого-либо другого сложного распределенного решения?

Ответ 6

Существует несколько стратегий; но ничто из того, что я знаю, не может быть действительно распространено и дать реальную последовательность.

  • имеют центральный генератор чисел. он не должен быть большой базой данных. memcached имеет быстрый атомный счетчик, в подавляющем большинстве случаев он достаточно быстрый для всего вашего кластера.
  • разделите целочисленный диапазон для каждого node (например, ответ Стивена Шланнтера)
  • использовать случайные числа или UUID
  • используйте часть данных вместе с идентификатором node и хешем все (или hmac it)

лично, я склоняюсь к UUID или memcached, если я хочу иметь в основном непрерывное пространство.

Ответ 7

Почему бы не использовать генератор UUID (потокобезопасный)?

Я должен, вероятно, расширить это.

UUID гарантированно уникальны во всем мире (если вы избегаете тех, которые основаны на случайных числах, где уникальность просто высока).

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

Ваше "потокобезопасное" требование может быть выполнено, выбирая генераторы UUID с "безопасным потоком".

Предполагается, что ваше требование "порядкового номера" удовлетворяется гарантированной глобальной уникальностью каждого UUID.

Обратите внимание, что многие версии последовательности номеров базы данных (например, Oracle) не гарантируют монотонного увеличения или (даже) увеличения порядковых номеров (по принципу "соединение" ). Это связано с тем, что последовательная партия номеров последовательностей распределяется в "кэшированных" блоках по каждому соединению. Это гарантирует глобальную уникальность и обеспечивает достаточную скорость. Но порядковые номера, фактически выделенные (со временем), могут быть перепутаны, когда они распределяются несколькими соединениями!

Ответ 8

Я знаю, что это старый вопрос, но мы также столкнулись с такой же потребностью и не смогли найти решение, которое удовлетворяет наши потребности. Нашим требованием было получить уникальную последовательность (0,1,2,3... n) идентификаторов и, следовательно, снежинка не помогла. Мы создали нашу собственную систему для генерации идентификаторов с помощью Redis. Redis является однопоточным, поэтому его механизм списка/очереди всегда будет давать нам 1 всплывающее окно за раз.

Мы создаем буфер идентификаторов. Изначально в очереди будет от 0 до 20 идентификаторов, которые готовы к отправке по запросу. Несколько клиентов могут запросить идентификатор, и redis будет выдавать по 1 идентификатору за раз. После каждого щелчка слева мы вставляем BUFFER + currentId справа, который поддерживает работу списка буферов. Реализация здесь

Ответ 9

Генерация распределенных идентификаторов может быть заархивирована с помощью Redis и Lua. Реализация доступна в Github. Он создает распределенные и k-сортируемые уникальные идентификаторы.

Ответ 10

Я написал простую службу, которая может генерировать полу-уникальные несекретные 64-битные номера. Он может быть развернут на нескольких машинах для резервирования и масштабируемости. Он использует ZeroMQ для обмена сообщениями. Для получения дополнительной информации о том, как это работает, посмотрите страницу github: zUID

Ответ 11

Используя базу данных, вы можете достичь 1.000+ приращений в секунду с помощью одного ядра. Это довольно легко. Вы можете использовать свою собственную базу данных в качестве бэкэнд для создания этого числа (как и должно быть его собственное агрегирование в терминах DDD).

У меня возникла аналогичная проблема. У меня было несколько разделов, и я хотел получить счетчик смещения для каждого из них. Я реализовал что-то вроде этого:

CREATE DATABASE example;
USE example;
CREATE TABLE offsets (partition INTEGER, offset LONG, PRIMARY KEY (partition));
INSERT offsets VALUES (1,0);

Затем выполняется следующее утверждение:

SELECT @offset := offset from offsets WHERE partition=1 FOR UPDATE;
UPDATE offsets set [email protected]+1 WHERE partition=1;

Если ваше приложение позволяет вам, вы можете выделить блок сразу (это был мой случай).

SELECT @offset := offset from offsets WHERE partition=1 FOR UPDATE;
UPDATE offsets set [email protected]+100 WHERE partition=1;

Если вам нужна дополнительная пропускная способность, вы не можете заранее назначить смещения, вы можете реализовать свою собственную услугу, используя Flink для обработки в реальном времени. Я смог получить около 100 тыс. Приращений для каждого раздела.

Надеюсь, что это поможет!

Ответ 12

Проблема аналогична: В мире iscsi, где каждый LUNS/тома должны быть однозначно идентифицированы инициаторами, запущенными на стороне клиента. В стандарте iscsi говорится, что первые несколько бит должны представлять информацию поставщика/производителя хранилища, а остальные монотонно увеличиваются.

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

Ответ 13

Одним из приемлемых решений является использование долгого поколения. Это можно сделать с помощью распределенной базы данных.