perfkitbenchmarker/linux_packages/postgresql16.py (286 lines of code) (raw):

# Copyright 2020 PerfKitBenchmarker Authors. All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Module containing postgres installation functions.""" import os from perfkitbenchmarker import data from perfkitbenchmarker import os_types SYSBENCH_PASSWORD = 'Syb3enCh#1' SHARED_BUFFERS_CONF = { 'SIZE_10GB': { 'shared_buffers': '10GB', 'effective_cache_size': '30GB', 'max_memory': '40G', 'nr_hugepages': '5632', }, 'SIZE_100GB': { 'shared_buffers': '100GB', 'effective_cache_size': '112.5GB', 'max_memory': '150G', 'nr_hugepages': '52736', }, 'SIZE_80GB': { # run with 40M table size and 8 tables to write 80GB of data 'shared_buffers': '80GB', 'effective_cache_size': '90GB', 'max_memory': '120G', 'nr_hugepages': '45000', }, } OS_DEPENDENT_DEFAULTS = { 'centos': { 'postgres_path': '/usr/pgsql-16', 'data_dir': '/var/lib/pgsql/16/data', 'conf_dir': '/var/lib/pgsql/16/data', 'disk_mount_point': '/var/lib/pgsql/16', 'postgres_service_name': 'postgresql-16' }, 'debian': { 'postgres_path': '/usr/lib/postgresql/16', 'data_dir': '/etc/postgresql/16/data/data', 'conf_dir': '/etc/postgresql/16/main', 'disk_mount_point': '/etc/postgresql/16/data', 'postgres_service_name': 'postgresql', 'postgres_template_service_name': 'postgresql@16-main', }, 'amazonlinux': { 'data_dir': '/var/lib/pgsql/data', 'conf_dir': '/var/lib/pgsql/data', 'disk_mount_point': '/var/lib/pgsql', 'postgres_service_name': 'postgresql', } } def ConfigureSystemSettings(vm): """Tune OS for postgres.""" sysctl_append = 'sudo tee -a /etc/sysctl.conf' sysctl_data = ( 'vm.swappiness=1\nvm.dirty_ratio=15\nvm.dirty_background_ratio=5\n' 'net.core.somaxconn=65535\nnet.core.netdev_max_backlog=65535\n' 'net.ipv4.tcp_max_syn_backlog=65535\n' 'net.ipv4.ip_local_port_range=4000 65000\nnet.ipv4.tcp_tw_reuse=1\n' 'net.ipv4.tcp_fin_timeout=5' ) vm.RemoteCommand(f'echo """{sysctl_data}""" | {sysctl_append}') vm.RemoteCommand('sudo sysctl -p') limits_append = 'sudo tee -a /etc/security/limits.conf' vm.RemoteCommand(f'echo "* soft nofile 64000" | {limits_append}') vm.RemoteCommand(f'echo "* hard nofile 64000" | {limits_append}') vm.RemoteCommand( 'echo "session required pam_limits.so" | sudo tee -a /etc/pam.d/login' ) thp_append = 'sudo tee -a /usr/lib/systemd/system/disable-thp.service' vm.RemoteCommand('sudo touch /usr/lib/systemd/system/disable-thp.service') disable_huge_pages = f"""[Unit] Description=Disable Transparent Huge Pages (THP) DefaultDependencies=no After=sysinit.target local-fs.target Before={GetOSDependentDefaults(vm.OS_TYPE)["postgres_service_name"]}.service [Service] Type=oneshot ExecStart=/bin/sh -c 'echo never | tee /sys/kernel/mm/transparent_hugepage/enabled > /dev/null' [Install] WantedBy=basic.target """ vm.RemoteCommand(f'echo "{disable_huge_pages}" | {thp_append}') vm.RemoteCommand( 'sudo chown root:root /usr/lib/systemd/system/disable-thp.service' ) vm.RemoteCommand( 'sudo chmod 0600 /usr/lib/systemd/system/disable-thp.service' ) vm.RemoteCommand('sudo systemctl daemon-reload') vm.RemoteCommand( 'sudo systemctl enable disable-thp.service && sudo systemctl start' ' disable-thp.service' ) vm.Reboot() def YumInstall(vm): """Installs the postgres package on the VM.""" if vm.OS_TYPE not in os_types.AMAZONLINUX_TYPES: vm.RemoteCommand('sudo dnf config-manager --set-enabled crb') vm.RemoteCommand('sudo dnf install -y epel-release epel-next-release') if vm.is_aarch64: repo = 'EL-9-aarch64' else: repo = 'EL-9-x86_64' vm.RemoteCommand( 'sudo yum install -y https://download.postgresql.org/pub/repos/yum/' f'reporpms/{repo}/pgdg-redhat-repo-latest.noarch.rpm --skip-broken' ) vm.RemoteCommand('sudo dnf -qy module disable postgresql') else: vm.RemoteCommand('sudo dnf update') postgres_devel = 'postgresql16-devel' if vm.OS_TYPE in os_types.AMAZONLINUX_TYPES: postgres_devel = 'postgresql-devel' vm.RemoteCommand( 'sudo yum install -y postgresql16-server postgresql16' f' postgresql16-contrib {postgres_devel}' ) vm.RemoteCommand( 'echo "export PATH=/usr/pgsql-16/bin:$PATH" | sudo tee -a ~/.bashrc' ) vm.RemoteCommand('pg_config --version') def AptInstall(vm): """Installs the postgres package on the VM.""" vm.RemoteCommand('sudo apt-get install -y postgresql-common') vm.RemoteCommand( 'sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y' ) vm.RemoteCommand('sudo apt-get update') vm.RemoteCommand('sudo apt-get install -y postgresql-contrib-16') vm.RemoteCommand('sudo apt-get -y install postgresql-16') def InitializeDatabase(vm): """Initialize the database.""" if vm.OS_TYPE in os_types.AMAZONLINUX_TYPES: vm.RemoteCommand('sudo postgresql-setup --initdb') return postgres_path = GetOSDependentDefaults(vm.OS_TYPE)['postgres_path'] data_path = GetOSDependentDefaults(vm.OS_TYPE)['data_dir'] vm.RemoteCommand( f'sudo mkdir -p {data_path} && sudo chown postgres:root' f' {data_path}' ) vm.RemoteCommand( 'sudo -u postgres' f' {postgres_path}/bin/initdb -D' f' {data_path}' ) def GetOSDependentDefaults(os_type: str) -> dict[str, str]: """Returns the OS family.""" if os_type in os_types.CENTOS_TYPES: return OS_DEPENDENT_DEFAULTS['centos'] elif os_type in os_types.AMAZONLINUX_TYPES: return OS_DEPENDENT_DEFAULTS['amazonlinux'] else: return OS_DEPENDENT_DEFAULTS['debian'] def IsUbuntu(vm): """Returns whether the VM is Debian.""" return vm.OS_TYPE in os_types.UBUNTU_OS_TYPES def ConfigureAndRestart(vm, run_uri, buffer_size): """Configure and restart postgres. Args: vm: virtual machine to configure postgres on. run_uri: run uri to use for password generation. buffer_size: buffer size to use for postgres. """ conf_path = GetOSDependentDefaults(vm.OS_TYPE)['conf_dir'] data_path = GetOSDependentDefaults(vm.OS_TYPE)['data_dir'] buffer_size_key = f'SIZE_{buffer_size}GB' conf_template_config = 'postgresql/postgresql-custom.conf.j2' remote_temp_config = '/tmp/my.cnf' postgres_conf_path = os.path.join(conf_path, 'postgresql-custom.conf') pg_hba_conf_path = os.path.join(conf_path, 'pg_hba.conf') database_queries_path = os.path.join(conf_path, 'queries.sql') database_setup_queries = 'postgresql/database_setup_queries.sql.j2' context = { 'listen_address': vm.internal_ip, 'shared_buffers': SHARED_BUFFERS_CONF[buffer_size_key]['shared_buffers'], 'effective_cache_size': SHARED_BUFFERS_CONF[buffer_size_key][ 'effective_cache_size' ], 'data_directory': data_path, 'host_address': vm.internal_ip, 'password': GetPsqlUserPassword(run_uri), } vm.RenderTemplate( data.ResourcePath(conf_template_config), remote_temp_config, context, ) vm.RemoteCommand(f'sudo cp {remote_temp_config} {postgres_conf_path}') vm.RemoteCommand( 'sudo echo -e "\ninclude = postgresql-custom.conf" | sudo tee -a' f' {os.path.join(conf_path, "postgresql.conf")}' ) vm.RenderTemplate( data.ResourcePath('postgresql/pg_hba.conf.j2'), '/tmp/pg_hba.conf', {}, ) vm.RemoteCommand(f'sudo cp /tmp/pg_hba.conf {pg_hba_conf_path}') vm.RenderTemplate( data.ResourcePath(database_setup_queries), '/tmp/queries.sql', { 'repl_user_password': GetPsqlUserPassword(run_uri), 'sysbench_user_password': GetPsqlUserPassword(run_uri), 'pmm_user_password': GetPsqlUserPassword(run_uri), }, ) vm.RemoteCommand(f'sudo cp /tmp/queries.sql {database_queries_path}') vm.RemoteCommand(f'sudo chmod 755 {database_queries_path}') # changes made to /proc do not persist after a reboot vm.RemoteCommand('sudo sync; echo 3 | sudo tee /proc/sys/vm/drop_caches') postgres_service_name = GetOSDependentDefaults(vm.OS_TYPE)[ 'postgres_service_name' ] UpdateHugePages(vm, buffer_size_key) if IsUbuntu(vm): postgres_service_name = GetOSDependentDefaults( vm.OS_TYPE )['postgres_template_service_name'] UpdateMaxMemory(vm, buffer_size_key, postgres_service_name) vm.RemoteCommand( 'sudo su - postgres -c "openssl req -new -x509 -days 365 -nodes -text' f' -out {data_path}/server.crt -keyout' f' {data_path}/server.key -subj "/CN=`hostname`""' ) vm.RemoteCommand(f'sudo chmod 755 {postgres_conf_path}') vm.RemoteCommand( 'sudo systemctl restart' f' {GetOSDependentDefaults(vm.OS_TYPE)["postgres_service_name"]}' ) vm.RemoteCommand(f'sudo systemctl status {postgres_service_name}') vm.RemoteCommand( f'sudo su - postgres -c "psql -a -f {database_queries_path}"' ) def UpdateHugePages(vm, buffer_size_key): vm.RemoteCommand( 'sudo sysctl -w' f' vm.nr_hugepages={SHARED_BUFFERS_CONF[buffer_size_key]["nr_hugepages"]}' ) vm.RemoteCommand( 'sudo sysctl -w vm.hugetlb_shm_group=$(getent group postgres | cut -d:' ' -f3)' ) vm.RemoteCommand('cat /proc/meminfo | grep -i "^hugepage"') vm.RemoteCommand('sudo cat /proc/sys/vm/hugetlb_shm_group') def UpdateMaxMemory(vm, buffer_size_key, postgres_service_name): vm.RemoteCommand( 'sudo systemctl set-property' f' {postgres_service_name}.service' f' MemoryMax={SHARED_BUFFERS_CONF[buffer_size_key]["max_memory"]}' ) vm.RemoteCommand( f'cat /etc/systemd/system.control/{postgres_service_name}.service.d/50-MemoryMax.conf' ) def SetupReplica(primary_vm, replica_vm, replica_id, run_uri, buffer_size): """Setup postgres replica.""" buffer_size_key = f'SIZE_{buffer_size}GB' data_path = GetOSDependentDefaults(replica_vm.OS_TYPE)['data_dir'] conf_path = GetOSDependentDefaults(replica_vm.OS_TYPE)['conf_dir'] replica_vm.RemoteCommand(f'sudo mkdir -p {data_path}') replica_vm.RemoteCommand(f'sudo chown postgres:root {data_path}') replica_vm.RemoteCommand( 'sudo su - postgres -c' f' "PGPASSWORD="{GetPsqlUserPassword(run_uri)}"' f' pg_basebackup -h {primary_vm.internal_ip} -U repl -p 5432 -v -D' f' {data_path} -S slot{replica_id} -Fp -P -Xs -R"' ) context = { 'listen_address': 'localhost', 'shared_buffers': SHARED_BUFFERS_CONF[buffer_size_key]['shared_buffers'], 'effective_cache_size': SHARED_BUFFERS_CONF[buffer_size_key][ 'effective_cache_size' ], 'data_directory': data_path, } conf_template_config = 'postgresql/postgresql-custom.conf.j2' remote_temp_config = '/tmp/my.cnf' postgres_conf_path = os.path.join(conf_path, 'postgresql-custom.conf') replica_vm.RenderTemplate( data.ResourcePath(conf_template_config), remote_temp_config, context, ) replica_vm.RemoteCommand(f'sudo cp {remote_temp_config} {postgres_conf_path}') replica_vm.RemoteCommand( 'sudo echo -e "\ninclude = postgresql-custom.conf" | sudo tee -a' f' {os.path.join(conf_path, "postgresql.conf")}' ) postgres_service_name = GetOSDependentDefaults(replica_vm.OS_TYPE)[ 'postgres_service_name' ] UpdateHugePages(replica_vm, buffer_size_key) UpdateMaxMemory(replica_vm, buffer_size_key, postgres_service_name) replica_vm.RemoteCommand( 'sudo sync; echo 3 | sudo tee -a /proc/sys/vm/drop_caches' ) if IsUbuntu(replica_vm): postgres_service_name = GetOSDependentDefaults( replica_vm.OS_TYPE )['postgres_template_service_name'] UpdateMaxMemory(replica_vm, buffer_size_key, postgres_service_name) replica_vm.RemoteCommand(f'sudo chown -R postgres:root {data_path}') replica_vm.RemoteCommand(f'sudo chown -R postgres:root {conf_path}') replica_vm.RemoteCommand( f'sudo chmod 700 {data_path}' ) replica_vm.RemoteCommand( 'sudo systemctl restart' f' {GetOSDependentDefaults(replica_vm.OS_TYPE)["postgres_service_name"]}' ) def GetPsqlUserPassword(run_uri): return run_uri + '_' + SYSBENCH_PASSWORD