Gazelle 加速 openGauss

背景介绍

openGauss是一款高性能数据库,Gazelle作为一款高性能用户态协议栈,能够大幅提高应用的网络I/O吞吐能力。通过使用Gazelle加速openGauss,可有效提高openGauss性能。 gazelle在openGauss单机场景中,能够提升15%的性能,一主一备场景中,能够提升5%的性能。

功能约束

  • 当前验证使用的openGauss版本是openGauss 6.0.0(LTS)版本,其他版本未做过验证,可能不支持。
  • 当前gazelle验证通过openGauss单机、一主一备场景的加速使能,其他场景未做过验证,可能不支持。
  • Gazelle不支持端口复用:如果在用户态协议栈的IP上使用了某个端口,其他IP不能再使用这个端口。

用户态环境搭建

前置条件

  1. 数据库安装完成以及完成内核态数据库正常启动。内核态具体可参考:openGauss官网

  2. 安装gazelle及依赖

     ```sh
     yum -y install gazelle dpdk libconfig numactl libboundscheck libcap 
     ``` 
    
  3. benchmark 安装使用可参考 benchmarkSql使用

Gazelle环境配置

通过以下命令查看支持的大页大小。

shell
ll /sys/kernel/mm/hugepages/

一般来说,每个numa节点需要设置2-3G的大页内存。通常为4个numa节点,即需要8-12G的大页内存。根据支持的大页大小设置大页数量。

例如加入hugepages-1048576kB(1G)的大页,这里选择的是20个大页。对应内存为20GB,足够分配使用。需要保证数量为4的倍数。这个数值不宜过大,过大时会占据过多操作系统内存。

shell
echo 20 > /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages

#设置完成之后,在本地创建磁盘挂载:
mkdir /mnt/hugepages-1G
mount -t hugetlbfs -o pagesize=1G nodev /mnt/hugepages-1G

#加载ko
modprobe vfio enable_unsafe_noiommu_mode=1
modprobe vfio-pci

说明

Gazelle部署详见Gazelle用户指南
不同网卡绑定用户态方法详见Gazelle网卡支持及使用

配置lstack.conf文件

使用对应数据库用户编写lstack.conf,即保证用户具备该文件的访问权限。

几个关键配置项说明及修改点:

  • dpdk_args

3096,3096,3096,3096为每个numa设置的内存大小。这里设置3GB。

/mnt/hugepages-1G修改为大页环境配置中设置的路径。

  • num_cpus

30,31,62,63,94,95,126,127:lstack设置的网络中断核。这里设置的是每个numa的最后两个CPU号。一共使用8个中断。

  • app_bind_numa

该参数决定是否将epoll/poll线程绑定到对应的numa节点上。需设置为0,即不绑定。gazelle绑核策略与gauss绑核策略冲突,此处使用gauss绑核策略。

  • host_addr、mask_addr、gateway_addr、devices

获取需要的网卡ip信息。一般通过使用ip addr show命令查看,即可获取所需信息。gateway_addr一般是ip将最后一位改为1。可以通过route -n查看gateway。 需要配置的网卡信息:

host_addr:20.20.20.119

mask_addr:255.255.255.0

gateway_addr:20.20.20.1

devices:78:b4:6a:40:16:30

执行ip addr show命令后截取的网卡信息:

sh
 8: enp7s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
     link/ether 78:b4:6a:40:16:30 brd ff:ff:ff:ff:ff:ff
     inet 20.20.20.149/24 brd 20.20.20.255 scope global enp7s0
        valid_lft forever preferred_lft forever
  • app_exclude_cpus

排除的CPU编号。openGauss采用CPU0作为xlog写入线程。采用app_exclude_cpus="0"这个方式排除对CPU0的绑核处理。

  • listen_shadow

是否使用影子fd监听,0为关闭,1为开启。单listen线程,多协议栈线程时使能。此处需要开启。

配置文件参考实例:

shell
dpdk_args=["--socket-mem", "3096,3096,3096,3096", "--huge-dir", "/mnt/hugepages-1G", "--proc-type", "primary", "--legacy-mem"]

use_ltran=0
kni_switch=0

low_power_mode=0

#needed mbuf count = tcp_conn_count * mbuf_count_per_conn
tcp_conn_count = 1500
mbuf_count_per_conn = 350

# send ring size, default is 32, max is 2048
send_ring_size = 32

# 0: when send ring full, send return
# 1: when send ring full, alloc mbuf from mempool to send data
expand_send_ring = 0

#protocol stack thread per loop params
#read data form protocol stack into recv_ring
read_connect_number = 4
#process rpc msg number
rpc_number = 4
#read nic pkts number
nic_read_number = 128

#each cpu core start a protocol stack thread.
num_cpus="30,31,62,63,94,95,126,127"

#app worker thread bind to numa in epoll/poll.
app_bind_numa=0
#app main thread affinity set by dpdk.
main_thread_affinity=0

host_addr="20.20.20.119"
mask_addr="255.255.255.0"
gateway_addr="20.20.20.1"
devices="78:b4:6a:40:16:31"

udp_enable=0
#0: use rss rule
#1: use tcp tuple rule to specify packet to nic queue
tuple_filter=0

#tuple_filter=1, below cfg valid
num_process=1
process_numa="0,1"
process_idx=0

#tuple_filer=0, below cfg valid
listen_shadow=1
#exclude cpu
app_exclude_cpus="0"

提权

对gaussdb二进制、liblstack.so提权,对ls命令提权。

shell
#对gaussdb二进制提权
sudo setcap 'cap_chown,cap_dac_override,cap_dac_read_search,cap_sys_rawio,cap_net_admin,cap_net_raw,cap_sys_admin+eip' `which gaussdb`
#对liblstack.so提权
sudo chmod u+s /usr/lib64/liblstack.so
#对ls命令提权
setcap 'cap_chown,cap_dac_override,cap_dac_read_search,cap_sys_rawio,cap_net_admin,cap_net_raw,cap_sys_admin+eip' $(which ls)

提权之后的gaussdb不会再从LD_LIBRARY_PATH中查找动态库路径,因此还需要配置全局动态库路径:vim /etc/ld.so.conf.d/opengauss.conf。将实际的动态库对应路径内容写入。

shell
/home/code/openGauss-server/dest/lib

必要路径权限

需要修改大页内存对应的文件路径权限和liblstack.so权限,允许用户访问。

shell
chown -R 777 /mnt/
chmod 777 /usr/lib64/liblstack.so

还需要确保编写的lstack.conf文件也具备用户访问权限。

数据库测试

必要信息准备

首先数据库测试需要至少一块NVME硬盘用于数据存储。

本地测试为HINIC网卡。

一些信息可以下面这些命令查询,假设网卡名为:enp8s0。

shell
# PCI查询:
 ethtool -i enp8s0 | grep bus-info

切换用户态网卡

该操作会导致该网卡无法使用。请使用BMC机器操作,或者具备双网口的环境操作。否则环境会不可用。 使用root用户切换网卡为用户态网卡。该操作会停止该网卡并用dpdk接管。如果使用该网卡建立ssh连接,会直接断开连接。

shell
#PCI=0000:08:00.0
#NET_DEVICE=enp8s0
ifconfig enp8s0 down
sudo modprobe vfio enable_unsafe_noiommu_mode=1
sudo echo 1 > /sys/module/vfio/parameters/enable_unsafe_noiommu_mode
sudo dpdk-devbind -b vfio-pci 0000:08:00.0

启动数据库

openGauss 配置文件修改:

在openGauss数据库的配置文件‘postgresql.conf’ 追加参数:追加参数文件

数据库配置 postgresql.conf文件修改,需要需根据实际情况修改线程池相关参数,以及增加数据配置文件中性能参数。

shell
# 此参数为 openGauss 绑定cpu 个数, 如 openGauss 绑定 1-29 32-61 64-93 96-125 共计 4 numa 分区,119 个 cpu, 线程数为 cpu 的整数倍,以4倍为例,为 476
thread_pool_attr = '476,4,(cpubind:1-29,32-61,64-93,96-125)'

# 此参数在使用 gazelle 加速时打开此选项
enable_gazelle_performance_mode=on

环境清理: 为避免后台缓存和后台信号量对测试有影响,需要清理下对应的数据。

shell
ipcs -m | awk '$2 ~/[0-9]+/ {print $2}' | while read s; do ipcrm -m $s; done
ipcs -s | awk '$2 ~/[0-9]+/ {print $2}' | while read s; do ipcrm -s $s; done
echo 3 > /proc/sys/vm/drop_caches

启动数据库:

shell
# 设置Gazelle 配置文件路径
LSTACK_CONF_PATH=/usr1/gazelle/gazelle_conf/lstack.conf
# 启动 Gazelle 加速 gaussdb, 已启动 openGauss 下dn1 数据库节点为例
LD_PRELOAD=liblstack.so GAZELLE_BIND_PROCNAME=gaussdb LSTACK_CONF_PATH=$LSTACK_CONF_PATH /home/opengauss/software/openGauss/bin/gaussdb -D /home/opengauss/software/openGauss/data/dn1

启动TPCC测试

客户端需要根据实际情况配置网络中断,此处以配置20个中断为例,对应的bind_irq.sh文件:

shell
intf=enp4s0

ethtool -G ${intf} rx 1024 tx 1024
ethtool -K ${intf} lro on
ethtool -L ${intf} combined ${combined}

irq_list=`cat /proc/interrupts | grep $intf | awk {'print $1'} | tr -d ":"`
irq_array_net=($irq_list)

cpu_array_irq=(27 28 29 30 31 59 60 61 62 63 91 92 93 94 95 123 124 125 126 127)

for (( i=0;i<20;i++))
do
        echo "${cpu_array_irq[$i]}" > /proc/irq/${irq_array_net[$i]}/smp_affinity_list
done

for j in ${irq_array_net[@]}
do
        cat /proc/irq/$j/smp_affinity_list
done

benchmark客户端需要根据实际情况修改并发数。 通常修改为postgresql.conf配置文件中cpubind参数,核数量的倍数如1-29,32-61,64-93,96-125核数为119,取4倍得714,则将并发数修改为714:

shell
terminals=714

恢复

  1. 停止数据库。
  2. 使用root切换回内核态网卡。

将用户态网卡切换为内核态网卡:

shell
#PCI=0000:08:00.0
#NET_DEVICE=enp8s0
#IP=20.20.20.119
sudo dpdk-devbind -u 0000:08:00.0
sudo dpdk-devbind -b hinic 0000:08:00.0
sudo ifconfig enp8s0 20.20.20.119 netmask 255.255.255.0

测试结论

在单机测试中,实测TPCC性能大致提升15%左右。

openGauss文件配置参考

postgresql.conf配置文件:打开postgresql.conf文件后,在文件末尾追加如下内容(IP需根据实际ip更改):

shell
max_connections = 4096
allow_concurrent_tuple_update = true
audit_enabled = off
checkpoint_segments = 1024
checkpoint_timeout = 15min
cstore_buffers = 16MB
enable_alarm = off
enable_codegen = false
enable_data_replicate = off
full_page_writes = off
max_files_per_process = 100000
max_prepared_transactions = 2048
shared_buffers = 350GB
#max_process_memory = 100GB
use_workload_manager = off
wal_buffers = 1GB
work_mem = 1MB
log_min_messages = FATAL
transaction_isolation = 'read committed'
default_transaction_isolation = 'read committed'
synchronous_commit = on
fsync = on
maintenance_work_mem = 2GB
vacuum_cost_limit = 10000
autovacuum = on
autovacuum_mode = vacuum
autovacuum_max_workers = 20
autovacuum_naptime = 5s
autovacuum_vacuum_cost_delay = 10
#xloginsert_locks = 48
update_lockwait_timeout = 20min

enable_mergejoin = off
enable_nestloop = off
#-----
enable_hashjoin = off
#enable_cbm_tracking = off
enable_bitmapscan = on
enable_material = off

wal_log_hints = off
log_duration = off
checkpoint_timeout = 15min
autovacuum_vacuum_scale_factor = 0.1
autovacuum_analyze_scale_factor = 0.02
enable_save_datachanged_timestamp = false

# enable_stat_send = off
# enable_commandid_send = off
log_timezone = 'PRC'
timezone = 'PRC'
lc_messages = 'C'
lc_monetary = 'C'
lc_numeric = 'C'
lc_time = 'C'

enable_thread_pool = on

enable_double_write = on

enable_incremental_checkpoint = on
enable_opfusion = on
instr_unique_sql_count=0
advance_xlog_file_num = 100
numa_distribute_mode = 'all'

track_activities = off
enable_instr_track_wait = off
enable_instr_rt_percentile = off
track_counts = off
track_sql_count = off
enable_instr_cpu_timer = off

plog_merge_age = 0

# numa_excluded_cpus = '29,30,31,61,62,63,93,94,95,125,126,127'
# numa_excluded_cpus = '28,29,30,31,60,61,62,63,92,93,94,95,124,125,126,127'

#enable_crc_check = off
session_timeout = 0

enable_instance_metric_persistent = off
enable_logical_io_statistics = off
enable_page_lsn_check = off
enable_user_metric_persistent = off
enable_xlog_prune = off

enable_resource_track = off
instr_unique_sql_count=0

remote_read_mode = non_authentication
client_min_messages = ERROR
log_min_messages = FATAL
enable_asp = off
enable_bbox_dump = off
bgwriter_flush_after = 32
#gs_clean_timeout = '300s'
#minimum_pool_size = 200
wal_keep_segments = 1025


#scan_fusion
enable_bitmapscan = off
enable_seqscan = off

track_activities='off'
enable_resource_track='off'
enable_instr_rt_percentile='off'
enable_instr_cpu_timer='off'
# bypass_workload_manager='off'
enable_asp='off'

enable_thread_pool = on
xloginsert_locks=16
checkpoint_segments=8000

enable_stmt_track=false

data_replicate_buffer_size=128MB

#bgwriter_thread_num = 1

bgwriter_delay = 5s
incremental_checkpoint_timeout = 5min
pagewriter_thread_num = 2
candidate_buf_percent_target = 0.3
pagewriter_sleep = 100ms

standby_shared_buffers_fraction = 0.9

#replconninfo1 = 'localhost=20.20.20.58 localport=21131 localheartbeatport=21135 localservice=21134 remotehost=20.20.20.64 remoteport=21131 remoteheartbeatport=21135 remoteservice=21134'

# 2020-12-20
enable_incremental_checkpoint = on
checkpoint_segments = '4096'
checkpoint_timeout = 50min
#enable_thread_pool = off

max_process_memory = 240GB
shared_buffers = 180GB

wal_level = archive
hot_standby = off

wal_receiver_buffer_size = 256MB
walsender_max_send_size = 32MB


# 2021-03-16
xloginsert_locks = 8
wal_file_init_num = 30
#xlog_idle_flushes_before_sleep = 500000000
walwriter_sleep_threshold = 50000
wal_writer_delay = 150

undo_zone_count = 0

walwriter_cpu_bind = 0
checkpoint_segments = 32768

local_syscache_threshold = 16MB
enable_cachedplan_mgr = off
enable_global_syscache = off

time_record_level = 1
enable_beta_opfusion = on

#wal_file_init_num = 10000
#advance_xlog_file_num = 50000
light_comm = on
enable_indexscan_optimization = on

hot_standby = off

checkpoint_segments = 3000
advance_xlog_file_num = 100000
thread_pool_attr = '476,4,(cpubind:1-29,32-61,64-93,96-125)'
enable_gazelle_performance_mode=on

#------------------------------------------------------------------------------
wal_file_init_num = 40000
advance_xlog_file_num = 100000