Что такое копия на записи?

Отказ от ответственности :

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

Наблюдения :

  1. Энтропия эффективно ограничивает производительность максимально возможного сжатия без потерь - Википедия - Энтропия (теория информации) [1117 ]. [1 123]
  2. Оба постоянных столбчатых формата , а также внутреннее представление Spark SQL прозрачно применяют различные методы сжатия (например, кодирование по длине прогона или . ] словарь кодирования ), чтобы уменьшить объем памяти хранимых данных.

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

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

  4. На основании 1), 2) и 3) можно предположить, что средняя степень сжатия будет зависеть от распределения данных в кластере. Мы также должны отметить, что конечный результат может быть недетерминированным, если линия вверх по течению содержит широкие преобразования.

Возможное влияние coalesce против repartition :

В целом coalesce может идти двумя путями:

[ 1161]

  • Эскалация по конвейеру до источника - самый распространенный сценарий.
  • Распространяться до ближайшего шаффла.
    • В первом случае мы можем ожидать, что степень сжатия будет сопоставима со степенью сжатия ввода. Однако есть некоторые случаи, когда можно добиться гораздо меньшего конечного результата. Давайте представим вырожденный набор данных:

    val df = sc.parallelize(
      Seq("foo", "foo", "foo", "bar", "bar", "bar"),
      6 
    ).toDF
    

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

    df.withColumn("pid", spark_partition_id).show
    
    +-----+---+
    |value|pid|
    +-----+---+
    |  foo|  0|
    |  foo|  1|
    |  foo|  2|
    |  bar|  3|
    |  bar|  4|
    |  bar|  5|
    +-----+---+
    

    Другими словами, нам нужно примерно 6 * 3 байта, что дает всего 18 байтов.

    Однако, если мы объединим

    df.coalesce(2).withColumn("pid", spark_partition_id).show
    
    +-----+---+
    |value|pid|
    +-----+---+
    |  foo|  0|
    |  foo|  0|
    |  foo|  0|
    |  bar|  1|
    |  bar|  1|
    |  bar|  1|
    +-----+---+
    

    , мы можем, например, применить RLE с маленьким int в качестве счетчика и сохранить каждый раздел 3 + 1 байт, дающий в общей сложности 8 байт.

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

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

    Как насчет repartition ?

    Без выражения разделения repartition применяется RoundRobinPartitioning (реализовано как HashPartitioning с псевдослучайным ключом на основе раздела Я бы). Пока хеш-функция ведет себя разумно, такое перераспределение должно максимизировать энтропию данных и в результате уменьшить возможную степень сжатия.

    Заключение :

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

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

    Наконец, repartition с выражением разделения или repartitionByRange должны уменьшить энтропию и улучшить степень сжатия.

    Примечание :

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

    108
    задан hhafez 21 September 2010 в 23:21
    поделиться

    4 ответа

    Я собирался описать свое собственное объяснение, но эта статья Wikipedia в значительной степени подводит итог его.

    Вот фундаментальное понятие:

    Копия на записи (иногда называемый "COW") является стратегией оптимизации, используемой в программировании. Фундаментальная идея состоит в том, что, если несколько вызывающих сторон просят ресурсы, которые первоначально неразличимы, можно дать им подсказки к тому же ресурсу. Эта функция может сохраняться, пока вызывающая сторона не пытается изменить ее "копию" ресурса, в которой точке истинная частная копия создается для предотвращения изменений, становящихся видимой всем остальным. Все это происходит прозрачно с вызывающими сторонами. Основное преимущество состоит в том, что, если вызывающая сторона никогда не делает модификаций, никакая частная копия не должна когда-либо быть созданной.

    Также вот приложение общего использования COW:

    понятие COW также используется в обслуживании мгновенного снимка на серверах баз данных как Microsoft SQL Server 2005. Мгновенные снимки сохраняют статичное представление базы данных путем хранения копии перед модификацией данных, когда базовые данные обновляются. Мгновенные снимки используются для тестирования использования или зависимых от момента отчетов и не должны использоваться для замены резервных копий.

    127
    ответ дан Andrew Hare 24 November 2019 в 03:31
    поделиться

    "Копия на записи" означает более или менее, на что она походит: у всех есть единственная общая копия тех же данных , пока они не записали , и затем копия сделана. Обычно, копия на записи используется для разрешения видов параллелизма проблем. В ZFS, например, блоки данных на диске являются выделенной копией на записи; пока нет никаких изменений, Вы сохраняете исходные блоки; изменение изменило только затронутые блоки. Это означает, что минимальное количество новых блоков выделяется.

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

    51
    ответ дан OmarGW 24 November 2019 в 03:31
    поделиться

    Я не повторю тот же ответ на Копии на записи. Я думаю ответ Andrew и , ответ Charlie уже сделал его очень ясным. Я дам Вам пример от мира ОС, только чтобы упомянуть, как широко это понятие используется.

    Мы можем использовать fork() или vfork() для создания нового процесса. vfork следует за понятием копии на записи. Например, дочерний процесс, созданный vfork, совместно использует сегмент данных и сегмент кода с родительским процессом. Это ускоряет разветвляющееся время. Это, как ожидают, будет использовать vfork при выполнении должностного лица, сопровождаемого vfork. Таким образом, vfork создаст дочерний процесс, который обменяется данными и сегмент кода с его родителем, но когда мы вызовем должностное лицо, он загрузит изображение нового исполняемого файла в адресном пространстве дочернего процесса.

    9
    ответ дан Ahmad F 24 November 2019 в 03:31
    поделиться

    Это также используется в Ruby 'Enterprise Edition' как аккуратный способ сохранить память.

    0
    ответ дан Chris 24 November 2019 в 03:31
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: