почему Кассандре так много свободного места на диске для небольших данных? - PullRequest
0 голосов
/ 24 февраля 2020

Я совершенно новый / новичок с Кассандрой. Я немного исследовал, как работает Cassandra (https://www.scnsoft.com/blog/cassandra-performance), но я попал в ситуацию.

У меня есть 2 CSV на 384 МБ и виртуальная машина Win10 с почти 10 ГБ без хранения. Моя цель - сохранить 384 МБ CSV (7,496,735 строк) в одной таблице в Cassandra, используя spark / scala от IntelliJ (все в одной виртуальной машине с одним узлом). Я предполагаю, что я буду использовать что-то вроде 200-400 МБ памяти, но в действительности все было иначе. Он потреблял все 10 ГБ диска до сбоя из-за отсутствия диска. Я думал, что «это должен быть фактор репликации», но это не может быть так, как пространство ключей было создано как:

CREATE KEYSPACE, ЕСЛИ НЕ СУЩЕСТВУЕТ testkeyspace WITH REPLICATION = {'class': 'SimpleStrategy' , 'replication_factor': 1} AND DURABLE_WRITES = true;

При подсчете хранимых строк (это длилось вечно, выполняя несколько операций на консоли самостоятельно), удается сохранить: 1.767.450 строк .

it lasted forever, doing several operations on the console by itself

На следующий день я понял, что он «освобождает» 6,38 ГБ диска.

Мои вопросы:

, почему Cassandra требовалось слишком много свободного дискового пространства для таких маленьких данных (сначала 10 ГБ, а затем 3,5 ГБ для менее чем 0,5 ГБ необработанных данных )?

почему позже освобождается дисковое пространство (6,38 ГБ, которое должно было использоваться)?

и, наконец, как я могу успешно сохранить данные CSV в Cassandra из spark / scala ?

Код для записи:

val spark_cassandra = cassandra_session()
cassandra_write(spark_cassandra, joined_df_unique, "joined_df_unique", "testkeyspace")

def cassandra_write( spark_cassandra : SparkSession, df : DataFrame , df_name : String, keyspace : String )  = {
    import com.datastax.spark.connector._
    import com.datastax.spark.connector.cql.CassandraConnector
    import org.apache.spark.sql.cassandra._

    val sparkContext = spark_cassandra.sparkContext
    val connector = CassandraConnector(sparkContext.getConf)

    df.createCassandraTable(keyspace,df_name) //, writeConf = writeConf)
    df.write.cassandraFormat(df_name,keyspace).mode(SaveMode.Append).save()

  }

def cassandra_session()  :  SparkSession = {

    val spark_cassandra = org.apache.spark.sql.SparkSession
      .builder()
      .master("local[*]")
      .config("spark.cassandra.connection.host", "localhost")
      .appName("Spark Cassandra Connector Example")
      .getOrCreate()

    spark_cassandra
  }

 // ("com.datastax.spark" %% "spark-cassandra-connector" % "2.4.3")

Извините, если это слишком основательно c, я впервые храню фоновую искру / scala для Кассандры. Заранее спасибо.

1 Ответ

2 голосов
/ 24 февраля 2020

Cassandra хранит данные на диске как неизменяемые SSTables (каждый SSTable состоит из нескольких файлов). Неизменяемость SSTables решает определенные проблемы, присущие распределенным системам, которые я не буду go описывать здесь.

Следствием неизменности является то, что при обновлении или удалении значения вы просто пишете новое значение ( или в случае удаления вы пишете надгробную плиту, которая, по сути, гласит: «это значение было удалено в то же самое время»). UPDATE - это, по сути, еще один INSERT, а DELETE - это действительно особенный INSERT.

  • В момент времени 0 введите значение 1 для ключа «A» => SSTable, содержащее запись метки времени 0, связывающую 1 с «A «записывается на диск
  • Через некоторое время n ( n > 0) обновите ключ« A »со значением 2 => SSTable, содержащим метку времени n ассоциирование 2 с «A» записывается на диск (предыдущая SSTable, ассоциирующая 1 с «A» в момент времени 0, остается на диске)
  • После времени n , a чтение значения «A» отсканирует таблицы SST, увидит оба значения 1 и 2, связанные с «A», и выберет более позднее, то есть значение 2
  • Через некоторое время m ( m > n > 0), удалить ключ «A» => SSTable, содержащее метку времени m с надгробной плитой для «A» на диск (остаются два предыдущих SSTable)

Это несколько упрощается, но в результате получается, что если все INSERT использовались * 103 1 * x байт диска, после выполнения запросов y UPDATE или DELETE общее потребление диска может быть не намного меньше (1 + y ) * x .

В Cassandra существует процесс сжатия, который в нашем сценарии в конечном итоге объединит три SSTable со значениями для «A» (включая надгробную плиту) в один SSTable только с последним значением (т. Е. tombstone) для «A», и после этого в конечном итоге удалите любые следы «A» из таблиц SSTable (обратите внимание, что в кластере не случайно, что tombstone не распространяется по всему кластеру, что приводит к получению данных, которые были удален, будучи воскрешенным как "зомб ie"). В зависимости от используемой стратегии сжатия и объема записи, прежде чем освободить любое пространство, может потребоваться много дополнительного дискового пространства: существуют даже стратегии сжатия, которые могут никогда восстанавливать пространство (примером является TimeWindowCompaction, часто встречается в сценарии использования временных рядов).

Стоит отметить, что чтение, которое попадает в слишком много (по умолчанию, IIR C, 100k) надгробий, не сможет вернуть никаких данных; это должно быть еще одним соображением при большой нагрузке DELETE.

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

...