Создание новой таблицы с помощью cqlsh в существующем пространстве ключей: несоответствие идентификатора семейства столбцов

Хьюстон, у нас есть проблема.

Попытка создать новую таблицу с cqlsh в существующем ключевом пространстве Cassandra (v2.1.3) приведет к:

ServerError: 
<ErrorMessage code=0000 [Server error] message="java.lang.RuntimeException:
java.util.concurrent.ExecutionException: 
    java.lang.RuntimeException:      
        org.apache.cassandra.exceptions.ConfigurationException: Column family ID mismatch (found e8c03790-c952-11e4-a753-5981ea73cd7c; expected e8b14370-c952-11e4-a844-8f10bfb9c386)">

После первой попытки создания попытка повторного запуска приведет к:

AlreadyExists: таблица "ks.metrics" уже существует

Но получение списка существующих таблиц для пространства ключей desc tables; не будет сообщать о новой таблице.

Проблема связана с Cassandra-8387, за исключением того, что только один клиент пытается создать таблицу: cqlsh

У нас есть куча Spark-заданий, которые будут создавать кластеры и таблицы при запуске, что может сделать это параллельно. Это приведет к повреждению ключа?

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

Любые идеи?

UPDATE

Обнаружено обходное решение: выполните ремонт в ключевом пространстве, и появятся таблицы (desc tables).

Ответы

Ответ 1

Короткий ответ: У них есть условие гонки, которое, по их мнению, разрешено в 1.1.8...


Длинный ответ:

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

Ниже у меня есть копия трассировки стека из моей установки Cassandra 3.7. Хотя ваша версия была 2.1.3, я был бы удивлен, что эта часть кода сильно изменилась.

Как мы видим, исключение происходит в функции validateCompatibility(). Это требует, чтобы новые и старые версии MetaData были равны:

  • ksName (имя ключа)
  • cfName (имя столбца)
  • cfId (columnfamily UUID)
  • flags (isSuper, isCounter, isDense, isCompound)
  • компаратор (ключ сортировка компаратор)

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

Подняв стек, у нас есть apply(), который вызывает validateCompatibility() сразу.

Далее мы имеем updateTable(). Точно так же он вызывает apply() почти сразу. Сначала он вызывает getCFMetaData() для извлечения текущих данных семейства столбцов ( "старый" ), которые будут сопоставлены с новыми данными.

Далее мы видим updateKeyspace(). Эта функция вычисляет a diff, чтобы узнать, что изменилось. Затем он сохраняет это в каждом типе данных. Таблица 2-го после Тип...

До этого у них есть mergeSchema(), который вычисляет то, что изменилось на уровне Keyspace. Затем он удаляет пространства ключей, которые были удалены, и генерирует новые временные пространства для тех, которые были обновлены (и для новых областей ключей). Наконец, они перебирают новые области ключей, вызывающие updateKeyspace() для каждого из них.

Далее в стеке мы видим интересную функцию: mergeSchemaAndAnnounceVersion(). Этот будет обновлять версию после того, как области ключей были обновлены в памяти и на диске. Версия схемы включает в себя cfId, которая несовместима и, таким образом, генерирует исключение. Часть Announce должна отправить сообщение сплетни другим узлам о том, что этот node теперь знает о новой версии определенной схемы.

Далее мы видим нечто, называемое MigrationTask. Это сообщение, используемое для переноса изменений между узлами Cassandra. Полезная нагрузка сообщения представляет собой набор мутаций (которые обрабатываются функцией mergeSchema().)

Остальная часть стека показывает только функции run(), которые представляют собой различные типы функций, используемых для обработки сообщений.

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

Итак, давайте посмотрим на код, отправляющий сообщение, в первую очередь, вы видите его в MigrationManager. Здесь у нас есть параметр MIGRATION_DELAY_IN_MS, связанный со старой проблемой, Schema push/pull race, которая заключалась в том, чтобы избежать состояния гонки. Ну... вот ты. Поэтому они знают, что есть возможное состояние гонки и пытаться избежать этого, они добавили немного задержки там. Одна часть этого исправления включает проверку версии. Если версии уже равны, вообще избегайте обновления (т.е. Игнорируйте эту сплетню).

if (Schema.instance.getVersion().equals(currentVersion))
{
    logger.debug("not submitting migration task for {} because our versions match", endpoint);
    return;
}

Задержка, о которой мы говорим, составляет одну минуту:

public static final int MIGRATION_DELAY_IN_MS = 60000;

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

Дело в том, что их код не ожидает, что несколько изменений происходят один за другим, включая большие задержки, как у меня. Поэтому, если бы я должен был создать один стол, а затем делать другие вещи, я был бы в порядке. С другой стороны, когда я хочу создать 20 таблиц подряд на этих медленных машинах, сообщение о сплетнях из предыдущего изменения схемы прибывает поздно (т.е. После того, как новая команда CREATE TABLE пришла к этому node.) Это, когда я получу эта ошибка. Самая худшая часть, я думаю, заключается в том, что это ложная ошибка (то есть она говорит мне, что сплетни были позже, а не то, что моя схема недействительна, а схема сообщения сплетни является старой).

org.apache.cassandra.exceptions.ConfigurationException: Column family ID mismatch (found 122a2d20-9e13-11e6-b830-55bace508971; expected 1213bef0-9e
    at org.apache.cassandra.config.CFMetaData.validateCompatibility(CFMetaData.java:790) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.config.CFMetaData.apply(CFMetaData.java:750) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.config.Schema.updateTable(Schema.java:661) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.schema.SchemaKeyspace.updateKeyspace(SchemaKeyspace.java:1350) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.schema.SchemaKeyspace.mergeSchema(SchemaKeyspace.java:1306) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.schema.SchemaKeyspace.mergeSchemaAndAnnounceVersion(SchemaKeyspace.java:1256) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.service.MigrationTask$1.response(MigrationTask.java:92) ~[apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.net.ResponseVerbHandler.doVerb(ResponseVerbHandler.java:53) [apache-cassandra-3.9.jar:3.9]
    at org.apache.cassandra.net.MessageDeliveryTask.run(MessageDeliveryTask.java:64) [apache-cassandra-3.9.jar:3.9]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_111]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_111]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_111]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_111]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_111]