4 内存管理
4.1 SGA管理
4.1.1 SGA的组成
buffer cache,shared pool,redo log buffer,large pool,java pool,streams pool
select * from v$sgainfo;
4.1.2 SGA与共享内存
SGA的设置在Linux/UNIX上和一个操作系统内核参数有关,这个参数是shmmax。
在Solaris上,该参数由/etc/system文件中shmsys:shminfo_shmmax定义;在linux上,该参数由/proc/sys/kernel/shmmax参数定义。
shmmax内核参数定义的是系统运行的单个共享内存段的最大值,如果该参数设置小于SGA设置,那么SGA仍然可以创建成功,但是会被分配到多个共享内存段。
在windows系统中,由于系统采用多线程服务器(所有oracle进程实际上都是一个进程中的线程),所以不存在共享内存的问题,无需进行特殊设置。
shmmax内核参数定义的是系统运行的单个共享内存段的最大值,如果该参数设置小于SGA设置,那么SGA仍然可以创建成功
查看shmmax值:
more /porc/sys/kernel/shmmax
查看操作系统版本:
cat /etc/redhat-release
查看操作系统发行版号:
uname -r
ipcs查看共享内存的分配:
ipcs -sa
可以看到为了创建oracle的SGA,系统共分配了27个共享内存段(shared memory segments)
针对一个后台进程,使用pmap工具可以看到每个共享内存段的地址空间
ps -ef|grep dbw
pmap 2333
echo 1073741824>/proc/sys/kernel/shmmax
这里修改为1GB,对于shmmax文件的修改,系统重启后会复位,可以通过修改/etc/sysctl.conf文件使更改永久化。
vi /etc/sysctl.conf
添加:
kernel.shmmax=1073741824
重启数据库使之生效
如果没有修改kernel参数,oracle在启动过程中就会在alertorcl.log文件中记录警告。
SGA设置过大,超过物理内存;数据库异常关闭,后台进程未正常退出,可通过ipcrm命令强制释放该共享内存段。
4.1.3 SGA管理的变迁
一些建议视图:
select * from dba_views where view_name like '%ADVICE%';
4.2.1 PGA
PGA:程序全局区,是服务器进程使用的一块包含数据和控制信息的内存区域,pga是非共享的内存,在服务器进程启动或创建时分配,通常来水,pga中包含私有sql区(存放绑定信息、运行时内存结构等)和session信息等内容。
所有服务器进程分配的PGA总和通常被称为PGA合计(aggregated pga)
对于pga_aggregate_target参数的设置,oracle提供这样一个建议方案
对于OLTP系统:
pga_aggregate_target=(total physical memory * 80%) * 20%
对于DSS系统
pga_aggregate_target=(total physical memory * 80% ) *50%
也就是说,对于一个单纯的数据库服务器,通常需要保留20%的物理内存给操作系统使用,剩余80%可以分配给oracle使用。oracle使用的内存分为两部分sga和pga,那么pga可以占用oracle消耗总内存的20%(oltp系统)~50%(dss系统)
v$process视图增加了相应字段用来记录进程的pga耗用
ps -ef|grep ora|head -l
SQL在工作区中以3种方式执行:
optimal(优化方式):指所有处理可以在内存中完成;
onepass:大部分操作可以在内存中完成,但是需要使用到磁盘操作;
multipass:大量操作需要产生磁盘交互,性能极差。
通常对于pga的优化目标,就是使得optimal的执行尽量高,也就是尽量在内存中完成所有排序等操作;同时使multipass操作尽量低,也就是要使磁盘交互尽量低。
在v$pgastat中有这样一个条目global memory bound,该条目记录数据库允许的最高pga内存使用量,可以从不同的pga参数设置来观察一些oracle允许的pga上限。
4.2.2 PGA调整建议
select pga_target_for_estimate,pga_target_factor,estd_pga_cache_hit_percentage,estd_overalloc_count from v$pga_target_advice;
hit最高,消除过载。
4.3 oracle的内存分配和使用
oracle数据库在系统占用的内存分为两个部分:SGA和PGA。
根据oracle的建议,oracle最多可以使用80%的物理内存,其余20%保留给操作系统用,在这80%的内存中,对于OLTP系统,oracle建议分配20%给PGA使用;对于DSS系统,可以分配50%给PGA使用。
如果oracle耗用的内存过高,甚至超过了系统的物理内存,那么系统的性能就会受到严重的影响,当系统执行任务时,如果没有足够的内存,那么系统就会进行分页或交换,以完成当前活动事务。
当系统执行分页时,会将当前没有使用的信息从内存转移到硬盘上,这样就可以为当前需要内存的程序分配内存。如果频繁发生分页,系统性能就会严重降低,从而导致很多程序的执行时间变长。
当系统执行交换时,会将某些进程所分配的不活跃内存页(根据LRU算法)从内存转移到硬盘上,这样另一个活动进程就可以得到所需要的内存。交换基于系统循环时间。如果交换太过于频繁,系统甚至会出现宕机。
4.3.1 诊断案列:SGA与Swap
案列描述:用户报告,服务器启动一段时间后,无法建立数据库连接。重新启动几分以后,再次无法连接。
操作系统:SunOS5.8,系统无法正常使用
(1) 登陆数据库,检查系统进程
ps -ef|grep ora
发现后台进程正常
(2)检查警报日志文件
skgpspawn failed:该提示说明系统无法fork新的数据库进程,数据库无法spawn a new session
报错:category=27142,即ora-27142,报错内容:无法创建一个新进程。
(3)尝试连接数据库
报错:超出内部限制,通常说明某些系统资源不足。
(4)检查系统日志
检查系统日志信息,发现大量失败的su操作,有Swap区不足的报告
基本可以判断是交换区的问题,当然和oracle SGA设置有关。
(5)检查系统内存及交换区使用
top
发现物理内存仅为1GB,free部分为34MB,交换区使用了752MB,仅Swap Free部分仅余10MB。由此可知,系统内存严重不足,Swap区不足。
(6)检查数据库的SGA设置
show sga;
发现SGA设置为600MB,这个SGA设置过高。
对于RAM小于1GB的系统,Dedicated模式下,通常建议oracle的sga一般不应超过1/2物理内存,sga之外还应考虑到pga及操作系统的内存分配。
(7)调整内容
减小sga,为系统保留足够的内存;
为系统增加Swap区
cd /export/home1
mkdir swap
cd swap
mkfile -v lg swapfile1
swap -a /export/home1/swap/swapfile1
swap -s
至此系统恢复正常,问题解决。
(8)问题总结
oracle数据库问题的解决从来就离不开操作系统,很多时候必须通过操作系统一级的手段来诊断并解决问题。
关于操作系统,一般Swap区的推荐指为2xSwap。
如果物理内存很大,不一定要设置成2倍,可以=或小于,若内存超过32G则完全可以设置Swap为16GB。
如果物理内存过小,在系统繁忙期间,产生大量交换无法换到磁盘,就会出现问题。
4.3.2 诊断案例二:SGA设置过高导致的系统故障
案例描述:大型生产系统,问题出现时系统累计大量用户进程,用户请求得不到及时响应,新的进程不断尝试建立连接,连接数很快被用完。最后系统处于挂起状态,无法进行服务响应。
(1)登陆数据库,检查警告日志文件
WARNING:aiowait timed out 2 times
说明系统异步IO出现问题,每次warning间隔时间为10分钟。
(2)检查共享内存设置
说明系统内核参数设置不合理或者和sga不匹配,检查system配置文件
cat /etc/system
发现最大共享内存段设置为4GB
(3)检查SGA设置
发现sga设置接近7GB(超过4GB,oracle将分配多个共享内存段)
(4)交换区问题
top
memory:8192M real,118m free 12G swap in use 11G swap free
物理内存几乎耗尽,使用了12GB的Swap
至此可以初步做出以下判断:由于SGA设置过大,导致运行时产生大量交换,大量Swap交换进而引发磁盘I/O问题。
大量交换导致数据库性能急剧下降,进而导致用户请求得不快速响应,堵塞,累计,直至数据库失去响应。
(5)解决方案
缩小SGA
(6)系统调整后状态
top
稳定
(7)一点总结
(8)后续研究
异步I/O问题
4.3.3 诊断案例三:如何诊断和解决CPU高度消耗(100%)问题
这类问题通常是因为系统中存在性能低下甚至存在错误的SQL语句,消耗了大量的CPU所致。
问题描述:系统CPU高度消耗,系统运行缓慢
(1)top命令
发现在进程列表里,存在两个搞CPU耗用的oracle进程
(2)找到存在问题的进程信息
ps -ef|grep 20521
ps -ef|grep 20845
(3)捕获存在问题的SQL语句
select /*+ordered*/ sql_text from v$sqltest a where (a.hash_value,a.address) in (select decode(sql_hash_value,0,prev_hash_value,sql_hash_value),(sql_address,0,prev_sql_address,sql_address) from v$session b where b.paddr=(select addr from v$process c where c.spid='&pid')) order by piece asc;
(4)连接数据库,找到问题sql及进程
这段代码就是CPU疯狂消耗的原因,找出这段代码的问题,看是否可以通过优化提高其效率,减少资源消耗。
(5)进一步跟踪
如果需要进一步的跟踪详细信息,可以用过dbms_system包来进行;
exec dbms_system.set_sql_trace_in_session(45,38991,true);
(6)一点说明
很多时候,高CPU消耗都是由于问题SQL导致的,所以找到这些SQL通常也就找到了问题所在,通过优化调整通常就可以解决问题。
但是有时候可能会发现,这些最消耗CPU的进程是后台进程,这一般是由于异常、BUG、或者恢复后的异常导致的,那么就需要具体问题具体分析了。
第四章完