Как эффективно создать упорядоченную последовательность в Spanner?

Google Spanner рекомендует не использовать такие вещи, как отметки времени или последовательные числа в качестве начальной части первичного ключа или индекса, что имеет смысл на основе архитектуры. Однако для моих требований мне нужен какой-то способ обеспечения строгого "только добавления" порядка строк.

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

Наивно это было бы смоделировано как:

| Category    | STRING       |
| Stream Id   | STRING       |
| Sequence Nr | INT64        |

(С первичным ключом, состоящим из Category, Stream Id, Sequence Nr.) Это обеспечит строгий порядок событий для одного потока. Теперь, когда с некоторыми категориями связано много событий, и у лучших советов Spanner есть разница в старших битах, было бы лучше перевернуть это. Каждый "поток" будет содержать достаточно небольшое количество событий (тысячи, а не миллионов) и будет считываться вместе, чтобы облегчить лучшее распределение данных и обеспечить локальность для событий, принадлежащих одному потоку:

| Stream Id   | STRING       |
| Category    | STRING       |
| Sequence Nr | INT64        |

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

| Aggregate Id | STRING      |                         | 
| Category     | STRING      |                         |
| Timestamp    | TIMESTAMP   | allow_commit_timestamp  |

В Spanner встроена временная метка коммита, которая помечает ее во время фактической обработки транзакции. Но к вопросу наконец:

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

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

В документации говорится, что "значения отметок времени фиксации не гарантируются как уникальные. Транзакции, которые записывают в непересекающиеся наборы полей, могут иметь одинаковую метку времени. Транзакции, которые записывают в перекрывающиеся наборы полей, имеют уникальные метки времени". - но я не совсем понимаю, что представляет собой "наборы полей" в этом контексте.

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

1 ответ

Решение

Если у вас есть несколько событий в одной транзакции, то все они будут иметь одну и ту же временную метку.

Поле - это ячейка таблицы (одно значение столбца в одной строке). Таким образом, "неперекрывающиеся наборы полей" в этом контексте в основном означают отдельные строки, потому что одно из полей - это отметка времени фиксации!

Две независимые транзакции, одна обновляющая строка "R1" и одна обновляющая строка "R2" в одной и той же таблице, теоретически могут иметь одну и ту же метку времени фиксации, поскольку они не перекрываются.

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

В приведенном вами примере, где вы используете отметку времени коммита в своем первичном ключе, тогда нет, вы не сможете добавить несколько событий к одной и той же паре stream_id/category в одной транзакции, так как они будут иметь одну и ту же метку времени - и следовательно, тот же первичный ключ.

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

Если вы использовали комбинацию метки времени фиксации и sequence_number для каждого кортежа (stream_id, category, timestamp), то вы можете сохранить строгий порядок в одной транзакции:

Увеличьте порядковый номер, начиная с 0, для каждой пары (stream_id, category) в одной и той же транзакции. Временная метка фиксации будет обеспечивать порядок для разных транзакций, а порядковый номер будет обеспечивать порядок внутри транзакции...

Другие вопросы по тегам