1 什么时候需要调整数据库内存配置?
可以通过多种方式发现数据库运行内存不足,这里介绍怎样从AWR报告里发现内存不足的征兆。对于采用自动共享内存管理模式的数据库,可以从Memory Statistics下Memory Dynamic Components发现内存方面的瓶颈,看下面的图
上图中,如果组件Begin Snap Size和CurrentSize的差别比较大,或者是Oper Count的操作数据比较大,可能是数据库的SGA内存不足所致,可以结合后面的Memory Resize Operations Summary、Memory Resize Ops进一步判断。
数据库缓冲池的不足会导致缓冲区的数据块被不停地刷出后又重新读入,会造成大量物理读,另外缓冲池的大小也会影响到直接物理读(和直接物理读相关的参数如_small_table_threshold等和缓冲池大小有关)。可以从AWR报告的Advisory Statistics->Advisory Statistics部分看到不同SGA_TARGET对物理读的影响
同样,Advisory Statistics下也有对缓冲池、共享池、PGA的建议,有助于判断数据库是否存在内存方面的瓶颈。
另外,AWR报告中Buffer Pool Statistics,Dictionary Cache Stats,Library Cache Activity部分也有助于判断内存是否存在瓶颈。
2 数据库采用哪种内存管理方式?
在调整Oracle数据库内存配置之前,首先要确认数据库内存的管理方式。Oracle支持三种内存管理方式,手动内存管理、自动共享内存管理(ASMM),自动内存管理(AMM)。
手动内存管理需要禁用ASMM和AMM,这种方式现在很少用了。
自动内存管理(Automatic Memory Management,AMM)是指 Oracle 自动管理 SGA 和 PGA 的内存分配。要启用 AMM,只需设置 MEMORY_TARGET 和 MEMORY_MAX_TARGET 参数。MEMORY_TARGET 用于设置目标内存大小,而 MEMORY_MAX_TARGET 用于设置最大允许的内存大小。AMM内存设置不能和大页内存同时使用,这也就限制了它的使用场景。对于大于16G内存,SGA总内存8G的数据系统,Oracle 建议使用大页内存来提高数据库性能。在大多数场景下,虽然数据库的SGA很大(远超8GB),不启用大页内存也不会发生问题,可能得原因是数据库的并发连接不那么大。
由于自动内存管理应用场景的限制,大多数生产系统使用的自动共享内存管理(ASMM)管理,在这种方式下,Oracle自动管理SGA的动态组件,不需要DBA手动设置。
查看数据库使用了哪种内存管理方式的办法是检查数据库的几个参数,如果设置MEMORY_MAX_TARGET为非零值,则为自动化内存管理,如果这两个参数设置为0(默认值),sga_max_size和sga_target设置为大于的值则为自动共享内存管理,如果上面四个参数都是默认值0,则内存管理方式为手动管理。
2 操作系统上需要做哪些调整?
2.1 /dev/shm 和Oracle 内存管理
检查/dev/shm的值
[root@localhost ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 5.2G 0 5.2G 0% /dev
tmpfs 5.2G 1.1M 5.2G 1% /dev/shm
tmpfs 5.2G 8.7M 5.2G 1% /run
复制
/dev/shm目录是linux下一个利用内存虚拟出来的一个目录,这个目录中的文件都是保存在内存中,而不是磁盘上,其大小是非固定的,即不是预先分配好的内存来存储的,这个目录默认的容量是系统内存的一半,但是它不会真正占用这块内存,在目录里没有文件时,占用的内存空间是0,存入文件时,占用的内存是文件的大小,如下图
[root@localhost shm]# ls -lh /dev/shm
total 1.1M
-rw-------. 1 postgres postgres 27K Mar 14 10:01 PostgreSQL.2997644572
-rw-------. 1 postgres postgres 1.0M Mar 14 10:01 PostgreSQL.789534212
复制
在使用自动内存管理时,这个值要不能小于设置的值,如果小于memory_target的值,数据库启动失败,报ORA-00845错误,这是因为自动内存管理需要使用/dev/shm目录管理共享内存段(SGA),使用自动共享内存管理(ASSM)时则可以不用理会/dev/shm的设置。
bash-4.4$ df -h ##删去无关行
Filesystem Size Used Avail Use% Mounted on
shm 64M 0 64M 0% /dev/shm
SQL> show parameter sga_target
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
sga_target big integer 1536M
## /dev/shm目录里虽然有一个属于oracle用户的目录,该目录下却没有文件,总容量为0
bash-4.4$ cd /dev/shm
bash-4.4$ ls -l
total 0
drwxr-x---. 2 oracle oinstall 40 Mar 14 02:03 orahpatch_FREE
bash-4.4$ cd orahpatch_FREE
bash-4.4$ ls -l
total 0
复制
还是那个系统,改为自动内存管理,initFREE.ora里面memory_target
bash-4.4$ grep memory_target initFREE.ora *.memory_target=1536m
复制
使用这个配置文件启动数据库时,启动失败,报ORA-00845错误,如下
SQL> startup pfile=/opt/oracle/product/23ai/dbhomeFree/dbs/initFREE.ora ORA-32006: AUDIT_TRAIL initialization parameter has been deprecated ORA-00845: The Automatic Memory Management (AMM) feature encountered a problem allocating memory.
复制
修改/dev/shm大小
临时修改大小可以使用mount命令
bash-4.2# mount -o remount,size=2G /dev/shm
bash-4.2# df -h
Filesystem Size Used Avail Use% Mounted on
overlay 25G 13G 11G 57% /
tmpfs 64M 0 64M 0% /dev
shm 2.0G 0 2.0G 0% /dev/shm
复制
启动一个自动内存管理的数据库
SQL> show parameter target;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
archive_lag_target integer 0
db_big_table_cache_percent_target string 0
db_flashback_retention_target integer 1440
fast_start_io_target integer 0
fast_start_mttr_target integer 0
memory_max_target big integer 2G
memory_target big integer 0
parallel_servers_target integer 160
pga_aggregate_target big integer 512M
sga_target big integer 1536M
target_pdbs integer 4
SQL> alter system set memory_target=2048M;
System altered.
SQL> exit
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
[oracle@cac46b06f16d dbs]$ cd /dev/shm
[oracle@cac46b06f16d shm]$ ls
ora_ORCLCDB_1135834572_0_0 ora_ORCLCDB_1135834572_1_112 ora_ORCLCDB_1135834572_1_14 ora_ORCLCDB_1135834572_1_3 ora_ORCLCDB_1135834572_1_45 ora_ORCLCDB_1135834572_1_60 ora_ORCLCDB_1135834572_1_76 ora_ORCLCDB_1135834572_1_91
ora_ORCLCDB_1135834572_1_0 ora_ORCLCDB_1135834572_1_113 ora_ORCLCDB_1135834572_1_15 ora_ORCLCDB_1135834572_1_30 ora_ORCLCDB_1135834572_1_46 ora_ORCLCDB_1135834572_1_61 ora_ORCLCDB_1135834572_1_77 ora_ORCLCDB_1135834572_1_92
ora_ORCLCDB_1135834572_1_1 ora_ORCLCDB_1135834572_1_114 ora_ORCLCDB_1135834572_1_16 ora_ORCLCDB_1135834572_1_31 ora_ORCLCDB_1135834572_1_47 ora_ORCLCDB_1135834572_1_62 ora_ORCLCDB_1135834572_1_78 ora_ORCLCDB_1135834572_1_93
ora_ORCLCDB_1135834572_1_10 ora_ORCLCDB_1135834572_1_115 ora_ORCLCDB_1135834572_1_17 ora_ORCLCDB_1135834572_1_32 ora_ORCLCDB_1135834572_1_48 ora_ORCLCDB_1135834572_1_63 ora_ORCLCDB_1135834572_1_79 ora_ORCLCDB_1135834572_1_94
复制
可以看到,/dev/shm目录下有了很多以ora_ORCLCDB开头的文件,这就是为数据库SGA创建的共享内存段,这个目录下所有文件的大小问1.5G,同数据库SGA的大小一致。
在SGA的大小为内存的一半的情况下,/de/shm的大小是没有问题的,如果SGA超过内存的一半,就要调整它的大小,重启之后也生效的办法是编辑/etc/fstab 文件,加入下面条目
tmpfs /dev/shm tmpfs defaults,size=3276M 0 0
复制
2.2 用户内存限制
检查用户资源限制,登陆Oracle数据库操作系统用户,运行下面命令
[root@localhost ~]# ulimit -a|grep memory
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
virtual memory (kbytes, -v) unlimited
复制
max locked memory内存的值在使用大页内存时最好不小于SGA_TARGET的值,以免SAG内存页被换页到交换空间,影响数据库的性能。max memory size建议保持为unlimited,如果不为unlimited,这个值要设置的足够大,至少要大于SGA_MAX_SIZE和pga_aggregate_target的值和,否则,在大并发的情况下,有可能数据库新建连接时申请不到内存而导致连接失败。
2.3 内核参数
检查的内核参数shmall和和shmmax的值,
kernel.shmall = 18446744073692774399 kernel.shmmax = 18446744073692774399 kernel.shmmni = 4096
复制
shmmax 是核心参数中最重要的参数之一,用于定义单个共享内存段的最大值,这个值的单位为字节,这个值的设置应该足够大,至少不能低于SGA_TARGET,确保SGA可以分配到一个共享内存段内。如果这个值设低了,在数据库启动时需要申请多个共享内存段,在Oracle创建服务器进程时也需要连接多个共享内存段,会对系统性能有轻微的影响。
核心参数中另一个比较重要共享内存参数是shmall,这个参数的单位是页(默认页的大小是4096字节),定义的是整个系统能够使用的共享内存的总页数,可以设置为系统内存的80%至90%。设置完之后可以用下面命令查看当前系统对共享内存段的限制(命令显示的单位都是字节)
[root@localhost ~]# ipcs -lm
------ Shared Memory Limits --------
max number of segments = 4096
max seg size (kbytes) = 18014398509465599
max total shared memory (kbytes) = 18014398442373116
min seg size (bytes) = 1
复制
2.4 大页内存
a大页内存对性能的影响
大页内存前面已经提过,linux标准的内存也是4K,内存比较大时,使用大页内存有三个好处:
- 减小页表的大小
- 减小TLB(Translation Lookaside Buffer)失效的情况
- 减少 PageFault(缺页中断)的次数
为了完成虚拟地址到物理地址的映射,linux每个进程都要维护一个内存页表,如下图
页表中存储的进程访问到的每一个内存页,如果是1G内存,页表的条目是262144,在64为操作系统下,每一条映射是8Bytes,页表的大小是2MBytes,由于页表是每个进程都要维护的,在大内存大并发的情况下,页表占用的内存将非常可观。如采用的2M的大页来存储,在页表会减少为原来的1/500,会节省大量的内存,进程对页表的影响可以从下面看到
--系统当前页表大小可以用cat /proc/meminfo命令看到
-- 系统进程很少时,页表不到6M
[root@localhost ~]# cat /proc/meminfo |grep -i pagetables;
PageTables: 5860 kB
-- 启动数据库,运行压测软件,观看进程和页表大小的变化,可以看到随着Oracle服务进程的增加,页表也不断变大
[root@localhost ~]# ps -ef|grep LOCAL=NO
54321 3572 1967 0 14:58 ? 00:00:01 oracleFREE (LOCAL=NO)
54321 3694 1967 0 14:58 ? 00:00:00 oracleFREE (LOCAL=NO)
54321 3769 1967 0 14:59 ? 00:00:00 oracleFREE (LOCAL=NO)
54321 3887 1967 0 14:59 ? 00:00:00 oracleFREE (LOCAL=NO)
54321 3961 1967 0 15:00 ? 00:00:00 oracleFREE (LOCAL=NO)
54321 4069 1967 0 15:00 ? 00:00:00 oracleFREE (LOCAL=NO)
root 4123 1796 0 15:01 pts/0 00:00:00 grep --color=auto LOCAL=NO
[root@localhost ~]# cat /proc/meminfo |grep -i pagetables;
PageTables: 80612 kB
复制
b 大页内存配置
从Oracle 19C开始,大页内存的配置十分简单,只需设置USE_LARGE_PAGES的参数为相应的值即可,这个参数的值如下
TRUE - 如果大页内存可用,实例将使用大页内存。如果整个SGA不能存储到大页内存中,会分配一些常规内存页。这个是缺省值。.
FALSE - 不使用大页内存.
AUTO - 和TRUEL类似, 数据库会在系统上自动配置相应数量的大页内存。
ONLY - 如果大页内存能够存储整个SGA,则使用,否则实例启动失败.
AUTO_ONLY - 同ONLY类似, 但是数据库会自动在系统上配置正确数量的大页内存.
下面在Oracle 23AI上实验一个这个参数
SQL> show parameter USE_LARGE_PAGES
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
use_large_pages string TRUE
--默认参数值为TRUE,将其设置为auto,调整这个参数需要重新启动数据库
SQL> alter system set USE_LARGE_PAGES=AUTO scope=spfile;
System altered.
--调整完毕后重新启动数据库
复制
也可以使用下面脚本调整及重启数据库
sqlplus / as sysdba <<EOF
alter system set use_large_pages=auto scope=spfile;
shutdown immediate;
startup;
exit;
EOF
复制
如果是在Oracle19c以前的版本,则需要编辑/etc/sysctl.conf文件,加入下面条目
vm.nr_hugepages=306--根据SGA内存调整此值,大页内存的容量要大于SGA大小
## 调整完毕后运行下面命令使调整生效
sysctl -p
复制
设置大页内存的另一个办法是编辑/etc/grub.conf文件,在 kernel行末尾加上hugepages=306重启系统,使用下面命令检查更改是否生效
grep Huge /proc/meminfo AnonHugePages: 0 kB HugePages_Total: 306 HugePages_Free: 306 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB
复制
c 关闭透明大页内存(Transparent HugePages)
透明大页内存和Oracle数据库的兼容性不是很好,Oracle建议关闭,比较简单的关闭方法是编辑/etc/rc.local文件,加入下面的行后重启系统
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi
复制
使用下面命令检查设置是否生效
# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
#
复制
另一个关闭的办法在redhat 6 和7 稍有不同在redhat 6上编辑/boot/grub/grub.conf文件,在kernel boot行末尾加上transparent_hugepage=never后重启,在redhat 7 上需要如下操作
# grubby --default-kernel
/boot/vmlinuz-4.1.12-61.1.6.el7uek.x86_64
# grubby --args="transparent_hugepage=never" --update-kernel /boot/vmlinuz-4.1.12-61.1.6.el7uek.x86_64
# grubby --info /boot/vmlinuz-4.1.12-61.1.6.el7uek.x86_64
index=2
kernel=/boot/vmlinuz-4.1.12-61.1.6.el7uek.x86_64
args="ro vconsole.font=latarcyrheb-sun16 rd.lvm.lv=ol/swap rd.lvm.lv=ol/root crashkernel=auto vconsole.keymap=uk rhgb quiet LANG=en_GB.UTF-8 transparent_hugepage=never"
root=/dev/mapper/ol-root
initrd=/boot/initramfs-4.1.12-61.1.6.el7uek.x86_64.img
title=Oracle Linux Server 7.2, with Unbreakable Enterprise Kernel 4.1.12-61.1.6.el7uek.x86_64
复制
3 怎样调整Oracle内存参数?
3.1 参数设置的问题
如为内存自动管理,在设置MEMORY_TARGET 和 MEMORY_MAX_TARGET的同时,能不能设置sga_target和pga_target等参数,有没有必要设置这些参数?
在内存自动管理时,可以设置sga_target和pga_target参数,设置这个参数可以达到两个目的,一是在数据库初次启动时设置PGA和SGA的初始化值,二是在内存调整时,Oracle将尽可能保持SGA和PGA设置的值之上。同时在共享内存自动管理时,也可以设设置共享池和缓冲池的值,在设置PGA target值时也可以设置pga各个组件的值。
3.2 自动内存管理的调整
系统内存扩展之后,如果为自动内存管理,需要调整MEMORY_TARGET 和 MEMORY_MAX_TARGET参数的值, MEMORY_MAX_TARGET的值必须重启数据库实例才能生效,MEMORY_TARGET调整后可以立即生效,使用下面命令调整
alter system set MEMORY_MAX_TARGET=****M scope=spfile;
--重启数据库后调整MEMORY_TARGET值
alter system set MEMORY_TARGET=*****M scope=both;
复制
3.3 自动共享内存管理
自动共享内存管理模式下,SGA_MAX_SIZE需要重启生效,SGA_TARGET立即生效,如下
alter system set SGA_MAX_SIZE=****M scope=spfile;
--重启数据库后调整MEMORY_TARGET值
alter system set SGA_TARGET=*****M scope=both;
复制
4 写在后面
Oracle数据库内存的调整涉及到操作系统的调整比较多,需要仔细检查,数据库方面的调整反而比较简单。要注意的是在调整的时候,一定要备份一下数据库的spfile,万一弄错了可以简单快速的恢复。