Maclean介绍Oracle ASM基础概念和原理

ASM基础概念

如果自己搞不定可以找ASKMACLEAN专业ORACLE数据库修复团队成员帮您恢复!

 

任何转载请注明源地址,否则追究法律责任!:https://www.askmac.cn/archives/know-oracle-asm-basic-html.html

 

相关文章链接:

Asm Instance Parameter Best Practice

为什么RHEL 6上没有ASMLIB?

Unix上如何查看文件名开头为”+asm”的TRACE文件

asm_power_limit对IO的影响

针对11.2 RAC丢失OCR和Votedisk所在ASM Diskgroup的恢复手段

10g ASM lost disk log

11gR2 RAC ASM启动揭秘

在11gR2 RAC中修改ASM DISK Path磁盘路径

在Linux 6上使用UDEV解决RAC ASM存储设备名问题

Script:找出ASM中的Spfile参数文件

如何诊断ASMLIB故障

Script:收集ASM诊断信息

Comparation between ASM note [ID 373242.1] and note [ID 452924.1]

Why ASMLIB and why not?

ASM file metadata operation等待事件

几个关于oracle 11g ASM的问题

利用UDEV服务解决RAC ASM存储设备名

Discover Your Missed ASM Disks

Oracle内部视图X$KFFXP

Fixed X$ Tables in ASM

了解AMDU工具生成的MAP文件

使用AMDU工具从无法MOUNT的DISKGROUP中抽取数据文件

深入了解Oracle ASM(一):基础概念

 

asm构成图

市场占有率

 

ASM自动存储管理技术已经面世10多个年头,目前已经广泛使用于各个领域的数据库存储解决方案。 到2014年为止,ASM在RAC上的采用率接近60%,在单机环境中也超过了25%。

RAC集群环境中3种存储解决方案: ASM、集群文件系统和裸设备; 虽然仍有部分用户坚持使用古老的裸设备,但随着版本的升级,更多用户开始采用ASM这种ORACLE提供的免费解决方案。

在国内使用ASM的场景一般均采用 External Redundancy(11gR2除了存放ocr/votedisk 的DG外)。  一般在10.2.0.5和11.2.0.2之后的版本上ASM,还是较为稳定的。

下图为部分在产品环境中使用ASM的国外知名企业:

asm customers

 

ASM FILE

ORACLE RDBMS Kernel内核与ASM在高层交互是基于ASM中存放的文件即ASM FILE。 这和ORACLE RDBMS去使用文件系统或其他逻辑卷的方式没有什么区别。 ASM中可以存放 数据文件,日志文件,控制文件,归档日志等等,对于数据库文件的存放基本和文件系统没啥2样。

一个ASM  FILE的名字一般以一个”+”和DiskGroup名字开头。 当ORACLE RDBMS KERNEL内核的文件I/O层碰到一个以”+”开头的文件时,就会走到相关ASM的代码层中 而不是调用依赖于操作系统的文件系统I/O。 仅仅在File I/O层面才会认识到这是一个ASM 中的文件,而其上层的内核代码看来ASM FILE和OS FILE都是一样的。

 

ASM对ROWID和SEGMENT等RDBMS元素没有影响,不过是数据文件存放在ASM中,ASM并不会打破ORACLE数据库中的这些经典元素。

在一个ASM Diskgroup中仅仅允许存放已知的ORACLE文件类型。假设一个文件通过FTP拷贝到ASM Diskgroup中,则该文件的第一个块将被检验以便确认其类型,以及收集其他信息来构建这个文件的完整ASM文件名。 如果其文件头无法被识别,则该文件在DiskGroup中的创建将会报错。

仅有以下的文件类型可以存放在ASM Diskgroup中:

  • Control File
  • Datafile
  • Temporary data file
  • Online Redo Log
  • Archive Log
  • RMAN backup
  • Datafile Copy
  • SPFILE
  • Disaster Recovery Configuration
  • Flashback Log
  • Change Tracking Bitmap
  • DataPump? Dumpset

 

 

ORACLE 的2进制可执行文件和ASCII文件,例如alert.log和其他trace文件,则不推荐也不能存放在ASM Diskgroup里。

 

File Blocks

所有被ASM所支持的文件类型仍以其file block作为读和写的基本单位。在ASM中的文件仍保持其原有的 Block Size 例如 Datafile 仍是 2k~32k(默认8k),ASM并不能影响这些东西。

值得一提的是在ASM FILE NUmber 1 的FILEDIR中记录了每一种FILE TYPE对应的BLOCK SIZE,例如:

 

kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            4 ; 0x002: KFBTYP_FILEDIR
kfbh.datfmt:                          1 ; 0x003: 0x01
kfbh.block.blk:                     256 ; 0x004: blk=256
kfbh.block.obj:                       1 ; 0x008: file=1
kfbh.check:                   567282485 ; 0x00c: 0x21d00b35
kfbh.fcn.base:                   220023 ; 0x010: 0x00035b77
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfffdb.node.incarn:           838529807 ; 0x000: A=1 NUMM=0x18fd7987
kfffdb.node.frlist.number:   4294967295 ; 0x004: 0xffffffff
kfffdb.node.frlist.incarn:            0 ; 0x008: A=0 NUMM=0x0
kfffdb.hibytes:                      20 ; 0x00c: 0x00000014
kfffdb.lobytes:                    8192 ; 0x010: 0x00002000
kfffdb.xtntcnt:                   35488 ; 0x014: 0x00008aa0
kfffdb.xtnteof:                   35488 ; 0x018: 0x00008aa0
kfffdb.blkSize:                    8192 ; 0x01c: 0x00002000
kfffdb.flags:                        17 ; 0x020: O=1 S=0 S=0 D=0 C=1 I=0 R=0 A=0
kfffdb.fileType:                      2 ; 0x021: 0x02
kfffdb.dXrs:                         17 ; 0x022: SCHE=0x1 NUMB=0x1
kfffdb.iXrs:                         17 ; 0x023: SCHE=0x1 NUMB=0x1
kfffdb.dXsiz[0]:                  20000 ; 0x024: 0x00004e20

 

这里的kfffdb.blkSize即是 一个数据文件的Block Size。

由于这个blocksize 总是2的次方,所以一个block总是在 一个AU allocation Unit中,而不会跨2个AU。

 

Data Extents

 

数据盘区Data Extents 是裸的存储,用以存放文件内容。每一个Data Extent在 11g之前对应某一个ASM disk上的一个Allocation Unit , 在11g之后 一个Extent可以对应多个AU,具体见《【Oracle ASM】Variable Extent Size 原理》

 

kffxp

 

Extent Map

extent map

Extent Map盘区图是盘区指针的列表,这些指针将支出所有属于一个文件的数据盘区。这些盘区是真正存放数据的裸存储空间。每一个盘区指针给出其所在的磁盘号和AU信息。为了保证可信,每一个盘区指针也会包含一个checksum byte来确认本指针未损坏。当这个checksum值和实际存放的Extent信息不匹配时可能出现ORA-600错误,例如ORA-00600: internal error code, arguments: [kffFdLoadXmap_86], [256], [0], [1], [68], [54], [29], [], [], [], [], []。

 

 Virtual Data Extents

 

虚拟数据盘区 Virtual Data Extent是几个data extent的集合,这些data Extent中包含了相同的数据。 镜像Mirror是在虚拟Extent级别实现的。每一个虚拟extent为文件块提供一个盘区地址空间。每一个写入到文件块均是写入到一个虚拟extent中每一个Online在线的data extent中。 每一个对文件块的读取也是被重定位到一个虚拟extent中的主镜像extent (primary Extent),除非primary extent所在Disk被OFFLINE了。  对于没有冗余度(即external redundancy disk group上的FILE)的文件而言,一个虚拟Extent实际就是一个data Extent。

对于Normal redundancy+普通数据库文件而言, 一个虚拟Extent实际就是2个Data Extent。

对于High redundancy+普通数据库文件而言, 一个虚拟Extent实际就是3个Data Extent。

 

asm file extent

 

粗粒度条带化Coarse Grain Striping

 

粗粒度条带化就是对虚拟data Extent的简单联接。类似于传统卷管理器使用1MB作为stripe size。

 

细粒度条带化Fine Grain Striping

 

细粒度与粗粒度的区别在于,文件块不是线性地布局在每一个虚拟Extent上,而是文件将以1/8个虚拟Extent成长,由此文件块被在diskgroup内以1/8的条带化深度分布。  由此当该文件的block size 为8k,则block 0~15在虚拟Virtual Extent 0上面,而block 16-31 在Vritual Extent 1上面,blocks 112-127在vritual extent 7, block 128-143在block 0-15之后仍在virtual extent 0上。

fine grained striping

 

File Templates

 

File Template文件模板当文件被创建时用以指定 条带化 (coarse 或 FINE) 和冗余度(external, normal, high)。 ORACLE默认已经为每一个ORACLE数据库文件提供了默认模板。可以修改默认模板 也可以客制化模板。修改模板只影响新创建的文件,而不是现有文件。 创建文件时可以指定使用某一个模板。

 

默认的模板如下:

asm file templates

 

 Failure Group

 

ASM提供冗余,failure group用来保证单点错误不会造成同一数据的多份拷贝同时不可用。 如果ASM使用的多个ASM DISK LUN属于同一硬件 例如同一磁盘阵列,该硬件故障会导致这多个盘均不可用,则该硬件的失败应当被容错, 在ASM中一般将这些盘规划到同一个failure group中。多份冗余拷贝不会存放在同一个failure group的磁盘中,换句话说一个failure group中只有一份数据的拷贝,不会有第二份。

由于Failure Group的配置很大程度上与用户的本地规划有关,所以ASM允许用户自己指定Failure group的规划、组成。 但是如果用户自己没有指定Failure Group的规划,那么ASM会自动分配磁盘到必要的Failure Group。

使用External Redundancy的Diskgroup没有Failure Group。Normal redundancy Disk Groups要求至少2个Failure Group,High Redundancy Disk Groups要求3个Failure Group。

如果Normal redundancy Disk Groups中有多于2个的Failure Group,例如 Failure Group A、B、C,则一个Virtual Extent会自动在A、B、C之间找2个Failure Group存放2个mirror extent,不会存放3份拷贝。

High Redundancy Disk Groups与之类似。

实际上,国内对ASM的运行,绝大多数不依赖于ASM实现redundancy,而是使用 External Redundancy的, 在Maclean遇到的场景中External Redundancy占了70%以上。

实际应用中 Normal/High一般会和多个存储控制器Controller 结合来分配failure group,或者存在多路存储可用。

asm failure groups

以下为一个示例, 一个normal redundancy 的Diskgroup 中存在8个Disk,并使用2个Failure Group:

 

stripe and mirror example

 

当磁盘Disk H失败,这个失败要求在失败磁盘上所有的Extent均被修复, Extent 3和5会从现存的拷贝中复制到Failgroup 2 中可用的区域。在此例子中,Extent 5被从Disk A拷贝到Disk F,extent 3从Disk C 拷贝到Disk G,最后还会将失败的磁盘从Diskgroup中drop出去。

 

failure group

 

 

Disk Partners

 

Disk Partnership是一种基于2个磁盘之间的对称关系,存在于high 或 normal的redundancy diskgroup中。Diskgroup中的Disk与同一个Diskgroup内的其他几个disk组成结伴关系。ASM会自动创建和维护这种关系。镜像拷贝数据仅仅在已经与主数据镜像primary data extent组成partners关系的磁盘上分配。

Disk partnering用来减少由于同时2个磁盘故障导致的数据丢失的概率。原因在于当ASM配置中使用了较多的磁盘时(例如上千个),如果如果数据镜像是随机寻找次级磁盘来存放镜像拷贝,当2个磁盘丢失时有较大概率丢失数据。原因是如果采取随机存放镜像数据的话,出现数据的 primary和镜像数据同时存在于2个正好失败的磁盘上的概率是很高的。 如果我们不采取disk partnering,2个磁盘失败所造成的数据丢失的概率大大增加。

Disk partnering策略限制了用来保护某个磁盘数据拷贝的磁盘数目。ASM为一个磁盘限制了disk partners的总数为8。 这个数目越小,则双磁盘同时失败造成数据丢失概率越小。 但是这个数目越小,也会造成其他不便。所以ORACLE  ASM研发团队最终选择了8这个数字。

ASM从本disk所在Failure group之外的FG 中挑选partners disk,由于一个ASM DISK有多个partners,所以其多个partners disk可能有的在同一个failure Group中。Partners被尽可能多的选择在不同的Failure Group中,这样做的目的也很明确,提高磁盘失败时的容错能力。askmac.cn

如果一个ASM DISK失败了,其保护的extents可以通过其partners来重建。由于有多个partners所以其额外的I/O负载是在多个ASM disk中均衡损耗的。 这减少了修复故障的失败时间,因为更多的磁盘参与进来,可以获得更高的I/O吞吐量,所以加快了重构丢失数据镜像的速度。Partners被尽可能多的选择在不同的Failure Group中,这样做可以让重建丢失磁盘的负载均匀分布在尽可能多的硬盘资源上。   以上这些考虑均是基于同时不会有2个failgroup同时失败这个前提假设。

 

注意Partnering不是分区partitioning,Partnering仅仅是一种对称关系。如果Disk A将Disk B列出partner,则相对地Disk B也将Disk A列为partner。 但是partnering不是一种临时的关系。  同时假设disk A 和 Disk B是partners, 而Disk B和Disk C也是partners,  但这并不代表A和C是partners。

 

 

实际如果对partnering relationship有足够的传递性则可能表现为分区,如下图中的例子。但是分区仅仅是partnering可以提供的一种可能性。

partitioning分区仅仅是Partnering的特殊表现,Partnering本身已经能够保证在Disk磁盘以不规则的几何安排方式组织时仍能同一负载均衡,其移除了当额外的容量需要增加到现有系统时的许多限制。当然这仍不能保证在所有配置下都很完美,但ASM会基于现有给定的配置采取最佳的方案。

 

 

下面为一个Partning的例子:

 

partnering

ASM mirror 保护
ASM mirror 镜像保护可避免因丢失个别磁盘而丢失数据。每一个文件均有自己的ASM镜像策略属性, 对于该文件所辖的所有virtual extent来说同样基于该镜像策略。文件创建时会设置这个镜像策略属性,今后都无法修改。 ASM镜像要比操作系统镜像磁盘要来的灵活一些,至少它可以在文件级别指定需要的冗余度。

ASM mirror区分镜像extent的primary和secondary拷贝,但在更新extent时会同时写所有的拷贝镜像。 ASM总是先尝试读取primary 拷贝,仅当primary拷贝不可用时去读取secondary拷贝。

 

 

 

ASM metadata

 

Asm Metadata是存在于ASM disk header用以存放ASM Diskgroup 控制信息的数据,Metadata包括了该磁盘组中有哪些磁盘,多少可用的空间,其中存放的File的名字,一个文件有哪些Extent等等信息。

由于Asm metadata就存放在ASM DISK HEADER,所以ASM disk group是自解释的。所有的metadata元数据均存放在一个个metadata block中(默认block size 4096)。这些信息包括该metadata block的类型以及其逻辑位置。同样有checksum信息来确认block是否被损坏。所有的metadata block均是4k大小。实际使用时ASM实例会缓存这些ASm metadata。askmac.cn

 

ASM Instance

ASM instance的主要任务之一就是管理ASM metadata元数据; ASM Instance类似于ORACLE RDBMS INSTANCE 有其SGA和大多数主要后台进程。在10.2中使用与RDBMS一样的2进制软件,到11.2中分家。但ASM instance加载的不是数据库,而是Disk Group; 并负责告诉RDBMS database instance必要的ASM 文件信息。  ASM实例和DB实例均需要访问ASM DISK。 ASM实例管理metadata元数据,这些元数据信息足以描述ASM 中的FILE的信息。  数据库实例仍旧直接访问文件,虽然它需要通过ASM实例来获得例如 文件Extent Map 盘区图等信息,但I/O仍由其自行完成,而不是说使用了ASM之后DB的文件I/O需要通过ASM来实现; 其仅仅是与ASM instance交互来获得文件位置、状态等信息。

 

有一些操作需要ASM实例介入处理,例如DB实例需要创建一个数据文件,则数据库服务进程直接连接到ASM实例来实现一些操作; 每一个数据库维护一个连接池到其ASM实例,来避免文件操作导致的反复连接。

ASM metadata通过一个独立的ASM实例来管理以便减少其被损坏的可能。ASM instance很相似于db instance,虽然它一般只使用ORACLE KERNEL内核的一小部分代码,则其遇到bug或导致buffer cache讹误或者写出讹误到磁盘的概率由此比DB实例要小。 数据库实例自己从来不更新ASM metadata。ASM metadata中每一个指针一般都有check byte以便验证。

和DB RAC一样,ASM instance 自己可以被集群化,一样是使用ORACLE Distributed Lock Manager(DLM)分布式锁管理器架构。在一个集群中每一个节点上可以有一个ASM instance。如果一个节点上有多个数据库、多个实例,则他们共享使用一个ASM instance 。

 

如果一个节点上的ASM instance失败了,则所有使用该ASM instance 均会失败。但其他节点上的ASM和数据库实例将做recover并继续操作。

 

oracle asm IO layer

 

 

asm versus raw device

 

Disk Discovery

 

Disk Discovery磁盘发现是指从OS层面找到那些ASM值得访问的磁盘。也用来找到那些需要被mount的diskgroup名下的磁盘ASM DISK,以及管理员希望将其加入到diskgroup中的Disk,或管理员会考虑将其加入到diskgroup的Disk。Discovery 使用一个discovery string( asm_diskstring)作为输入参数,并返回一系列可能的DISK。注意一个是要指定asm_diskstring,另一个是要求这些disk的权限可以被oracle/grid用户使用。精确的asm_diskstring discovery语法取决于操作系统平台和ASMLIB库。OS可接受的路径名生成的匹配,一般对于discovery strings也是可用的。一般推荐这个路径名下最好只有ASM Disk,来避免管理上的问题。

ASM实例会打开和读取由asm_diskstring指定的路径名匹配到的每一个文件并读取前4k的block, 这样做的目的是判断disk header的状态;如果它发现这是一个ASM disk header则会认为这是一个可以mount的diskgroup的一部分。如果发现这4k的block其无法识别,则认为该disk可以加入到ASM diskgroup中(candidate)。

 

ASM实例需要通过一个初始化参数来指定这个discovery strings,实际就是asm_diskstring; 注意 asm_diskstring中可以加入多个路径字符串,例如 ‘/dev/raw*’,’/dev/asm-disk*’ ; 同样的磁盘不会被发现2次(除非你欺骗ASM)。 在RAC cluster中如果一个磁盘不是在整个cluster范围内都可见,那么这个磁盘无法被加入到RAC的ASM DISKGROUP 中。  在实际使用中每一个节点上的磁盘名字可以不一样,但其实际介质要被操作系统识别,但是实际MACLEAN也强烈建议你保持每个节点上磁盘的名字一样,否则管理很麻烦。 所以这里引入UDEV等规则是有必要的。

 

 

Disk Group Mount  加载磁盘组

在数据库实例可以用Diskgroup上的文件之前,需要ASM实例去 mount 这个本地diskgroup。 Mount Diskgroup牵扯到发现所有的磁盘并找到上面已经有metadata数据的disk,并尝试将对应到一个diskgroup的DISK mount起来。 能 mount起来的前提还需要验证metadata来确保现在已经有足够数量的磁盘在哪里,例如使用3个DISK创建的external diskgroup ,当前OS下面只挂了2个Disk,则显然不能mount这个diskgroup。 之后还需要初始化SGA以便之后更新和管理这些metadata。

可以显示地去dismount一个diskgroup,但是如果diskgroup上的文件正在被client (例如DB)使用则dismount会报错。如果在ASM冗余算法容错能力内丢失磁盘,则不会导致diskgroup被强制dismount。但是如果超出了容错能力则会被强制dismount。 这种强制dismount会导致使用其上文件的DB instance被kill。

 

Disk ADD 增加磁盘

 

加入一个磁盘到现有的Diskgroup 来扩空间和增加吞吐量是很常见的需求。最简单的加入磁盘命令如 : alter diskgroup Data add disk ‘/dev/asm-disk5’; 如前文所述在RAC cluster中如果一个磁盘不是在整个cluster范围内都可见,那么这个磁盘无法被加入到RAC的ASM DISKGROUP 中。

如果add disk指定的磁盘的disk header发现了其他diskgroup的信息或者操作系统的一些信息,则需要alter diskgroup Data add disk ‘/dev/asm-disk5’ force ; 加入FORCE选项。实际使用中尽可能避免使用FORCE选项。

需要注意的事add disk命令返回后只代表disk header已经完成必要的metadata写入,但不代表该磁盘已经完成了rebalance操作。后续的rebalance会被引发并移动数据到新加入的磁盘中。一般推荐如果你要加入多个ASM DISK,那么在同一时间加入,而不是分多次加入。  但是一般不推荐同时做add disk和drop disk。

 

 

 

asmdisk1

 

Disk Drop踢盘

 

可以从现有的Diskgroup里drop出disk,这些disk可以用作它途;当然由于asm disk失败,导致ASM实例自动drop 该失败的asm disk也是常见的。若一个ASM DISK常发生一些非致命的错误,则一般推荐将该Disk drop出来,以避免如果某天发生真的磁盘失败导致可能的数据丢失。 但是需要注意drop disk时 不要指定其路径名,而是指定ASM DISK NAME。

drop disk命令可能较短时间内返回,但是diskgroup必须完成rebalance后这个磁盘才能被挪作他用。rebalance将读取即将被drop掉disk的数据,并拷贝这些数据到其他磁盘上。FORCE选项可以用于避免读取该正被drop的磁盘。该FORCE选项当磁盘发生失败或磁盘确实需要立即被挪用。原来那些需要被拷贝的extent,使用FORCE选项后会从冗余的备份中读取,所以external redundancy不支持使用FORCE选项。当然如果使用FORCE选项最后会导致在NORMAL/HIGH冗余的Diskgroup下造成数据丢失的话,则FORCE选项也将不可用。

 

DROP DISK NOFORCE:

drop disk noforce

DROP DISK FORCE:

drop disk force

 

对磁盘的写入如果发生了严重的错误那么也会导致ASM自动强制去DROP该Disk。如果该disk的drop会造成数据丢失,那么diskgroup被强制dismount,该dismount也会造成数据库实例被kill。

asm可靠性

Rebalance

rebalance diskgroup将在diskgroup范围内将数据在其DISK上移动,以保证文件们均匀分布在diskgroup中的所有磁盘上,同时也会考虑到每一个ASM DISK的大小。 当文件均匀地分布在所有磁盘上,则各个磁盘的使用量也会很接近。如此以保证负载均衡。rebalance的算法既不基于I/O统计信息也不基于其他统计结果; 完全取决于Diskgroup中disk的大小。

一旦diskgroup中发生了一些存储配置变化 例如disk add/drop/resize均会自动触发一次rebalance。power参数将决定有多少slave进程并发参数数据移动。所有的slave进程均从发生rebalance的实力启动并工作。rebalance可以手动调控,即便已经在进行一次rebalance中了,也可以指定其他节点上的实例做rebalance,只要管路员想要这样做。如果实例意外crash,那么未结束的rebalance将自动重新启动。

注意rebalance中的每一次extent 移动均会与数据库实例做协调,因为数据库实例可能同时需要读取或者写这个 extent,所以数据库在rebalance 同时能正常工作。 其对数据库的影响一般较小,原因是同一时间只有一个extent被锁定以便移动,且仅仅是阻塞写入。

 

rebalance

 

 ASMLIB

ASMLIB是通过在Linux上安装asmlib包来提供标准I/O接口,以便ASM发现和访问ASM disk。 关于ASMLIB详见:

关于udev与asmlib 以及Multipath的问题,提问前先看这个

 

 

Disk Header

 

一个ASM DISK的最前面4096字节为disk header,对于ASM而言是block 0 (blkn=0);许多操作系统会保留LUN的第一个block来存放分区表或其他OS信息。 一般不让ASM基础到这个block,因为ASM会毫不犹豫地覆盖这个block。在一些指定的平台上ORACLE从代码层跳过这些操作系统块,但实际操作时一般的惯例是只给ASM用那些上面没有分区表的LUN DISK。

对于这一点详细的展开是,例如你在AIX操作系统上使用PV作为ASM DISK,则PV上不能有PVID,同时如果一个PV已经分给ASM用了,但是由于系统管理员的疏忽而给PV分配了一个PVID,则该PV 头部的ASM disk header会被覆盖掉,这将直接导致disk header丢失;如果是External Redundancy那么这个diskgroup就直接mount不起来了。所以对那些会影响ASM disk header的操作要慎之又慎,同时最好定期备份disk header。

ASM disk header描述了该ASM disk和diskgroup的属性,通过对现有disk header的加载,ASM实例可以知道这个diskgroup的整体信息。

下面是一个典型的disk header的一部分, 其disk number为0 ,redundancy为KFDGTP_HIGH,diskname为DATA1_0000,diskgroup name 为DATA1,failgroup name为DATA1_0000:

 

kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            1 ; 0x002: KFBTYP_DISKHEAD
kfbh.datfmt:                          1 ; 0x003: 0x01
kfbh.block.blk:                       0 ; 0x004: blk=0
kfbh.block.obj:              2147483648 ; 0x008: disk=0
kfbh.check:                  3107059325 ; 0x00c: 0xb931f67d
kfbh.fcn.base:                        0 ; 0x010: 0x00000000
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdhdb.driver.provstr:         ORCLDISK ; 0x000: length=8
kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000
kfdhdb.driver.reserved[1]:            0 ; 0x00c: 0x00000000
kfdhdb.driver.reserved[2]:            0 ; 0x010: 0x00000000
kfdhdb.driver.reserved[3]:            0 ; 0x014: 0x00000000
kfdhdb.driver.reserved[4]:            0 ; 0x018: 0x00000000
kfdhdb.driver.reserved[5]:            0 ; 0x01c: 0x00000000
kfdhdb.compat:                186646528 ; 0x020: 0x0b200000
kfdhdb.dsknum:                        0 ; 0x024: 0x0000
kfdhdb.grptyp:                        3 ; 0x026: KFDGTP_HIGH
kfdhdb.hdrsts:                        3 ; 0x027: KFDHDR_MEMBER
kfdhdb.dskname:              DATA1_0000 ; 0x028: length=10
kfdhdb.grpname:                   DATA1 ; 0x048: length=5
kfdhdb.fgname:               DATA1_0000 ; 0x068: length=10
kfdhdb.capname:                         ; 0x088: length=0
kfdhdb.crestmp.hi:             32999670 ; 0x0a8: HOUR=0x16 DAYS=0x7 MNTH=0x2 YEAR=0x7de
kfdhdb.crestmp.lo:           1788720128 ; 0x0ac: USEC=0x0 MSEC=0x36d SECS=0x29 MINS=0x1a
kfdhdb.mntstmp.hi:             32999670 ; 0x0b0: HOUR=0x16 DAYS=0x7 MNTH=0x2 YEAR=0x7de
kfdhdb.mntstmp.lo:           1812990976 ; 0x0b4: USEC=0x0 MSEC=0x3 SECS=0x1 MINS=0x1b
kfdhdb.secsize:                     512 ; 0x0b8: 0x0200
kfdhdb.blksize:                    4096 ; 0x0ba: 0x1000
kfdhdb.ausize:                  4194304 ; 0x0bc: 0x00400000
kfdhdb.mfact:                    454272 ; 0x0c0: 0x0006ee80
kfdhdb.dsksize:                   32375 ; 0x0c4: 0x00007e77
kfdhdb.pmcnt:                         2 ; 0x0c8: 0x00000002
kfdhdb.fstlocn:                       1 ; 0x0cc: 0x00000001
kfdhdb.altlocn:                       2 ; 0x0d0: 0x00000002
kfdhdb.f1b1locn:                      2 ; 0x0d4: 0x00000002
kfdhdb.redomirrors[0]:                0 ; 0x0d8: 0x0000
kfdhdb.redomirrors[1]:                0 ; 0x0da: 0x0000
kfdhdb.redomirrors[2]:                0 ; 0x0dc: 0x0000
kfdhdb.redomirrors[3]:                0 ; 0x0de: 0x0000
kfdhdb.dbcompat:              186646528 ; 0x0e0: 0x0b200000
kfdhdb.grpstmp.hi:             32999670 ; 0x0e4: HOUR=0x16 DAYS=0x7 MNTH=0x2 YEAR=0x7de
kfdhdb.grpstmp.lo:           1783335936 ; 0x0e8: USEC=0x0 MSEC=0x2e3 SECS=0x24 MINS=0x1a
kfdhdb.vfstart:                       0 ; 0x0ec: 0x00000000
kfdhdb.vfend:                         0 ; 0x0f0: 0x00000000
kfdhdb.spfile:                        0 ; 0x0f4: 0x00000000
kfdhdb.spfflg:                        0 ; 0x0f8: 0x00000000
kfdhdb.ub4spare[0]:                   0 ; 0x0fc: 0x00000000
kfdhdb.ub4spare[1]:                   0 ; 0x100: 0x00000000
kfdhdb.ub4spare[2]:                   0 ; 0x104: 0x00000000
kfdhdb.ub4spare[3]:                   0 ; 0x108: 0x00000000

 

下面的信息是在同一个diskgroup中的所有disk的header上均会复制一份的:

  • Disk group name and creation timestamp
  • Physical sector size of all disks in the disk group
  • Allocation unit size
  • Metadata block size
  • Software version compatibility
  • Default redundancy
  • Mount timestamp

 

下面的信息是每一个asm disk独有的:

  • ASM disk name (not OS path name)
  • Disk number within disk group
  • Failure group name
  • Disk size in allocation units

 

 

Freespace Table

 

AU=0 的blkn=1 包含的是free space table;其中包含了该AU中allocation table中每一个block上大致的可用剩余FREE SPACE可用空间信息。通过参考free space table可以避免在已经分配完的allocation table中查找空间。

 

[oracle@mlab2 dbs]$ kfed read /oracleasm/asm-disk01 blkn=1 aun=0 aus=4194304|less 
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            2 ; 0x002: KFBTYP_FREESPC
kfbh.datfmt:                          2 ; 0x003: 0x02
kfbh.block.blk:                       1 ; 0x004: blk=1
kfbh.block.obj:              2147483648 ; 0x008: disk=0
kfbh.check:                  3847932395 ; 0x00c: 0xe55ac9eb
kfbh.fcn.base:                    22557 ; 0x010: 0x0000581d
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdfsb.aunum:                         0 ; 0x000: 0x00000000
kfdfsb.max:                        1014 ; 0x004: 0x03f6
kfdfsb.cnt:                          73 ; 0x006: 0x0049
kfdfsb.bound:                         0 ; 0x008: 0x0000
kfdfsb.flag:                          1 ; 0x00a: B=1
kfdfsb.ub1spare:                      0 ; 0x00b: 0x00
kfdfsb.spare[0]:                      0 ; 0x00c: 0x00000000
kfdfsb.spare[1]:                      0 ; 0x010: 0x00000000
kfdfsb.spare[2]:                      0 ; 0x014: 0x00000000
kfdfse[0].fse:                        0 ; 0x018: FREE=0x0 FRAG=0x0
kfdfse[1].fse:                        0 ; 0x019: FREE=0x0 FRAG=0x0
kfdfse[2].fse:                        0 ; 0x01a: FREE=0x0 FRAG=0x0
kfdfse[3].fse:                        0 ; 0x01b: FREE=0x0 FRAG=0x0
kfdfse[4].fse:                        0 ; 0x01c: FREE=0x0 FRAG=0x0
kfdfse[5].fse:                        0 ; 0x01d: FREE=0x0 FRAG=0x0
kfdfse[6].fse:                        0 ; 0x01e: FREE=0x0 FRAG=0x0
kfdfse[7].fse:                        0 ; 0x01f: FREE=0x0 FRAG=0x0
kfdfse[8].fse:                        0 ; 0x020: FREE=0x0 FRAG=0x0
kfdfse[9].fse:                        0 ; 0x021: FREE=0x0 FRAG=0x0
kfdfse[10].fse:                       0 ; 0x022: FREE=0x0 FRAG=0x0
kfdfse[11].fse:                     119 ; 0x023: FREE=0x7 FRAG=0x7
kfdfse[12].fse:                      16 ; 0x024: FREE=0x0 FRAG=0x1
kfdfse[13].fse:                      16 ; 0x025: FREE=0x0 FRAG=0x1
kfdfse[14].fse:                      16 ; 0x026: FREE=0x0 FRAG=0x1
kfdfse[15].fse:                      16 ; 0x027: FREE=0x0 FRAG=0x1
kfdfse[16].fse:                      16 ; 0x028: FREE=0x0 FRAG=0x1
kfdfse[17].fse:                      16 ; 0x029: FREE=0x0 FRAG=0x1
kfdfse[18].fse:                      16 ; 0x02a: FREE=0x0 FRAG=0x1
kfdfse[19].fse:                      16 ; 0x02b: FREE=0x0 FRAG=0x1
kfdfse[20].fse:                      16 ; 0x02c: FREE=0x0 FRAG=0x1
kfdfse[21].fse:                      16 ; 0x02d: FREE=0x0 FRAG=0x1
kfdfse[22].fse:                      16 ; 0x02e: FREE=0x0 FRAG=0x1
kfdfse[23].fse:                      16 ; 0x02f: FREE=0x0 FRAG=0x1
kfdfse[24].fse:                      16 ; 0x030: FREE=0x0 FRAG=0x1
kfdfse[25].fse:                      16 ; 0x031: FREE=0x0 FRAG=0x1
kfdfse[26].fse:                      16 ; 0x032: FREE=0x0 FRAG=0x1
kfdfse[27].fse:                      16 ; 0x033: FREE=0x0 FRAG=0x1
kfdfse[28].fse:                      16 ; 0x034: FREE=0x0 FRAG=0x1

 

aunum_kfdfsb  First AU of first ATB of this FSB
max_kfdfsb  Max number of FSEs per FSB
cnt_kfdfsb  Number of FSEs up to end of disk
spare_kfdfsb  spares for future

kfdfse – Kernel Files Disk Free Space Entry.

max_kfdfsb describes the number of free space entries which would
be used in this free space table if the disk were large enough to
provide all of the AUs which can be described by a single physical
metadata AU.  cnt_kfdfsb describes the number of free space entries
which correspond to AUs which are actually present on the disk.  In
the case where there are additional physical metadata AUs beyond the
one containing this kfdfsb, then max_kfdfsb will equal cnt_kfdfsb.

There are complications with the interpretation of cnt_kfdfsb when
a disk is being grown or shrunk.  It is possible in these cases to
have allocated AUs past the range indicated by cnt_kfdfsb which have
not yet been relocated into the new area of the disk.

The Free Space Table provides a summary of which allocation table
blocks have free space.  There is one kfdfse in the FST for each
Allocation Table block described by the FST.
The first key parameter is the stripe width of the array. Stripe width refers to the number of parallel stripes that can be written to or read from simultaneously. This is of course equal to the number of disks in the array. So a four-disk striped array would have a stripe width of four.

 

 Allocation Table

 

Aun=0的后254个metadata block用以存放AU分配信息。 每一个metadata描述448个AU的状态, 如果一个AU已经分配给一个文件,则allocation table 记录其ASM文件号和data extent号。对于还是FREE的AU则被link到free list上。

 

 

kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            3 ; 0x002: KFBTYP_ALLOCTBL
kfbh.datfmt:                          2 ; 0x003: 0x02
kfbh.block.blk:                       2 ; 0x004: blk=2
kfbh.block.obj:              2147483648 ; 0x008: disk=0
kfbh.check:                  2376540464 ; 0x00c: 0x8da72130
kfbh.fcn.base:                    44495 ; 0x010: 0x0000adcf
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdatb.aunum:                         0 ; 0x000: 0x00000000
kfdatb.shrink:                      448 ; 0x004: 0x01c0
kfdatb.ub2pad:                        0 ; 0x006: 0x0000
kfdatb.auinfo[0].link.next:         112 ; 0x008: 0x0070
kfdatb.auinfo[0].link.prev:         112 ; 0x00a: 0x0070
kfdatb.auinfo[1].link.next:         120 ; 0x00c: 0x0078
kfdatb.auinfo[1].link.prev:         120 ; 0x00e: 0x0078
kfdatb.auinfo[2].link.next:         136 ; 0x010: 0x0088
kfdatb.auinfo[2].link.prev:         136 ; 0x012: 0x0088
kfdatb.auinfo[3].link.next:          20 ; 0x014: 0x0014
kfdatb.auinfo[3].link.prev:          20 ; 0x016: 0x0014
kfdatb.auinfo[4].link.next:         168 ; 0x018: 0x00a8
kfdatb.auinfo[4].link.prev:         168 ; 0x01a: 0x00a8
kfdatb.auinfo[5].link.next:         296 ; 0x01c: 0x0128
kfdatb.auinfo[5].link.prev:         296 ; 0x01e: 0x0128
kfdatb.auinfo[6].link.next:         552 ; 0x020: 0x0228
kfdatb.auinfo[6].link.prev:        3112 ; 0x022: 0x0c28
kfdatb.spare:                         0 ; 0x024: 0x00000000
kfdate[0].discriminator:              1 ; 0x028: 0x00000001
kfdate[0].allo.lo:                    0 ; 0x028: XNUM=0x0
kfdate[0].allo.hi:              8388608 ; 0x02c: V=1 I=0 H=0 FNUM=0x0
kfdate[1].discriminator:              1 ; 0x030: 0x00000001
kfdate[1].allo.lo:                    0 ; 0x030: XNUM=0x0
kfdate[1].allo.hi:              8388608 ; 0x034: V=1 I=0 H=0 FNUM=0x0
kfdate[2].discriminator:              1 ; 0x038: 0x00000001
kfdate[2].allo.lo:                    0 ; 0x038: XNUM=0x0
kfdate[2].allo.hi:              8388609 ; 0x03c: V=1 I=0 H=0 FNUM=0x1
kfdate[3].discriminator:              1 ; 0x040: 0x00000001
kfdate[3].allo.lo:                    8 ; 0x040: XNUM=0x8
kfdate[3].allo.hi:              8388611 ; 0x044: V=1 I=0 H=0 FNUM=0x3
kfdate[4].discriminator:              1 ; 0x048: 0x00000001
kfdate[4].allo.lo:                   19 ; 0x048: XNUM=0x13
kfdate[4].allo.hi:              8388611 ; 0x04c: V=1 I=0 H=0 FNUM=0x3
kfdate[5].discriminator:              1 ; 0x050: 0x00000001
kfdate[5].allo.lo:                   29 ; 0x050: XNUM=0x1d
kfdate[5].allo.hi:              8388611 ; 0x054: V=1 I=0 H=0 FNUM=0x3
kfdate[6].discriminator:              1 ; 0x058: 0x00000001
kfdate[6].allo.lo:                   30 ; 0x058: XNUM=0x1e
kfdate[6].allo.hi:              8388611 ; 0x05c: V=1 I=0 H=0 FNUM=0x3
kfdate[7].discriminator:              1 ; 0x060: 0x00000001
kfdate[7].allo.lo:                    0 ; 0x060: XNUM=0x0
kfdate[7].allo.hi:              8388612 ; 0x064: V=1 I=0 H=0 FNUM=0x4
kfdate[8].discriminator:              1 ; 0x068: 0x00000001

 

 

Partner and Status Table

 

一般来说aun=1 是保留给Partner and Status Table(PST)的拷贝使用的。 一般5个ASM DISK将包含一份PST拷贝。多数的PST内容必须相同且验证有效。否则无法判断哪些ASM DISK实际拥有相关数据。

在 PST中每一条记录对应Diskgroup中的一个ASM DISK。每一条记录会对一个ASM disk枚举其partners的ASM DISK。同时会有一个flag来表示该DISK是否是ONLINE可读写的。这些信息对recovery是否能做很重要。

PST表的Blkn=0是PST的header,存放了如下的信息:

  • Timestamp to indicate PST is valid
  • Version number to compare with other PST copies
  • List of disks containing PST copies
  • Bit map for shadow paging updates

PST的最后一个块是heartbeat block,当diskgroup mount时其每3秒心跳更新一次。

 

以下为PST header

kfed read /oracleasm/asm-disk01 aun=1 blkn=0 aus=4194304 |less 

kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                           17 ; 0x002: KFBTYP_PST_META
kfbh.datfmt:                          2 ; 0x003: 0x02
kfbh.block.blk:                    1024 ; 0x004: blk=1024
kfbh.block.obj:              2147483648 ; 0x008: disk=0
kfbh.check:                  3813974007 ; 0x00c: 0xe3549ff7
kfbh.fcn.base:                        0 ; 0x010: 0x00000000
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdpHdrPairBv1.first.super.time.hi:32999670 ; 0x000: HOUR=0x16 DAYS=0x7 MNTH=0x2 YEAR=0x7de
kfdpHdrPairBv1.first.super.time.lo:1788841984 ; 0x004: USEC=0x0 MSEC=0x3e4 SECS=0x29 MINS=0x1a
kfdpHdrPairBv1.first.super.last:      2 ; 0x008: 0x00000002
kfdpHdrPairBv1.first.super.next:      2 ; 0x00c: 0x00000002
kfdpHdrPairBv1.first.super.copyCnt:   5 ; 0x010: 0x05
kfdpHdrPairBv1.first.super.version:   1 ; 0x011: 0x01
kfdpHdrPairBv1.first.super.ub2spare:  0 ; 0x012: 0x0000
kfdpHdrPairBv1.first.super.incarn:    1 ; 0x014: 0x00000001
kfdpHdrPairBv1.first.super.copy[0]:   0 ; 0x018: 0x0000
kfdpHdrPairBv1.first.super.copy[1]:   1 ; 0x01a: 0x0001
kfdpHdrPairBv1.first.super.copy[2]:   2 ; 0x01c: 0x0002
kfdpHdrPairBv1.first.super.copy[3]:   3 ; 0x01e: 0x0003
kfdpHdrPairBv1.first.super.copy[4]:   4 ; 0x020: 0x0004
kfdpHdrPairBv1.first.super.dtaSz:    15 ; 0x022: 0x000f
kfdpHdrPairBv1.first.asmCompat:186646528 ; 0x024: 0x0b200000
kfdpHdrPairBv1.first.newCopy[0]:      0 ; 0x028: 0x0000
kfdpHdrPairBv1.first.newCopy[1]:      0 ; 0x02a: 0x0000
kfdpHdrPairBv1.first.newCopy[2]:      0 ; 0x02c: 0x0000
kfdpHdrPairBv1.first.newCopy[3]:      0 ; 0x02e: 0x0000
kfdpHdrPairBv1.first.newCopy[4]:      0 ; 0x030: 0x0000
kfdpHdrPairBv1.first.newCopyCnt:      0 ; 0x032: 0x00
kfdpHdrPairBv1.first.contType:        1 ; 0x033: 0x01
kfdpHdrPairBv1.first.spares[0]:       0 ; 0x034: 0x00000000
kfdpHdrPairBv1.first.spares[1]:       0 ; 0x038: 0x00000000
kfdpHdrPairBv1.first.spares[2]:       0 ; 0x03c: 0x00000000
kfdpHdrPairBv1.first.spares[3]:       0 ; 0x040: 0x00000000
kfdpHdrPairBv1.first.spares[4]:       0 ; 0x044: 0x00000000
kfdpHdrPairBv1.first.spares[5]:       0 ; 0x048: 0x00000000
kfdpHdrPairBv1.first.spares[6]:       0 ; 0x04c: 0x00000000
kfdpHdrPairBv1.first.spares[7]:       0 ; 0x050: 0x00000000
kfdpHdrPairBv1.first.spares[8]:       0 ; 0x054: 0x00000000
kfdpHdrPairBv1.first.spares[9]:       0 ; 0x058: 0x00000000
kfdpHdrPairBv1.first.spares[10]:      0 ; 0x05c: 0x00000000
kfdpHdrPairBv1.first.spares[11]:      0 ; 0x060: 0x00000000
kfdpHdrPairBv1.first.spares[12]:      0 ; 0x064: 0x00000000
kfdpHdrPairBv1.first.spares[13]:      0 ; 0x068: 0x00000000
kfdpHdrPairBv1.first.spares[14]:      0 ; 0x06c: 0x00000000
kfdpHdrPairBv1.first.spares[15]:      0 ; 0x070: 0x00000000
kfdpHdrPairBv1.first.spares[16]:      0 ; 0x074: 0x00000000
kfdpHdrPairBv1.first.spares[17]:      0 ; 0x078: 0x00000000
kfdpHdrPairBv1.first.spares[18]:      0 ; 0x07c: 0x00000000
kfdpHdrPairBv1.first.spares[19]:      0 ; 0x080: 0x00000000

 

  • super.time wall clock time of last PST commit
  • super.last  last committed content version number
  • super.next next available content version number
  • super.copyCnt  # of disks holding PST copies
  • super.version   version of PST header format
  • super.ub2spare  pad to ub4 align
  • super.incarn incarnation of <copy> list
  • super.copy[0]  disks holding the PST copies
  • super.dtaSz  data entries in PST
  • newCopy[0]   new disks holding PST copies
  • newCopyCnt  new # disks holding PST copies

 

以下为PST table block:

 

kfed read /oracleasm/asm-disk02 aun=1 blkn=3 aus=4194304 |less 

kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                           18 ; 0x002: KFBTYP_PST_DTA
kfbh.datfmt:                          2 ; 0x003: 0x02
kfbh.block.blk:                    1027 ; 0x004: blk=1027
kfbh.block.obj:              2147483649 ; 0x008: disk=1
kfbh.check:                  4204644293 ; 0x00c: 0xfa9dc7c5
kfbh.fcn.base:                        0 ; 0x010: 0x00000000
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdpDtaEv1[0].status:               127 ; 0x000: I=1 V=1 V=1 P=1 P=1 A=1 D=1
kfdpDtaEv1[0].fgNum:                  1 ; 0x002: 0x0001
kfdpDtaEv1[0].addTs:         2022663849 ; 0x004: 0x788f66a9
kfdpDtaEv1[0].partner[0]:         49154 ; 0x008: P=1 P=1 PART=0x2
kfdpDtaEv1[0].partner[1]:         49153 ; 0x00a: P=1 P=1 PART=0x1
kfdpDtaEv1[0].partner[2]:         49155 ; 0x00c: P=1 P=1 PART=0x3
kfdpDtaEv1[0].partner[3]:         49166 ; 0x00e: P=1 P=1 PART=0xe
kfdpDtaEv1[0].partner[4]:         49165 ; 0x010: P=1 P=1 PART=0xd
kfdpDtaEv1[0].partner[5]:         49164 ; 0x012: P=1 P=1 PART=0xc
kfdpDtaEv1[0].partner[6]:         49156 ; 0x014: P=1 P=1 PART=0x4
kfdpDtaEv1[0].partner[7]:         49163 ; 0x016: P=1 P=1 PART=0xb
kfdpDtaEv1[0].partner[8]:         10000 ; 0x018: P=0 P=0 PART=0x2710
kfdpDtaEv1[0].partner[9]:             0 ; 0x01a: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[10]:            0 ; 0x01c: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[11]:            0 ; 0x01e: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[12]:            0 ; 0x020: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[13]:            0 ; 0x022: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[14]:            0 ; 0x024: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[15]:            0 ; 0x026: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[16]:            0 ; 0x028: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[17]:            0 ; 0x02a: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[18]:            0 ; 0x02c: P=0 P=0 PART=0x0
kfdpDtaEv1[0].partner[19]:            0 ; 0x02e: P=0 P=0 PART=0x0
kfdpDtaEv1[1].status:               127 ; 0x030: I=1 V=1 V=1 P=1 P=1 A=1 D=1
kfdpDtaEv1[1].fgNum:                  2 ; 0x032: 0x0002
kfdpDtaEv1[1].addTs:         2022663849 ; 0x034: 0x788f66a9
kfdpDtaEv1[1].partner[0]:         49155 ; 0x038: P=1 P=1 PART=0x3
kfdpDtaEv1[1].partner[1]:         49152 ; 0x03a: P=1 P=1 PART=0x0
kfdpDtaEv1[1].partner[2]:         49154 ; 0x03c: P=1 P=1 PART=0x2
kfdpDtaEv1[1].partner[3]:         49166 ; 0x03e: P=1 P=1 PART=0xe
kfdpDtaEv1[1].partner[4]:         49157 ; 0x040: P=1 P=1 PART=0x5
kfdpDtaEv1[1].partner[5]:         49156 ; 0x042: P=1 P=1 PART=0x4
kfdpDtaEv1[1].partner[6]:         49165 ; 0x044: P=1 P=1 PART=0xd
kfdpDtaEv1[1].partner[7]:         49164 ; 0x046: P=1 P=1 PART=0xc
kfdpDtaEv1[1].partner[8]:         10000 ; 0x048: P=0 P=0 PART=0x2710
kfdpDtaEv1[1].partner[9]:             0 ; 0x04a: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[10]:            0 ; 0x04c: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[11]:            0 ; 0x04e: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[12]:            0 ; 0x050: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[13]:            0 ; 0x052: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[14]:            0 ; 0x054: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[15]:            0 ; 0x056: P=0 P=0 PART=0x0
kfdpDtaEv1[1].partner[16]:            0 ; 0x058: P=0 P=0 PART=0x0

 

 

  • kfdpDtaEv1[0].status: 127 ; 0x000: I=1 V=1 V=1 P=1 P=1 A=1 D=1 disk status
  • fgNum   fail group number
  • addTs   timestamp of the addition to the diskgroup
  • kfdpDtaEv1[0].partner[0]:         49154 ; 0x008: P=1 P=1 PART=0x2  partner list

 

aun=1 的最后第二个block中备份了一份KFBTYP_DISKHEAD

 

[oracle@mlab2 hzy]$ kfed read /oracleasm/asm-disk02 aun=1 blkn=1022 aus=4194304 |less  
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                            1 ; 0x002: KFBTYP_DISKHEAD
kfbh.datfmt:                          1 ; 0x003: 0x01
kfbh.block.blk:                    1022 ; 0x004: blk=1022
kfbh.block.obj:              2147483649 ; 0x008: disk=1
kfbh.check:                  3107059260 ; 0x00c: 0xb931f63c
kfbh.fcn.base:                        0 ; 0x010: 0x00000000
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdhdb.driver.provstr:         ORCLDISK ; 0x000: length=8
kfdhdb.driver.reserved[0]:            0 ; 0x008: 0x00000000
kfdhdb.driver.reserved[1]:            0 ; 0x00c: 0x00000000
kfdhdb.driver.reserved[2]:            0 ; 0x010: 0x00000000
kfdhdb.driver.reserved[3]:            0 ; 0x014: 0x00000000
kfdhdb.driver.reserved[4]:            0 ; 0x018: 0x00000000
kfdhdb.driver.reserved[5]:            0 ; 0x01c: 0x00000000
kfdhdb.compat:                186646528 ; 0x020: 0x0b200000
kfdhdb.dsknum:                        1 ; 0x024: 0x0001
kfdhdb.grptyp:                        3 ; 0x026: KFDGTP_HIGH
kfdhdb.hdrsts:                        3 ; 0x027: KFDHDR_MEMBER
kfdhdb.dskname:              DATA1_0001 ; 0x028: length=10
kfdhdb.grpname:                   DATA1 ; 0x048: length=5
kfdhdb.fgname:               DATA1_0001 ; 0x068: length=10
kfdhdb.capname:                         ; 0x088: length=0
kfdhdb.crestmp.hi:             32999670 ; 0x0a8: HOUR=0x16 DAYS=0x7 MNTH=0x2 YEAR=0x7de
kfdhdb.crestmp.lo:           1788720128 ; 0x0ac: USEC=0x0 MSEC=0x36d SECS=0x29 MINS=0x1a
kfdhdb.mntstmp.hi:             32999670 ; 0x0b0: HOUR=0x16 DAYS=0x7 MNTH=0x2 YEAR=0x7de
kfdhdb.mntstmp.lo:           1812990976 ; 0x0b4: USEC=0x0 MSEC=0x3 SECS=0x1 MINS=0x1b
kfdhdb.secsize:                     512 ; 0x0b8: 0x0200
kfdhdb.blksize:                    4096 ; 0x0ba: 0x1000
kfdhdb.ausize:                  4194304 ; 0x0bc: 0x00400000

 

 

AUN=1 的最后一个block为KFBTYP_HBEAT 心跳表:

 

[oracle@mlab2 hzy]$ kfed read /oracleasm/asm-disk02 aun=1 blkn=1023 aus=4194304 |less  
kfbh.endian:                          1 ; 0x000: 0x01
kfbh.hard:                          130 ; 0x001: 0x82
kfbh.type:                           19 ; 0x002: KFBTYP_HBEAT
kfbh.datfmt:                          2 ; 0x003: 0x02
kfbh.block.blk:                    2047 ; 0x004: blk=2047
kfbh.block.obj:              2147483649 ; 0x008: disk=1
kfbh.check:                  1479766671 ; 0x00c: 0x5833728f
kfbh.fcn.base:                        0 ; 0x010: 0x00000000
kfbh.fcn.wrap:                        0 ; 0x014: 0x00000000
kfbh.spare1:                          0 ; 0x018: 0x00000000
kfbh.spare2:                          0 ; 0x01c: 0x00000000
kfdpHbeatB.instance:                  1 ; 0x000: 0x00000001
kfdpHbeatB.ts.hi:              32999734 ; 0x004: HOUR=0x16 DAYS=0x9 MNTH=0x2 YEAR=0x7de
kfdpHbeatB.ts.lo:            3968041984 ; 0x008: USEC=0x0 MSEC=0xe1 SECS=0x8 MINS=0x3b
kfdpHbeatB.rnd[0]:           1065296177 ; 0x00c: 0x3f7f2131
kfdpHbeatB.rnd[1]:            857037208 ; 0x010: 0x33155998
kfdpHbeatB.rnd[2]:           2779184235 ; 0x014: 0xa5a6fc6b
kfdpHbeatB.rnd[3]:           2660793989 ; 0x018: 0x9e987e85

 

 

  • kfdpHbeatB.instance   instance id
  • kfdpHbeatB.ts.hi timestamp
  • kfdpHbeatB.rnd[0]  随机加盐

 

  •  External Redundancy一般有一个PST
  • Normal Redundancy至多有个3个PST
  • High Redundancy 至多有5个PST

 

如下场景中PST 可能被重定位:

  • 存有PST的ASM DISK不可用了(当ASM启东时)
  • ASM DISK OFFLINE了
  • 当对PST的读写发生了I/O错误
  • disk被正常DROP了

 

  •  在读取其他ASM metadata之前会先检查PST
  • 当ASM实例被要求mount diskgroup时,GMON进程会读取diskgroup中所有磁盘去找到和确认PST拷贝
  • 如果他发现有足够的PST,那么会mount diskgroup
  • 之后,PST会被缓存在ASM缓存中,以及GMON的PGA中并使用排他的PT.n.0锁保护
  • 同集群中的其他ASM实例也将缓存PST到GMON的PGA,并使用共享PT.n.o锁保护
  • 仅仅那个持有排他锁的GMON能更新磁盘上的PST信息
  • 每一个ASM DISK上的AUN=1均为PST保留,但只有几个磁盘上真的有PST数据

 

 

Extents Set

 

extents set 是data extent的集合,以此来维护virtual extent的冗余拷贝。ASM FILE1 中的extent 指针在extent map中是连续的,如下面的数据:

 

SQL> select pxn_kffxp,xnum_kffxp from x$kffxp where number_kffxp=257;

 PXN_KFFXP XNUM_KFFXP
---------- ----------
         0          0
         1          0
         2          0
         3          1
         4          1
         5          1
         6          2
         7          2
         8          2
         9          3
        10          3

 

 

以上查询中PXN_KFFXP为文件号257文件的物理extent号,而XNUM_KFFXP为逻辑extent号。 此文件位于一个High redundancy diskgroup上,所以一个extent set 包含3份相同的virtual extent数据。
可以把上述查询就看做文件号257文件的extent map,其逻辑extent号是连续递增的。

在一个extent sets中第一个extent就是primary extent。 在external redundancy模式下仅有一个primary extent。Normal redundancy下有一个二级extent在primary之后,high的情况下有2个二级extent。

对于normal redundancy下的文件,每一个extent set 都由2个分布在不同磁盘同时也是2个不同failure group的data extent组成。这2个data extent在extent map上是紧挨着的。primary extent的extent number总是偶数,其唯一的一个二级extent总是奇数。当一个extent被移动时一般会引发extent set中所有extent对应的移动,以满足冗余要求。

High Redundancy diskgroup默认使用三路镜像。三路镜像下的Vritual Extent有一个primary和2个二级secondary data extents。secondary data extents需要存放在不同的failure group,所以其要求至少三个failure group来实现high redundancy。

在特殊情况下可能存在data extent的丢失,例如当failure group不可用导致无处可放时。

 

secondary extent将被均匀分配在primary extent对应的disk partners上;即便有磁盘失败仍能保持对extent set的写出是负载均衡的。

 

File Directory (file #1)

具体请参考 深入了解Oracle ASM(二):ASM File number 1 文件目录  https://www.askmac.cn/archives/asm-file-number-1-the-file-directory.html

 

 

 

ASM实例启动

 

在ASM文件可以通过ASM实例来访问之前,ASM实例必须先启动。 在11.2下 不管是RAC还是StandAlone环境下ASM实例都会随系统BOOT自动启动。 启动一个ASM实例和启动一个数据库实例类似。 SGA和一组后台进程在启动过程中被创建出来。初始化参数instance_type决定了是ASM 实例还是数据库实例。除非STARTUP时使用了 NOMOUNT选项,否则默认STARTUP会执行ALTER DISKGROUP ALL MOUNT。

ASM实例启动过程中将加入到CSS中的+ASM成员组中。这将允许本实例与其他+ASM实例共享锁。数据库实例不会加入到这个成员组中,因为数据库实例的实例名不能以”+”开头。

 

Discovery 发现磁盘

 

Discovery 过程是在找到磁盘以便后续的操作。Discovery 到DISK STRING匹配的位置去找寻磁盘,并返回那些其认为合适的磁盘。对discovery一般存在于2种场景下; 第一种是使用asm_diskstring中指定的所有字符串来找出所有ASM实例必要访问的磁盘。 第二种是指定磁盘路径用以create diskgroup或者add disk to diskgroup。

第一种discovery也叫做shallow discovery, 只会返回asm_diskstring指定下的磁盘。第二种也叫做deep discovery,是读取每一个磁盘的第一个块。 disk header在这里用以分类磁盘是否可用,是被ASM外的其他东西实用(例如LVM),还是已经被其他diskgroup实用。discovery操作并不会 mount diskgroup或者写任何磁盘头。

 

Create Disk Group  创建磁盘组

 

创建diskgroup 需要指定多个磁盘路径,且这些磁盘需要通过如下的检测:

  • 它不能是已经mount的diskgroup的一部分
  • 它不能有一个有效的ASM disk header,除非加了FORCE选项
  • 它不能有一个有效的ORACLE DATAFILE HEADER,除非加了FORCE 选项
  • 除非必须,不要用FORCE选项
  • 它不能存在对ASM可见的2个不同的路径名字。
  • 其必须可以通过asm_diskstring来发现

所有的磁盘均会以写入一个disk header的形式来验证。该 disk header中mount timestamp为0 ,由此可知diskgroup还没有被mount 过。之后free space block和allocation table blocks 元数据块将被写入。

其中部分磁盘被选出来 存放Partnership and Status Table ,PST 表。 PST被初始化记录所有的磁盘为在线状态。High redundancy disk group 每一个failure group对应一个 PST,最多5个拷贝。 normal redundancy group至多3个PST拷贝。external redundancy disk group有一个PST。

接着后续的metadata block将被初始化,并均匀分布在新创建的diskgroup的所有磁盘上。

 

【Oracle ASM Metadata】Alias Directory (file #6)

【Oracle ASM】Continuing Operations Directory (file #4)

【Oracle ASM Metadata】Template Directory (file #5)

【Oracle ASM】ASM FILE NUMBER 3 Active Change Directory

深入了解Oracle ASM(二):ASM File number 1 文件目录

【Oracle ASM】ASM FILE NUMBER #2 DISK Directory

 

当diskgroup完全初始化完成后mount timestamp将写入到disk header。 这将标记diskgroup已经格式好并可以被mount。其他实例也可以mount该disk group。

 

Drop Disk Group

 

diskgroup 可以被drop掉的前提是其上所有的文件都处于关闭状态且仅有本地实例在mount它。 可以通过在集群件的所有ASM上通信来确认这2点。drop diskgroup会在该DG下所有的磁盘头写入header_status为FORMER状态。

 

Mount Disk Group

Mount Disk Group使Disk Group其对本地ASM 实例和连接到该实例的数据库实例可用。 在该diskgroup中的文件在 OPEN/create/delete之前必须先被本地ASM实例mount; 一般启动ASM时同时mount 多个diskgroup较高效。 典型情况下是ASM_DISKGROUPS匹配到的所有的diskgroup均通过ALTER DISKGROUP ALL MOUNT 在ASM实例启动时被mount 。

下面是mount 一个diskgroup的步骤:

Discovery

会通过ASM_DISKSTRING.做一个deep discovery; 每一个disk header均包含了其所属于的diskgroup;该步骤应当要找到所有要被mount 的diskgroup下属的所有磁盘。 在disk header上获得如下信息:

  • Disk Name
  • Disk number
  • 最后一次mount的 timestamp
  • Disk Group Name

 

当discovery时若发现2个磁盘的disk header一样则可能报错,这样做的目的是为了避免损坏disk group。

注意从diskgroup创建之后每一个ASM DISK的OS设备名可能发生变化,或者在集群中的每个节点上都不一样,这不要紧只需要discovery能找到它们并通过验证即可。

 

第一次mount的实例

会通过Instance Lock实例锁来判断ASM实例是否是第一个mount 该diskgroup的,还是已经被其他ASM实例 mount 了。如果是第一个做mount的,那么锁会被以排他持有直到mount disk group初始化完成,以防止其他实例也在该过程中做mount。 如果不是第一个mount的,那么要等第一个mount的ASM完成其mount操作。

 

PST discovery

当diskgroup的一组磁盘被找到,必须要找到包含PST的那些磁盘。 每一个磁盘上的AUN=1的第一个块将被读取。这样来识别那些盘在AUN=1中存有PST拷贝。必须找到多数相同的PST拷贝来保证读出一个有效的PST。

例如如果有5个PST, 则需要找到3份内容一样的 PST并读出。

一旦PST被读取后,ASM实例将知道mount disk group必须要哪些个些disk number。

 

Heartbeat

 

如果是第一个mount的实例,那么会做一个heartbeat check心跳检查。这是为了防止2个不同主机上的实例都认为其实第一个mount该diskgroup的,这种现象可能发生在lock manager配置不当的场景中。当disk group被实例mount时,PST 表上的最后一个块即心跳块每3秒被写入新的值,这种写入是由已经mount该DG的实例中的一个执行 。  若一个实例自认为第一个mount,但是缺发现了heartbeat则其mount 失败。若其发现没有heartbeat,则其将开始heartbeat。

 

Header validation

若是第一个mount dg的实例则一个新的mount 时间戳timestamp被写入到各个磁盘。 若不是第一个mount的实例,则会验证该mount timestamp。这保证2个实例可能找到对一个磁盘的多份完全相同的拷贝时,仍能分辨出其实是不同的磁盘。

 

若是第一个mount的实例,则可能存在这种情况:上一次mount以来的部分磁盘变得不可用了; 但这些磁盘在PST中仍标记为在线的,但却找不到它们了。这个差异将被ASM发现并将丢失的磁盘OFFLINE掉,前提是其redundancy允许这些磁盘OFFLINE。

 

若不是第一个mount的实例则在PST中所有标记为ONLINE 的磁盘均需要被其所发现。若其他实例能发现DG下的所有磁盘,那么本实例必须也能看到。

 

Redo recovery

若本实例时第一个mount DG的, 则其有义务做crash recovery。若ACD 中的任意redo thread 在他们的检查点记录中标记为打开状态,则它们需要被recover。 这个工序和数据库的crash recovery很像。在检查点和最后写入记录之间的redo将被扫描,来找出那些块需要恢复。这些块将被读取并应用 redo。

 

Redo thread selection

ACD中需要找出一块未使用的区域来存放本实例生成的redo。 若是第一个mount DG的实例则需要保证所有thread 都处于关闭状态,由此最小的thread将必然可用。 若不是第一个MOUNT DG的实例则可能整个ACD均已被使用。 若遇到此场景,则mount 中的实例将要求已mount 实例去扩展ACD。一旦ACD扩容了新区域以便存放生成的redo,则另一个redo thread将以写出到checkpoint block的形式来标记为OPEN。

 

 

First done

若是第一个mount DG的实例,将开始允许其他实例也能mount该DG。 若第一个实例到这一步之前就crash了,则其他实例将认为自己是第一个mount DG的实例。则若在多于2个实例的集群中后续的mount可以并行运行了。

 

Registration

实例将自己已mount的DG信息注册到CSS中。尝试访问这些DG的数据库实例将发现这些CSS注册信息并连接到ASM实例以便访问DG。

 

COD recovery

若是第一个mount DG的实例,其会检查COD中的记录,若发现任何操作需要回滚,则将其回滚。若有一个 rebalance作业仍在过程中,则该实例的 RBAL将重新启动rebalance。

 

 Dismount Disk Group

如同mount是ASM实例本地操作,dismount也是这样。正常情况下当本地数据库实例还有访问diskgroup中文件时是不允许常规的dismount的。 若如果没有文件被打开访问,则ASM buffer cache中的脏块将被写出到磁盘,且在ACD中的checkpoint记录将被标记为线程已关闭。且SGA中描述diskgroup的部分将被释放。

 

强制FORCE Dismount Disk Group也是常有的事情,当某个磁盘失败导致冗余算法无法容忍时就会自动触发强制dismount。 举个例子来说,当external redundancy下数据未做任何镜像,则当ASM中cache无法写出时除了强制dismount外没有其他选择。

 

Add Disk

 

增加磁盘add disk的命令将针对 指定的discovery strings去识别磁盘,若此时发现的磁盘已经是disk group的一部分,则将被默许为忽略掉。 磁盘将允许被加入到diskgroup,前提是:

  • 该磁盘不能是已经mount的diskgroup的一部分
  • 必须没有有效的ASM disk header,除非使用了FORCE选项
  • 必须没有有效的ORACLE数据文件头,除非使用了FORCE选项
  • FORCE选项 如非必须建议用户不要用, 避免滥用
  • 其必须不能以2个不同的路径名同时可见
  • 其必须能被asm_diskstring所匹配到

 

当所有的磁盘均被以上验证过后,下面的步骤将被执行:

  • Disk Directory中加入对应该磁盘的记录
  • Free Space block和allocation table将写入到该磁盘
  • Disk header将被以当前时间戳更新
  • 磁盘将被加入到PST,但还没有partners,但是其已经 ONLINE可做读写。这将让磁盘真正成为diskgroup的一份,即便发生实例crash
  • 一次rebalance将被启动,这将给新的磁盘找partners,并将数据移动到其上。 一般推荐一次加多个磁盘,而非一次次地加。

当rebalance开始时这个add disk操作就被返回。 磁盘并不完全参与到disk group 中,直到rebalance结束。

 

ASM Drop Disk

 

磁盘可以从diskgroup中drop出来的前提是 有足够的未用空间在剩余的磁盘上。 即便其仍在被活跃使用也还是可以被 drop的。 当磁盘仍在工作,但是对于diskgroup不是必须的时可以做常规的drop。若磁盘失败时则可以用FORCE选项。 Drop磁盘将影响所有mount diskgroup 的实例。其不是一个实例本地操作。

 

ASM DROP Normal 常规drop

 

常规drop disk下磁盘将被标记为不可再分配,且开始一个rebalance。 drop命令当rebalance开始时即返回。在 rebalance过程中该drop中的磁盘将不断被移动其上的内容到其他磁盘上。 当rebalance 完成时该磁盘将被从disk group中移除并可以复用。 可以通过查询V$ASM_DISK来确认磁盘是否还是disk group的一部分。

 

当rebalance还在进行中时,disk将处于正被drop的状态,即dropping。 还可以通过命令 alter diskgroup undrop来反转这个还未完成的drop命令的效果。 如此则磁盘上不可再分配的标记将被移除,并会重启一个rebalance。 这个重启的rebalance将重新评估我们正在drop的磁盘的partnerships,并可能将数据data extent移回到正被dropping的磁盘上。 这个重启的rebalance 仅仅需要撤销之前rebalance所做的工作即可, 因此其所耗时间取决于之前的drop工作的rebalance的工作量。 最后的分配情况可能与开始有着些许区别,但其仍将是平衡的。

 

 

ASM DROP Force 强制drop 

 

对于Normal 或者 High Redundancy disk group而言一个磁盘可以使用FORCE选项被DROP。FORCE 选项对于external redundancy 的disk group而言是不可用的, 原因是无法正常从被drop掉的disk上将数据重构出来。 对于normal或者high redundancy的disk group而言如果有一个或者多个磁盘partners已经OFFLINE了,则可能也不允许FORCE DROP。 总是当FORCE DROP可能造成丢失文件上数据的时候都不允许使用。

FORCE DROP会立即将磁盘状态置为OFFLINE。该磁盘上的所有extent都将脱离其对应的extent set集合,这意味着冗余度的降低。 该磁盘将从disk directory中被移除,PST中也是这样。

该磁盘的disk header将被写入信息来表明其不再是disk group的一部分。 rebalance也会被启动。 当drop force命令返回时,意味着磁盘已经完全从disk group中移除了,可以被重用,也可以从操作系统上断开了。

发生操作的disk group上所有文件的冗余度要直到rebalance才能重新完善。 与常规的drop不同,显然force drop是无法被undrop的。磁盘将完全被从disk group移除,所以undrop也无法撤销此操作; 所能做的是将该磁盘重新加入到diskgroup, add disk。

 

数据库实例如何连接到ASM

 

当数据库实例尝试打开或者创建名字以“+”开头的文件时, 它会通过CSS来查看disk group和mount该DG的ASM实例的信息。 如果数据库实例之前访问过其他Disk Group里的文件,则将使用同一个ASM实例。 如果这是第一次访问ASM上的文件,数据库实例就需要连接到ASM实例了。  下面为数据库实例准备访问ASM上文件的步骤:

后台进程ASMB启动并connect连接到ASM实例。 数据库实例所打开的任意文件的extent map盘区图被发送给ASMB后台进程。 其有义务去维护extent map。若发生任何extent移位,则ASM实例将更新发送给数据库实例的ASMB进程。I/O统计信息定期由ASMB进程反馈给ASM实例。

RBAL后台进程启动,其对disk group下的所有磁盘做全局打开操作,其类似于DBWR进程全局打开数据文件。此全局打开允许数据库实例访问diskgroup中的任意文件。 若还有其他disk group需要被访问,则 RBAL也将打开对应diskgroup下的所有磁盘。 对add加入或者drop的磁盘,RBAL也会打开和关闭它们。 关于磁盘的讯息先是发送给ASMB,之后ASMB转发给RBAL。

会创建一个连接池,一组slave进程将建立到ASM实例的连接。数据库进程若需要发送信息给ASM实例,则需要使用这些slave进程。 举个例子来说,打开一个文件,将通过slave给ASM发送一个OPEN的请求。 但对于长时间运行的操作例如创建文件,则不使用slave。

 

ASM file Create文件创建

 

文件创建这个过程,是数据库发送请求给ASM实例,ASM创建文件并响应该请求。

创建文件时会为其分配空间并打开文件以便读写。一旦文件完成初始化,则创建被提交。 如果创建文件未被提交则文件会被自动删除。 其步骤如下:

数据库进程调用服务层代码来创建一个文件名以”+”开头的文件, 系统将自动返回一个生成的名字。 如果文件名里给出了完全路径则一个用户别名将被创建并返回。该调用同样包括 文件类型、块大小、初始文件大小和构建系统声称文件名的其他信息。

数据库进程连接到ASM实例,此处不用connection pool连接池,原因是文件创建要求保持在同一连接内。 这避免了使用过多连接池连接而可能造成的死锁。

数据库进程发送创建请求给ASM实例,需要等待新文件的extent map被加载到数据库实例中

ASM前台进程为新文件分配一个文件目录下的记录,并在COD continuing operations directory中创建一个回滚记录,以便删除该文件。 如果连接被打断,ASM前台进程崩溃,或者数据库中止该创建,则回滚该操作时将自动删除该文件。

ASM进程为该文件分配extent,以便其均匀分布在disk group中的所有磁盘上。

ASM实例发送extent map 给数据库实例的ASMB进程

ASM前台进程将文件名返回给数据库进程,数据库进程会保持与ASM进程之间的连接为打开

数据库进程为新的文件初始化内容,可给出resize请求以便扩大或收缩该文件

当文件的内容和大小都初始化后,一个提交该创建的请求将发送给ASM前台进程

ASM前台进程在 alias目录下创建系统生成文件名的记录。 如果还有用户指定的 alias,则该alias文件名也将加入到alias directory

ASM将该文件标记为创建成功的,并删除回滚记录

由于提交创建也将关闭文件,故 ASM实例告诉数据库ASMB进程要释放其extent map

ASM前台进程返回一个成功创建文件的信息给数据库进程。 数据库进程关闭到ASM实例的连接,其将终止对应的ASM前台进程

 

以上文件被成功创建并可以被任何进程打开了

 

 

Extent Allocation 盘区分配

 

分配盘区Allocating extents,将文件均匀地发布在disk Group中的所有磁盘上。 每一个磁盘有一个权重,这个权重是基于其大小的。extent set下属的data extents必须分配在disk partnerships之间。 每一个extent set的primary extent分配时会按照磁盘的权重来分布文件。则文件的下一个primary extent将尽可能分配在那些使文件分布更平衡的磁盘上。这样同一个文件在同一个磁盘上的primary extent会尽可能远。

对于Normal 或者 high redundancy的 文件的secondary extents必须为primary extent多冗余拷贝而分配。secondary extents理想是均匀分布在primary extent所在盘的partners disk上,同样也要基于磁盘权重。对于high redundancy还有一个要求,就是2个secondary extents需要分配在不同的failure group上。

 

FILE Delete ASM文件删除

 

ASM上的文件可以通过 数据库实例 或者在ASM实例中输入一条SQL命令来删除。 数据库实例可以通过连接池中的slave进程来发送一个delete 删除请求。若该文件还处于打开状态则文件暂时不能删除。 针对一个打开的文件,每一个ASM实例将持有一个全局锁来避免其被删除。 回滚记录也将介入,以保证如果删除开始,其必须完成。

 

 

 FILE OPEN ASM文件打开

 

当一个数据库实例下的进程打开一个ASM 文件时,它会使用连接池slave进程来发送请求给ASM实例。  ASM前台进程会查看alias directory下的文件,或使用系统生成的文件名中的文件号和incarnation信息。 ASM前台进程获取文件锁并发送extent map给数据库的 ASMB进程,并存在SGA中。 一旦extent map加载成功,ASM将返回成功信息给数据库进程。 数据库进程使用extent map来将文件访问转换为适合的磁盘IO。每一个extent指针存有一个check检测值,来捕获是否存在损坏的extent map。

若果数据库实例的一个进程打开一个文件,则其他进程可以使用同一个extent map。因此仅仅有第一个进程需要与ASM 实例联系。数据库实例的其他进程是坐享其成的。

 

FILE Close 关闭文件

当数据库实例中的所有进程均关闭了一个文件,则connection pool连接池slave进程将发送一个close信息给ASM实例。 ASM实例会通知数据库的ASMB进程要关闭extent map和释放extent map所占内存。当ASMB关闭进程后其将释放文件锁。

 

I/O 错误

Normal或者 high redundancy的disk group可以容忍多种 IO错误。 处理这些IO错误的方式 基于 I/O的类型:是读还是写?以及 其I/O 的原因。 最常见的处理方式是当发生I/O错误则将问题磁盘OFFLINE掉。 如果将磁盘OFFLINE掉将造成部分数据不可用,则强制性的Disk Group Dismount将被发动。 这样做则从其他节点或者待问题修复后,尝试恢复重新写入变得可能。 在external redundancy下磁盘不能被offline。 normal redundancy下2个互为partners的磁盘不能同时OFFLINE。high redundancy下2个partners可以OFFLINE,其他partners不能再OFFLINE。 如果一个错误引发disk group被强制dismount,则没有磁盘将被OFFLINE。如果normal disk group下2份数据写入都有问题,则也不会吧磁盘OFFLINE。

 

一个磁盘要OFFLINE的话,首先要求所有的数据库实例和ASM实例均在自己的SGA中将其标记为OFFLINE的,避免其仍正在被读取。 由于 I/O错误导致磁盘OFFLINE的行为,直到所有进程均停止读取该磁盘才被认为是完成的。

 

 

ASM FILE read 文件读取

 

注意文件数据的读取仍是数据库实例自己完成的,而不是ASM实例。 典型情况下总是读取primary extent除非对应的磁盘OFFLINE了。 如果primary extent 所在磁盘OFFLINE了或者读取失败了,则会使用secondary extents。 如果primary 和 secondary  extents都读取失败,则一个I/O错误将返回给 client。 文件读取失败一般不会造成磁盘OFFLINE或者disk group  dismount。

 

ASM FILE Write 写文件

 

文件数据写入同样仍由数据库实例自己完成,而非ASM实例。若任何写出发生IO错误,则该错误将通过connection pool slave连接池子进程发送给ASM实例。  ASM实例要么把磁盘OFFLINE,要么dismount diskgroup,且通过ASMB的连接来更新磁盘状态。 数据库进程或者重新发起之前的写出。由于写出不会再写到OFFLINE的磁盘上,所以重试写出一般会成功,除非diskgroup也给dismount了。

 

Instance Recovery实例恢复

 

ASM实例恢复instance recovery 与数据库实例恢复很类似。最大的区别在于ASM实例会mount多个disk group,且不同的disk group又可以为多个实例所用。Instance recovery是基于每一个disk group为基础的。在RAC中若一个实例强制dismount了一个disk group,则另一个ASM实例必须做该disk group的instance recovery,甚至于之前dismount该diskgroup的实例没有终止。ASM实例只为其已经 mount的disk group做instance recovery。RAC中,如果一个ASM实例已经mount了2个disk group且意外崩溃了,则这2个disk group的恢复工作可能有集群的其他ASM实例来完成。

instance recovery实例恢复首先扫描ACD中的redo来构建需要做恢复的块的列表。 redo将被应用到块,块将被写回到diskgroup中。 之后新的锁可以被请求以便访问diskgroup上的元数据metadata。注意ASM实例的instance recovery仅仅与 ASM metadata有关。 文件中的数据还是由数据库实例自己恢复的。

在redo应用之后正执行该instance recovery的ASM实例将检测COD中的数据,如果之前有rebalance正在之前崩溃的实例中运行的话, 则考虑如果必要重启该 rebalance 。 之前崩溃的ASM实例所留下的任意回滚操作都将被完成。

 

Rebalance 

 

当一个或者多个磁盘 被 加入,drop,或者resize时disk group要做rebalance来保证所有存储均匀地使用。Rebalance移动数据的依据不是 I/O统计信息,也不是其他统计的结果。 完全基于disk group中各个磁盘的大小。当存储配置发生变化时其自动开始,当然也可以手动来发起。一般不推荐手动介入,需要手动介入的是当需要修改 rebalance power,或者将rebalance操作变换到其他节点上执行时。 手动介入时命令在哪个实例上执行,rebalance就发生在哪个实例上。

 

下面是rebalance 的简要步骤:

 

Repartner 重新配对

当一个磁盘加入到diskgroup中时,其需要配对partners,这样它本身存放数据的primary extent,其配对partners磁盘才能存储镜像拷贝。由于理想情况下每一个磁盘已经拥有了最大数目的配对partners,新增加磁盘配对关系的话往往意味着要打破一些现有的partners配对。 当正在drop磁盘时,其现有的配对关系partnerships将不得不被打破。这将造成一些磁盘的配对数目小于理想数。 因此rebalance的第一步是重新计算一个新的配对组合集合。 这个新的partnerships基于移动最少量数据的依据被选择出来。这也是为什么最好增加和drop多个磁盘最好是同一时间发起的原因。

 

Calculate weights计算权重

rebalance的目标是让disk group 中的每一个磁盘均以同样的比例分配。因此更大的磁盘就要存放更多的文件数据。 这里会为每一个磁盘计算一个权重,来决定其上存放多少量的数据。权重受到磁盘大小和配对关系的影响。

 

Scan files 扫描文件

 

rebalance是一个文件、一个文件做的,文件的extent map将被扫描来判断其应当如何平衡。为了实现平衡,现有的extent set可能被移动到其他磁盘上,以便归于平衡。 这通常结果是移动到最新加入的磁盘中。也可能为了新的配对关系来做必要的移动。

 

 Extent relocation 盘区移位

 

移位一个extent 是需要协调发生到该 extent上的任意I/O的。 集群中的所有ASM实例均会被通知开始移位的信息。 此信息也将被转发给所有有打开该文件的数据库实例的ASMB进程,这样就锁住了对应的extent。任何新的写入到对应extent的操作将被阻塞, 但读取则不被影响。当relocate操作结束后,已有的写出操作将被重新触发。 extent 盘区是被从旧的位置读取并写出到新的位置 基于1MB的I/O。在 relocation完成后解锁的信息将传达并包含有新的盘区指针。 extent map将被更新 且其上面lock的标记将被清楚。 任何未完成的写入将被允许继续工作。 任何活动的查询将被重新触发,原因是旧有的extent可能已经被其他数据重用了。

可能有多个slave进程在同一时间做relocation,power limit参数控制slave进程数目。

 

Restart重新开始

 

同时时间只能有一个 rebalance。若进行中的rebalance被打断,那么其一般会自动重启。若正在做rebalance的一个节点发生失败,则rebalance将从其残局重启。如果管理员手动修改了power limit 也会引起重启。如果在rebalance过程中发生了另一个存储变更,则整个rebalance将从开头重启

 

 

Check Disk Group检测磁盘组

 

check disk group 命令比对一个 disk group中的冗余数据结构来保证没有损坏发生。 在检测过程中数据结构将被锁住,检测中将发生下面的动作:

PST将被验证来确保所有的配对关系是对称的且有效的。  如果disk A以Disk B作为partner,则Disk B也是Disk A的partner。 如果Disk B不存在或者 Disk A不在Disk B的partner 列表上,则生成错误。 A和B当然在不同的failure groups上。

 

Extent Map 将对照allocation tables做检查。所有在线的磁盘的allocation tables将被扫描,且extent map上每一个已经分配的AU将被确认。一个已经分配的 AU的allocation tables记录指出了使用该AU的文件号和data extent信息。文件的extent map中的磁盘和AU信息将被验证。如果文件不存在,或者extent map指向不同的AU,都将导致报错。 同时检测也会发现那些看上去已经被分配,但是不属于任何文件的一部分的AU。

 

Allocation tables将对照Extent Map做检查。所有文件的extent maps将被扫描,且每一个data extent的分配记录将被确认指向了文件extent。data extent的extent map记录给出了分配该extent的磁盘号和AU号。allocation table记录将被验证。 如果磁盘过小,或者AU实际上没被分配,或者AU其实分配给了其他文件,或者AU其实是分配给其他extent的,都会导致报错。 该检测可以发现被分配了2次的AU,或者虽然标记为空闲但实际已经被使用的AU。

 

所有的extent set都对照着配对关系partnerships做一次验证。每一个extent set中的每一个secondary extent都被验证是否在含有primary extent的磁盘的partner上。 这将发现丢失配对关系的情况。

 

若以上任何问题发生,则将报错,但检测会持续下去。修复不一致往往需要靠手动操作,例如使用KFED。

 

 

 

Comments

  1. 请教:Oracle有对应API来完成对ASM里面的文件进行读、写、创建、删除等操作吗?类似文件系统的open,close,read,write,lseek,remove. …

  2. Partnering本身已经能够保证在Disk磁盘以不规则的几何安排方式组织时仍能同一负载均衡这个不规则几何安排方式具体指什么? 是否是指 不同failgroup的磁盘个数不一致,或者failgroup中包含的磁盘大小不一致呢?

  3. “这个数目越小,则双磁盘同时失败造成数据丢失概率越小。 但是这个数目越小,也会造成其他不便”请问这个其他不便具体是指哪些方面啊

Trackbacks

  1. […] 【文档】Maclean介绍Oracle ASM基础概念和原理  原帖在这里:http://www.askmaclean.c… […]

Comment

*

沪ICP备14014813号-2

沪公网安备 31010802001379号