最近客户反馈他们的一个数据同步软件将生产数据同步到备库后,出现数据丢失的问题,想想ORACLE的redo落盘保护机制这么完善还没听说过有丢失的问题,如果真的有这个问题,崩溃恢复和一切需要用到redo的同步ADG等机制,还咋保障。应该是同步软件解析存在问题吧。
这个问题后面软件运维人员最终答复是需要调整_log_parallelism_max=1,否则会出现不一致。先不管最终什么原因,先对这个参数研究一把。
这是个redo相关的核心参数。
一、原理:Redo写入redo buffer的整个过程如下
1、在PGA中生产Redo Enrey
2、服务进程获取Redo Copy latch(存在多个---CPU_COUNT*2)
3、服务进程获取redo allocation latch(仅1个)
4、分配log buffer
5、 释放redo allocation latch
6、 将Redo Entry写入Log Buffer
7、释放Redo Copy latch
第4步提到分配log buffer,这个是重哪里分配呢?别急,我们引入2个概念shared strand、private strand
二:shared strand
为了减少redo allocation latch等待,在oracle 9.2中,引入了log buffer的并行机制。其基本原理就是,将log buffer划分为多个小的buffer,这些小的buffer被成为strand(为了和之后出现的private strand区别,它们被称之为shared strand)。每一个strand受到一个单独redo allocation latch的保护。多个shared strand的出现,使原来序列化的redo buffer分配变成了并行的过程,从而减少了redo allocation latch等待
shared strand 的分配情况
查看log buffer中内存空间分配的 shared strand个数数量(每一个shared strand的大小 = log_buffer/(shared strand数量)),也可以用下面语句查询
select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa != '00';
三、Private strand
为了进一步降低redo buffer冲突,在10g中引入了新的strand机制——Private strand。Private strand不是从log buffer中划分的,而是在shared pool中分配的一块内存空间
Private strand的引入为Oracle的Redo/Undo机制带来很大的变化。每一个Private strand受到一个单独的redo allocation latch保护,每个Private strand作为“私有的”strand只会服务于一个活动事务。获取到了Private strand的用户事务不是在PGA中而是在Private strand生成Redo,当flush private strand或者commit时,Private strand被批量写入log文件中。如果新事务申请不到Private strand的redo allocation latch,则会继续遵循旧的redo buffer机制,申请写入shared strand中。事务是否使用Private strand,可以由x$ktcxb的字段ktcxbflg的
对于使用Private strand的事务,无需先申请Redo Copy Latch,也无需申请Shared Strand的redo allocation latch,而是flush或commit是批量写入磁盘,因此减少了Redo Copy Latch和redo allocation latch申请/释放次数、也减少了这些latch的等待,从而降低了CPU的负荷
每个Private strand的大小为65K。10g中,shared pool中的Private strands的大小就是活跃会话数乘以65K,而11g中,在shared pool中需要为每个Private strand额外分配4k的管理空间,即:数量*69k
原理(优化后):Redo写入redo buffer的整个过程如下
1、事务开始
2、申请Private strand的redo allocation latch (申请失败则申请Shared Strand的redo allocation latch)
3、在Private strand中生产Redo Enrey
4、Flush/Commit
5、申请Redo Copy Latch
6、服务进程将Redo Entry批量写入Log File
7、释放Redo Copy Latch
8、释放Private strand的redo allocation latch
Private strand 的分配情况
查看shared pool中分配的 Private strand个数数量
select indx,strand_size_kcrfa from x$kcrfstrand where last_buf_kcrfa = '00';
查看log file 中分配的 Private strand个数数量
参数_log_private_mul指定了使用多少logfile空间预分配给Private strand,默认为5。我们可以根据当前logfile的大小(要除去预分配给log buffer的空间)计算出这一约束条件下能够预分配多少个Private strand:
select count(1) "actual private strands" from x$kcrfstrand where last_buf_kcrfa = '00';
select trunc(((select bytes from v$log where status = 'CURRENT' and THREAD#=1) - (select value from v$parameter where name = 'log_buffer'))*
(select to_number(val.KSPPSTVL)
from sys.x$ksppi nam, sys.x$ksppsv val
where nam.indx = val.indx
AND nam.ksppinm = '_log_private_mul') / 100 / 66560)
as "calculated private strands"
from dual;
查看有多少事务是否使用Private strand
查看有多少事务是否使用Private strand:(基本上发起一个事物,就会看到count(*) +1)
select decode(bitand(ktcxbflg, 4096),0,1,0) used_private_strand, count(*)
from x$ktcxb
where bitand(ksspaflg, 1) != 0
and bitand(ktcxbflg, 2) != 0
group by bitand(ktcxbflg, 4096);
查看sga(shared pool)中内存空间Private strand的使用大小
以下查询结果应该是一致的:
select * from v$sgastat where name ='private strands';
--10g
select trunc(value * KSPPSTVL / 100) * 65 * 1024
from (select value from v$parameter where name = 'transactions') a,
(select val.KSPPSTVL
from sys.x$ksppi nam, sys.x$ksppsv val
where nam.indx = val.indx
AND nam.ksppinm = '_log_private_parallelism_mul') b;
--11g
select trunc(value * KSPPSTVL / 100) * (65 + 4) * 1024
from (select value from v$parameter where name = 'transactions') a,
(select val.KSPPSTVL
from sys.x$ksppi nam, sys.x$ksppsv val
where nam.indx = val.indx
AND nam.ksppinm = '_log_private_parallelism_mul') b;
查看sga(shared pool)中内存空间Private strand的使用大小历史分配趋势
select a.instance_number,to_char(b.end_interval_time,'yyyy-mm-dd hh24:mi:ss'),name,pool,bytes from dba_hist_sgastat a,dba_hist_snapshot b
where a.snap_id=b.snap_id
and a.name ='private strands'
order by 1,2;
四:各相关参数解释
1、参数_log_parallelism_max
关于shared strand的数量设置,16个cpu之内***默认为2,当系统中存在Oracle redo allocation latch等待时,每增加16个cpu可以考虑增加1个strand,***不应该超过8。并且_log_parallelism_max不允许大于cpu_count
shared strand的初始数据量是由参数log_parallelism控制的;在10g中,该参数成为隐含参数,并新增参数_log_parallelism_max控制shared strand的最大数量
在11g中,参数_log_parallelism被取消,shared strand数量由_log_parallelism_max、_log_parallelism_dynamic和cpu_count控制
2、参数_log_parallelism_dynamic
_log_parallelism_dynamic则控制是否允许shared strand数量在_log_parallelism和_log_parallelism_max之间动态变化
3、参数_log_private_mul
参数_log_private_mul指定了使用多少logfile空间预分配给Private strand,默认为5。我们可以根据当前logfile的大小(要除去预分配给log buffer的空间)计算出这一约束条件下能够预分配多少个Private strand
五:测试
于是在测试环境(11G、机器配置不高)上进行了如下测试,3个session同时进行insert操作。在_log_parallelism_max=2和_log_parallelism_max=1(相当于不从shared pool去申请)时候,测试情况如下:
测试结果表明(仅供参考):插入性能未受明显的影响,等待事件有所差异,但是总量差不多。可能是机器性能差的原因,和无法模拟生产混合场景的情况。没有很明显的测试出Private strand带来的好处。