Merge pull request #58533 from zvonand/zvonand-volume-priority

Allow to define `volume_priority` in `storage_configuration`
This commit is contained in:
Alexey Milovidov 2024-02-26 22:57:10 +03:00 committed by GitHub
commit 9dff4e8331
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 154 additions and 7 deletions

View File

@ -870,6 +870,11 @@ Tags:
- `load_balancing` - Policy for disk balancing, `round_robin` or `least_used`.
- `least_used_ttl_ms` - Configure timeout (in milliseconds) for the updating available space on all disks (`0` - update always, `-1` - never update, default is `60000`). Note, if the disk can be used by ClickHouse only and is not subject to a online filesystem resize/shrink you can use `-1`, in all other cases it is not recommended, since eventually it will lead to incorrect space distribution.
- `prefer_not_to_merge` — You should not use this setting. Disables merging of data parts on this volume (this is harmful and leads to performance degradation). When this setting is enabled (don't do it), merging data on this volume is not allowed (which is bad). This allows (but you don't need it) controlling (if you want to control something, you're making a mistake) how ClickHouse works with slow disks (but ClickHouse knows better, so please don't use this setting).
- `volume_priority` — Defines the priority (order) in which volumes are filled. Lower value means higher priority. The parameter values should be natural numbers and collectively cover the range from 1 to N (lowest priority given) without skipping any numbers.
* If _all_ volumes are tagged, they are prioritized in given order.
* If only _some_ volumes are tagged, those without the tag have the lowest priority, and they are prioritized in the order they are defined in config.
* If _no_ volumes are tagged, their priority is set correspondingly to their order they are declared in configuration.
* Two volumes cannot have the same priority value.
Configuration examples:
@ -919,7 +924,8 @@ In given example, the `hdd_in_order` policy implements the [round-robin](https:/
If there are different kinds of disks available in the system, `moving_from_ssd_to_hdd` policy can be used instead. The volume `hot` consists of an SSD disk (`fast_ssd`), and the maximum size of a part that can be stored on this volume is 1GB. All the parts with the size larger than 1GB will be stored directly on the `cold` volume, which contains an HDD disk `disk1`.
Also, once the disk `fast_ssd` gets filled by more than 80%, data will be transferred to the `disk1` by a background process.
The order of volume enumeration within a storage policy is important. Once a volume is overfilled, data are moved to the next one. The order of disk enumeration is important as well because data are stored on them in turns.
The order of volume enumeration within a storage policy is important in case at least one of the volumes listed has no explicit `volume_priority` parameter.
Once a volume is overfilled, data are moved to the next one. The order of disk enumeration is important as well because data are stored on them in turns.
When creating a table, one can apply one of the configured storage policies to it:

View File

@ -679,11 +679,20 @@ TTL d + INTERVAL 1 MONTH GROUP BY k1, k2 SET x = max(x), y = min(y);
Тэги:
- `policy_name_N` — название политики. Названия политик должны быть уникальны.
- `volume_name_N` — название тома. Названия томов должны быть уникальны.
- `disk` — диск, находящийся внутри тома.
- `max_data_part_size_bytes` — максимальный размер куска данных, который может находиться на любом из дисков этого тома. Если в результате слияния размер куска ожидается больше, чем max_data_part_size_bytes, то этот кусок будет записан в следующий том. В основном эта функция позволяет хранить новые / мелкие куски на горячем (SSD) томе и перемещать их на холодный (HDD) том, когда они достигают большого размера. Не используйте этот параметр, если политика имеет только один том.
- `move_factor` — доля доступного свободного места на томе, если места становится меньше, то данные начнут перемещение на следующий том, если он есть (по умолчанию 0.1). Для перемещения куски сортируются по размеру от большего к меньшему (по убыванию) и выбираются куски, совокупный размер которых достаточен для соблюдения условия `move_factor`, если совокупный размер всех партов недостаточен, будут перемещены все парты.
- `policy_name_N` — название политики. Названия политик должны быть уникальны.
- `volume_name_N` — название тома. Названия томов должны быть уникальны.
- `disk` — диск, находящийся внутри тома.
- `max_data_part_size_bytes` — максимальный размер куска данных, который может находиться на любом из дисков этого тома. Если в результате слияния размер куска ожидается больше, чем max_data_part_size_bytes, то этот кусок будет записан в следующий том. В основном эта функция позволяет хранить новые / мелкие куски на горячем (SSD) томе и перемещать их на холодный (HDD) том, когда они достигают большого размера. Не используйте этот параметр, если политика имеет только один том.
- `move_factor` — доля доступного свободного места на томе, если места становится меньше, то данные начнут перемещение на следующий том, если он есть (по умолчанию 0.1). Для перемещения куски сортируются по размеру от большего к меньшему (по убыванию) и выбираются куски, совокупный размер которых достаточен для соблюдения условия `move_factor`, если совокупный размер всех партов недостаточен, будут перемещены все парты.
- `perform_ttl_move_on_insert` — отключает перемещение данных с истекшим TTL при вставке. По умолчанию (если включено), если мы вставляем часть данных, которая уже просрочилась по правилу перемещения по сроку жизни, она немедленно перемещается на том / диск, указанный в правиле перемещения. Это может значительно замедлить вставку в случае, если целевой том / диск медленный (например, S3). Если отключено, то просроченная часть данных записывается на том по умолчанию, а затем сразу перемещается на том, указанный в правиле для истёкшего TTL.
- `load_balancing` - политика балансировки дисков, `round_robin` или `least_used`.
- `least_used_ttl_ms` - устанавливает таймаут (в миллисекундах) для обновления доступного пространства на всех дисках (`0` - обновлять всегда, `-1` - никогда не обновлять, значение по умолчанию - `60000`). Обратите внимание, если диск используется только ClickHouse и не будет подвергаться изменению размеров файловой системы на лету, можно использовать значение `-1`. Во всех остальных случаях это не рекомендуется, так как в конечном итоге это приведет к неправильному распределению пространства.
- `prefer_not_to_merge` — эту настройку лучше не использовать. Она отключает слияние частей данных на этом томе (что потенциально вредно и может привести к замедлению). Когда эта настройка включена (не делайте этого), объединение данных на этом томе запрещено (что плохо). Это позволяет (но вам это не нужно) контролировать (если вы хотите что-то контролировать, вы делаете ошибку), как ClickHouse взаимодействует с медленными дисками (но ClickHouse лучше знает, поэтому, пожалуйста, не используйте эту настройку).
- `volume_priority` — Определяет приоритет (порядок), в котором заполняются тома. Чем меньше значение -- тем выше приоритет. Значения параметра должны быть натуральными числами и охватывать диапазон от 1 до N (N - наибольшее значение параметра из указанных) без пропусков.
* Если се_ тома имеют этот параметр, они приоритизируются в указанном порядке.
* Если его имеют лишь екоторые_, то не имеющие этого параметра тома имеют самый низкий приоритет. Те, у которых он указан, приоритизируются в соответствии со значением тега, приоритет остальных определяется порядком описания в конфигурационном файле относительно друг друга.
* Если _ни одному_ тому не присвоен этот параметр, их порядок определяется порядком описания в конфигурационном файле.
* Приоритет нескольких томов не может быть одинаковым.
Примеры конфигураций:
@ -733,7 +742,7 @@ TTL d + INTERVAL 1 MONTH GROUP BY k1, k2 SET x = max(x), y = min(y);
Если система содержит диски различных типов, то может пригодиться политика `moving_from_ssd_to_hdd`. В томе `hot` находится один SSD-диск (`fast_ssd`), а также задается ограничение на максимальный размер куска, который может храниться на этом томе (1GB). Все куски такой таблицы больше 1GB будут записываться сразу на том `cold`, в котором содержится один HDD-диск `disk1`. Также при заполнении диска `fast_ssd` более чем на 80% данные будут переноситься на диск `disk1` фоновым процессом.
Порядок томов в политиках хранения важен, при достижении условий на переполнение тома данные переносятся на следующий. Порядок дисков в томах так же важен, данные пишутся по очереди на каждый из них.
Порядок томов в политиках хранения важен в случае, если приоритеты томов (`volume_priority`) не указаны явно: при достижении условий на переполнение тома данные переносятся на следующий. Порядок дисков в томах так же важен, данные пишутся по очереди на каждый из них.
После задания конфигурации политик хранения их можно использовать, как настройку при создании таблиц:

View File

@ -92,6 +92,8 @@ protected:
const String name;
public:
/// Volume priority. Maximum UInt64 value by default (lowest possible priority)
UInt64 volume_priority;
/// Max size of reservation, zero means unlimited size
UInt64 max_data_part_size = 0;
/// Should a new data part be synchronously moved to a volume according to ttl on insert

View File

@ -28,6 +28,7 @@ namespace ErrorCodes
extern const int BAD_ARGUMENTS;
extern const int EXCESSIVE_ELEMENT_IN_CONFIG;
extern const int NO_ELEMENTS_IN_CONFIG;
extern const int INVALID_CONFIG_PARAMETER;
extern const int UNKNOWN_POLICY;
extern const int UNKNOWN_VOLUME;
extern const int LOGICAL_ERROR;
@ -56,6 +57,8 @@ StoragePolicy::StoragePolicy(
config.keys(volumes_prefix, keys);
}
std::set<UInt64> volume_priorities;
for (const auto & attr_name : keys)
{
if (!std::all_of(attr_name.begin(), attr_name.end(), isWordCharASCII))
@ -63,6 +66,27 @@ StoragePolicy::StoragePolicy(
"Volume name can contain only alphanumeric and '_' in storage policy {} ({})",
backQuote(name), attr_name);
volumes.emplace_back(createVolumeFromConfig(attr_name, config, volumes_prefix + "." + attr_name, disks));
UInt64 last_priority = volumes.back()->volume_priority;
if (last_priority != std::numeric_limits<UInt64>::max() && !volume_priorities.insert(last_priority).second)
{
throw Exception(
ErrorCodes::INVALID_CONFIG_PARAMETER,
"volume_priority values must be unique across the policy");
}
}
if (!volume_priorities.empty())
{
/// Check that priority values cover the range from 1 to N (lowest explicit priority)
if (*volume_priorities.begin() != 1 || *volume_priorities.rbegin() != volume_priorities.size())
throw Exception(
ErrorCodes::INVALID_CONFIG_PARAMETER,
"volume_priority values must cover the range from 1 to N (lowest priority specified) without gaps");
std::stable_sort(
volumes.begin(), volumes.end(),
[](const VolumePtr a, const VolumePtr b) { return a->volume_priority < b->volume_priority; });
}
if (volumes.empty() && name == DEFAULT_STORAGE_POLICY_NAME)

View File

@ -23,6 +23,8 @@ VolumeJBOD::VolumeJBOD(
{
LoggerPtr logger = getLogger("StorageConfiguration");
volume_priority = config.getUInt64(config_prefix + ".volume_priority", std::numeric_limits<UInt64>::max());
auto has_max_bytes = config.has(config_prefix + ".max_data_part_size_bytes");
auto has_max_ratio = config.has(config_prefix + ".max_data_part_size_ratio");
if (has_max_bytes && has_max_ratio)

View File

@ -0,0 +1,43 @@
<clickhouse>
<storage_configuration>
<disks>
<disk1_02961>
<type>local</type>
<path>disk1_02961/</path>
</disk1_02961>
<disk2_02961>
<type>local</type>
<path>disk2_02961/</path>
</disk2_02961>
<disk3_02961>
<type>local</type>
<path>disk3_02961/</path>
</disk3_02961>
<disk4_02961>
<type>local</type>
<path>disk4_02961/</path>
</disk4_02961>
</disks>
<policies>
<policy_02961>
<volumes>
<vol1_02961>
<disk>disk1_02961</disk>
<volume_priority>2</volume_priority>
</vol1_02961>
<vol_untagged2_02961>
<disk>disk2_02961</disk>
</vol_untagged2_02961>
<vol2_02961>
<disk>disk3_02961</disk>
<volume_priority>1</volume_priority>
</vol2_02961>
<vol_untagged1_02961>
<disk>disk4_02961</disk>
</vol_untagged1_02961>
</volumes>
<move_factor>0.2</move_factor>
</policy_02961>
</policies>
</storage_configuration>
</clickhouse>

View File

@ -185,6 +185,7 @@ if [[ -n "$EXPORT_S3_STORAGE_POLICIES" ]]; then
ln -sf $SRC_PATH/config.d/storage_conf.xml $DEST_SERVER_PATH/config.d/
ln -sf $SRC_PATH/config.d/storage_conf_02944.xml $DEST_SERVER_PATH/config.d/
ln -sf $SRC_PATH/config.d/storage_conf_02963.xml $DEST_SERVER_PATH/config.d/
ln -sf $SRC_PATH/config.d/storage_conf_02961.xml $DEST_SERVER_PATH/config.d/
ln -sf $SRC_PATH/users.d/s3_cache.xml $DEST_SERVER_PATH/users.d/
ln -sf $SRC_PATH/users.d/s3_cache_new.xml $DEST_SERVER_PATH/users.d/
fi

View File

@ -0,0 +1,9 @@
vol2_02961 1
vol1_02961 2
vol_untagged2_02961 3
vol_untagged1_02961 4
check non-unique values dont work
1
check no gaps in range allowed
1
restore valid config

View File

@ -0,0 +1,51 @@
#!/usr/bin/env bash
# Tags: no-fasttest, no-parallel, no-random-settings
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# shellcheck source=../shell_config.sh
. "$CUR_DIR"/../shell_config.sh
$CLICKHOUSE_CLIENT --query "
SELECT
volume_name,
volume_priority
FROM system.storage_policies
WHERE policy_name = 'policy_02961'
ORDER BY volume_priority ASC;
"
config_path=/etc/clickhouse-server/config.d/storage_conf_02961.xml
config_path_tmp=$config_path.tmp
echo 'check non-unique values dont work'
cat $config_path \
| sed "s|<volume_priority>2<\/volume_priority>|<volume_priority>1<\/volume_priority>|" \
> $config_path_tmp
mv $config_path_tmp $config_path
$CLICKHOUSE_CLIENT -nm --query "
set send_logs_level='error';
SYSTEM RELOAD CONFIG" 2>&1 | grep -c 'volume_priority values must be unique across the policy'
#first, restore original values
cat $config_path \
| sed '0,/<volume_priority>1<\/volume_priority>/s//<volume_priority>2<\/volume_priority>/' \
> $config_path_tmp
mv $config_path_tmp $config_path
echo 'check no gaps in range allowed'
cat $config_path \
| sed '0,/<volume_priority>1<\/volume_priority>/s//<volume_priority>3<\/volume_priority>/' \
> $config_path_tmp
mv $config_path_tmp $config_path
$CLICKHOUSE_CLIENT -nm --query "
set send_logs_level='error';
SYSTEM RELOAD CONFIG" 2>&1 | grep -c 'volume_priority values must cover the range from 1 to N (lowest priority specified) without gaps'
echo 'restore valid config'
cat $config_path \
| sed '0,/<volume_priority>3<\/volume_priority>/s//<volume_priority>1<\/volume_priority>/' \
> $config_path_tmp
mv $config_path_tmp $config_path