设为首页收藏本站

Botang唐波's Oracle Station

【博客文章2015】Oracle11gR2 RAC数据库中的Master实例、Owner实例、Past Image和Current Image的概念

2015-2-10 19:41| 发布者: admin| 查看: 12304| 评论: 0

摘要: 本文探索Oracle RAC数据库的内部原理。探索Oracle RAC数据库的调优源头,弄清“Master实例”、“Owner实例”、“Past Image”和“Current Image”的概念。

Botang唐波


摘要

本文探索Oracle RAC数据库的内部原理。探索Oracle RAC数据库的调优源头,弄清“Master实例”、“Owner实例”、“Past Image”和“Current Image”的概念。



目录
 

1Oracle RAC数据库服务器实例间的网络通信

2Oracle RAC数据库服务器中最重要的内存结构:GRDGRD中的资源

3.数据块上的BL锁和PR授权

4.能够查出某个块Master实例和Owner实例的X$

5自动RemasterObject Affinity and Dynamic Remastering引起)手工Remasteroradebug命令)

6.实例恢复过程中的RemasterDynamic Reconfiguration

总结



正文
 

1. Oracle RAC数据库服务器实例间的网络通信

下图描述了Oracle RAC数据库服务器实例间内连网通信体系结构(见图1):

  

1Oracle RAC数据库服务器实例间内连网通信体系结构示意图


Oracle RAC数据库服务器调优重要目标就是尽量减少实例没有必要的内连网通信量。下节所讨论的“Oracle RAC数据库服务器中最重要的内存结构:GRDGRD中的资源”,都是通过内连网通信来维护。


2Oracle RAC数据库服务器中最重要的内存结构:GRDGRD中的资源

RAC的体系结构中(见图2,全局资源目录(Global Resource Directory简称GRD)是Oracle RAC数据库服务器中最重要的内存结构。它是一套哈希分布于各个实例间由被称为“gcs mastership buckets”、“gcs res hash bucket”和“gcs resources”等内存结构组成的的元数据集(见表1)。这个哈希分布元数据集用以描述Oracle RAC数据库服务器中数据块的状态、属主信息以及数据块内部和数据块自身的锁信息。GRD分布在所有实例的共享池中,每个实例维护GRD的一部份。所有实例维护的GRD合起来形成哈希分布式的整体集。GRD内部包含“转换队列”和“写队列”,这两个队列被GCSGlobal Cache Service)和GESGlobal Enqueue Service)维护。所有维护信息通过前面介绍过的内连网传输。

  

2Oracle RAC体系结构图

   

POOL

NAME

BYTES

1

shared pool

KCL buffer header

9664

2

shared pool

KCL instance cache transf

262144

3

shared pool

KCL lock contexts

14420

4

shared pool

KCL lock state

3584

5

shared pool

KCL name table

262144

6

shared pool

KCL offline scn array

1608

7

shared pool

KCL partition table

720896

8

shared pool

KCL region array

8

9

shared pool

gcs I/O statistics struct

32

10

shared pool

gcs affinity 

4108

11

shared pool

gcs close obj

4104

12

shared pool

gcs commit sga state

67596

13

shared pool

gcs mastership buckets

4608

14

shared pool

gcs opaque in

4028

15

shared pool

gcs res hash bucket

32768

16

shared pool

gcs res latch table

15360

17

shared pool

gcs resource freelist arr

272

18

shared pool

gcs resource freelist dyn

32

19

shared pool

gcs resources

4812504

20

shared pool

gcs scan queue array

216

21

shared pool

gcs shadow locks dyn seg 

32

22

shared pool

gcs shadow locks freelist

272

23

shared pool

gcs shadows

3418328

1:共享池中的与RAC相关内存结构,数据来源于:V$SGASTAT


理论上每个数据块都有对应于它的GRD信息:无论它当前存在于某个实例的数据库缓冲区缓存中还是已经被写回硬盘数据文件中。这些信息加上管理这些信息的锁合在一起称为“资源”。

既然GRD是分布式的整体,对于一个数据块而言,管理该数据块的状态和属主信息以及数据块内部和数据块自身的锁信息的实例只有一个。这个实例就被称作为该数据块(或更准确地说:资源)的Master实例。Oracle这样做是为了将数据块状态和属主等信息均衡地哈希分布在不同实例上。从10g以后版本开始,数据块的状态和属主等信息被存储成每128个块的信息一个master单元,即128个数据块的状态和属主等信息构成一个“gcs mastership bucket”。但是要说明以下:一个“gcs mastership bucket”不一定要存满128个块的状态和属主等信息。这样就能理解:超过128个块的表的数据块可以被多个实例分布式地分段master。如果发生自动RemasterObject Affinity and Dynamic Remastering引起)或手工Remasteroradebug命令),整个对象将作为master单元而不进行多个实例分布式地分段master:即不管表多大,它的数据块都由同一个实例master。另外,任何时候undo段整段必需由同一个实例master

数据库缓冲区缓存中拥有某个内存拷贝的实例被称作该数据块的Owner实例。Owner实例的个数可以是0(最小)到集群节点总数(最大)中的任何数值。如果该数据块内存拷贝在多个实例的数据库缓冲区缓存中同时被找到,也就是说该数据块有多个Owner实例,那么证明在近期有多个实例先后修改或访问过它。在所有这些该数据块的内存拷贝中,SCN最大的那个内存拷贝被称为Current ImageXI),SCN不是最大的那些内存拷贝就都被统统称为该数据块的 Past ImagePI)。PI的存在主要是为了在实例恢复过程中能被利用来减少实例交叉恢复的时间。如果由于检查点事件XI被写回硬盘,那么所有它所对应的所有PI都将被从内存中直接flush掉。还有一点值得注意的是:XIPI都可以包含各自的new valueold value。通常old valueOracle文档中又被称为Before Image即:BI

最后说一下:对于回滚段上的BI而言,激活了一个回滚段的实例立刻成为该段的master实例。因为该回滚段将会被打开这个回滚段的实例所使用,用以写入事务产生的BI。因为回滚段没有真正的object_id,所以在X$KJBL表中Oracle使用回滚段号作为该回滚段的object_id

以下用一幅图来形象描绘了一下数据库服务器其中一个实例的GRD构成(见图3):

  

3:某个实例的GRD构成示意图(其中:Null表示空锁,Shared表示共享锁,Exclusive表示独占锁)

3.数据块上的BL锁和PR授权

对于RACBuffer cache中的Buffer以及硬盘数据文件上的,都是锁管理的对象之一。这种锁就被称为“BL锁”,单实例的数据库上没有这种类型的锁。对Buffer和硬盘数据文件上的的修改或访问都要先得到它的master实例的“Protected Read”授权,简称PR授权(锁状态为:KJUSERPR)。PR授权就是获得BL锁的过程。下面列出查看BL锁和PR请求的SQL语句(见表2),同时形象展现GRD中的BL锁和PR请求的动态过程(见图4)。如前所述BL锁和被其锁住的信息合在一起就是一个BL锁资源。


select * from v$ges_resource where resource_name like '%BL%';

select * from v$ges_enqueue where resource_name2 like '%BL%';

注:v$ges_resourcev$dlm_ress是相同的。

2:查看BL锁资源和PR请求的SQL语句
 

4Buffer Cache中的数据块变化前必需询问GRD

某个实例是否有申请了BL锁资源,关键是理解该实例对数据块OpenBuffer Access之间的区别。如果缓存中的数据块已经处于适当的模式,就没有必要在数据块上再打开BL锁。所以如果会话反复存取同一个数据块而不请求额外的BL锁,那么在X$OBJECT_POLICY_STATISTICSBL锁的Open计数就不会增加。这个计数可以从以下的查询语句中查出(见表3)。


实验第1步:

查看实验用表t04209_uname的定义

在任一个实例上执行:

select t.TABLE_NAME, t.COLUMN_NAME, t.DATA_LENGTH, t.DATA_PRECISION

from dba_tab_columns t

where t.owner = 'HR'

and t.table_name = 'T04209_UNAME';



TABLE_NAME

COLUMN_NAME

DATA_LENGTH

DATA_PRECISION

1

T04209_UNAME

UNAME

60


2

T04209_UNAME

UVALUE

22

9


实验第2步:

查看实验用表t04209_uname的内容

在任一个实例上执行:

select * from hr.t04209_uname;



UNAME

UVALUE

1

a1

1

2

a2

2

3

a3

3

4

a4

4

5

a5

5

6

a6

6

7

a7

7

8

a8

8

9

a9

9

10

a10

10

...

...

...


10万行


实验第3步:

查看实验用表t04209_uname的数据块个数

在任一个实例上执行:

select s.segment_name, s.blocks

from dba_segments s

where s.owner = 'HR'

and s.segment_name = 'T04209_UNAME';



SEGMENT_NAME

BLOCKS

1

T04209_UNAME

256 该表共有256个块


实验第4步:

查看实验用表t04209_unameobject_id

在任一个实例上执行:

select o.object_name, o.object_id

from dba_objects o

where o.owner = 'HR'

and o.object_name = 'T04209_UNAME';



OBJECT_NAME

OBJECT_ID

1

T04209_UNAME

52533


实验第5步:

在任一个实例上执行:

select * from x$OBJECT_POLICY_STATISTICS where object = 52533;

无输出


实验第6步:

在实例1update这个表t04209_uname

update hr.t04209_uname set uvalue = 2 where uname = 'a1';

update hr.t04209_uname set uvalue = 3 where uname = 'a2';

update hr.t04209_uname set uvalue = 4 where uname = 'a3';

update hr.t04209_uname set uvalue = 5 where uname = 'a4';

update hr.t04209_uname set uvalue = 6 where uname = 'a5';

update hr.t04209_uname set uvalue = 7 where uname = 'a6';

update hr.t04209_uname set uvalue = 8 where uname = 'a7';

……

update hr.t04209_uname set uvalue = 99996 where uname = 'a99995';

update hr.t04209_uname set uvalue = 99997 where uname = 'a99996';

update hr.t04209_uname set uvalue = 99998 where uname = 'a99997';

update hr.t04209_uname set uvalue = 99999 where uname = 'a99998';

update hr.t04209_uname set uvalue = 100000 where uname = 'a99999';

update hr.t04209_uname set uvalue = 100001 where uname = 'a100000';

10万行


实验第7步:

在任一个实例上执行:

select * from x$OBJECT_POLICY_STATISTICS where object = 52533;



ADDR

INDX

INST_ID

OBJECT

NODE

SOPENS

XOPENS

1

B7F4C4C8

7

2

INST_ID2代表Mater实例为实例2

52533

1 ↖NODE1代表Owner实例为实例1


245 ←BL Open次数,这个表共有256个块几乎占全部。说明update大部分的行。


实验第8步:

等实例1update结束后,再查x$OBJECT_POLICY_STATISTICS没有输出

重新在实例1上做 updatex$OBJECT_POLICY_STATISTICS仍然没有输出。

这就说明:如果缓存中的数据块已经处于适当的模式,就没有必要在数据块上再打开BL锁。所以如果会话反复存取同一个数据块而不请求额外的BL锁,那么在x$OBJECT_POLICY_STATISTICSBL锁的Open计数就不会增加。


实验第9步:

在实例1alter system flush buffer_cache;后,再做同样的update


实验第10步:

在任一个实例上执行:

select * from x$OBJECT_POLICY_STATISTICS where object = 52533;



ADDR

INDX

INST_ID

OBJECT

NODE

SOPENS

XOPENS

1

B688A1D0

7

2↖INST_ID2代表Mater实例为实例2

52533

1↖NODE1代表Owner实例为实例1


248 ←BL Open次数


实验第11步:

为了使情况更复杂点,在实例2同时进行(保证实例1还在执行刚才的update):

update hr.t04209_uname set uvalue = 9 where uname = 'a8';

update hr.t04209_uname set uvalue = 99 where uname = 'a98';

update hr.t04209_uname set uvalue = 999 where uname = 'a998';

update hr.t04209_uname set uvalue = 9999 where uname = 'a9998';

update hr.t04209_uname set uvalue = 99999 where uname = 'a99998';

update hr.t04209_uname set uvalue = 99998 where uname = 'a99997';

update hr.t04209_uname set uvalue = 99997 where uname = 'a99996';

update hr.t04209_uname set uvalue = 99996 where uname = 'a99995';

update hr.t04209_uname set uvalue = 99995 where uname = 'a99994';

……

update hr.t04209_uname set uvalue = 10006 where uname = 'a10005';

update hr.t04209_uname set uvalue = 10005 where uname = 'a10004';

update hr.t04209_uname set uvalue = 10004 where uname = 'a10003';

update hr.t04209_uname set uvalue = 10003 where uname = 'a10002';

update hr.t04209_uname set uvalue = 10002 where uname = 'a10001';

update hr.t04209_uname set uvalue = 10001 where uname = 'a10000';

update hr.t04209_uname set uvalue = 10000 where uname = 'a9999';

update hr.t04209_uname set uvalue = 100001 where uname = 'a100000';

update hr.t04209_uname set uvalue = 100000 where uname = 'a99999';

10万行,这10万行update是不按顺序打乱后的组合。


实验第12步:

在任一个实例上执行:

select * from x$OBJECT_POLICY_STATISTICS where object = 52533;



ADDR

INDX

INST_ID

OBJECT

NODE

SOPENS

XOPENS

1

B688A1D0

20

2

52533

1

0

2562由于两个实例同时更改,产生 了大量BL Open

2

B688A1D0

21

2

52533

2


1053 ↙BL Open的增加是为了进行gc cr


实验第13步:

在任一个实例上执行:

select to_char(52533, 'xxxxxxxx') from dual;



TO_CHAR(52533,'XXXXXXXX')

1

cd35


实验第14步:

在任一个实例上执行: 查看两个实例此时的资源状态

select inst_id,

resource_name,

on_convert_q,

on_grant_q,

master_node,

next_cvt_level

from gv$ges_resource

where resource_name like '[0xcd35]%';



INST_ID

RESOURCE_NAME

ON_CONVERT_Q

ON_GRANT_Q

MASTER_NODE

NEXT_CVT_LEVEL

1

2

[0xcd35][0x0],[TM]

0

1

0

KJUSERNL

2

2

[0xcd35][0xc09281d],[IV]

0

1

0

KJUSERNL

3

1

[0xcd35][0x0],[TM]

0

1

0

KJUSERNL

4

1

[0xcd35][0xc09281d],[IV]

0

1

0

KJUSERNL


实验第15步:

在任一个实例上执行: 查看两个实例此时的锁状态

select inst_id,

grant_level,

request_level,

resource_name2,

PID,

TRANSACTION_ID0,

TRANSACTION_ID1

from gv$ges_enqueue

where resource_name2 like '52533%';



INST_ID

GRANT_LEVEL

REQUEST_LEVEL

RESOURCE_NAME2

PID

TRANSACTION_ID0

TRANSACTION_ID1

1

1

KJUSERCW

KJUSERCW

52533,0,TM

27730

1835009

33

2

1

KJUSERCW

KJUSERCW

52533,0,TM

0

0

0

3

1

KJUSERPR

KJUSERPR

52533,201926685,IV

7283

0

0

4

1

KJUSERPR

KJUSERPR

52533,201926685,IV

0

0

0

5

2

KJUSERCW

KJUSERCW

52533,0,TM

9231

1703938

111

6

2

KJUSERPR

KJUSERPR

52533,201926685,IV

7200

0

0


KJUSERPRBL锁,KJUSERCW是表级共享锁,KJUSERTM是行级独占锁,KJUSERNL是空锁,KJUSEREXlock table之类命令产生的独占锁


3Buffer Cache中的数据块变化前必需询问GRD的完整实验过程

由于表3中的实验后半段在两个实例上都对表t04209_name做了更改。对于两个实例各自回滚段上的BI而言,激活了一个回滚段的实例立刻成为该段的master实例。如上一节所述回滚段没有真正的object_id,所以使用回滚段号作为该回滚段的object_id。到此我们自然就会得出一个有意思的推论:一个事务产生的new valueold valueBI)可以被两个不同的实例master:因为实例1可以update一个实例2master的数据块,new valuemaster自然是实例2old value由于在实例1的回滚段上所以归实例1master。这样推导下去诸如“gc [current/cr] [multiblock] request”、“gc [current/cr] [2/3]-way“、”gc [current/cr] block busy“、”gc [current/cr] grant 2-way“、”gc [current/cr] [block/grant] congested“和“gc [current/cr] [failure/retry]“等待事件中的currentnew value)和crold value)分别对应的master实例有可能不是同一个。可以顺便验证一下(见表4):


实验第16步:

查看回滚段信息

在任一个实例上执行:

select rs.instance_num,

rs.segment_name,

rs.segment_id

from dba_rollback_segs rs;



INSTANCE_NUM

SEGMENT_NAME

SEGMENT_ID

1

1

SYSTEM

0

2

1

_SYSSMU1$

1

3

1

_SYSSMU2$

2

4

1

_SYSSMU3$

3

5

1

_SYSSMU4$

4

6

1

_SYSSMU5$

5

7

1

_SYSSMU6$

6

8

1

_SYSSMU7$

7

9

1

_SYSSMU8$

8

10

1

_SYSSMU9$

9

11

1

_SYSSMU10$

10

12

2

_SYSSMU11$

11

13

2

_SYSSMU12$

12

14

2

_SYSSMU13$

13

15

2

_SYSSMU14$

14

16

2

_SYSSMU15$

15

17

2

_SYSSMU16$

16

18

2

_SYSSMU17$

17

19

2

_SYSSMU18$

18

20

2

_SYSSMU19$

19

21

2

_SYSSMU20$

20


实验第17步:

查看回滚段正被哪个实例Remaster

在任一个实例上执行:

select * from v$gcspfmaster_info;



FILE_ID

DATA_OBJECT_ID

CURRENT_MASTER

PREVIOUS_MASTER

REMASTER_CNT

1

0↖10.1版本以前,是以文件作为Remaster单元,现在以对象作为单元,这里都是0

1

0

32767表示之前没有发生过Remaster事件

0

2

0

2

0

32767

0

3

0

3

0

32767

0

4

0

4

0

32767

0


4:表3实验过程中伴随的undoGRD信息

4.能够查出某个块Master实例和Owner实例的X$

X$KJBL描述哪一个实例是某个表的带BL锁的块的master实例(见表5)。


让表3中所描述的两个实例继续update,不要停接着做以下的实验(如果两个实例,或其中一个结束了update重新update

实验第18步:

在任一个实例上执行:

创建一个基于X$KJBL的视图,后续实验需要它

create or replace view myview as

select kj.block#, kjblname, kjblname2, kjblowner+1 "OWNER_Instance", kjblmaster+1 "MASTER_Instance", kjbllockp from

(

select kjblname, kjblname2, kjblowner, kjblmaster, kjbllockp,

(substr ( kjblname2, instr(kjblname2,',')+1, instr(kjblname2,',',1,2)-instr(kjblname2,',',1,1)-1))/65536 file#,

substr ( kjblname2, 1, instr(kjblname2,',')-1) block# from x$kjbl

) kj,

(

select block_id block#_begin, block_id+blocks-1 block#_end, e.file_id file#

from dba_extents e where e.owner='HR' and e.segment_name='T04209_UNAME'

) e

where kj.block# between e.block#_begin and e.block#_end order by block# ;

实验第19步:

在任一个实例上执行:

select * from myview;



FILE#

BLOCK#

KJBLNAME

KJBLNAME2

OWNER_Instance

MASTER_Instance

KJBLLOCKP

1

4

387

[0x183][0x40000],[BL]

387,262144,BL

1

1

237EC730

2

4

387

[0x183][0x40000],[BL]

387,262144,BL

2

1

49A35F58

3

4

388

[0x184][0x40000],[BL]

388,262144,BL

2

1

49A31B60

4

4

388

[0x184][0x40000],[BL]

388,262144,BL

1

1

237F38A0

5

4

389

[0x185][0x40000],[BL]

389,262144,BL

1

1

237FA490

6

4

389

[0x185][0x40000],[BL]

389,262144,BL

2

1

49A321D0

7

4

390

[0x186][0x40000],[BL]

390,262144,BL

2

1

49A32368

8

4

390

[0x186][0x40000],[BL]

390,262144,BL

1

1

23BF2560

9

4

391

[0x187][0x40000],[BL]

391,262144,BL

2

1

49A31BE8

10

4

391

[0x187][0x40000],[BL]

391,262144,BL

1

1

237F16F0

...

...

...

...

...

...

...

...


从以上的查询结果可以看出:每个数据块内存拷贝在两个实例的数据库缓冲区缓存中都可以被找到,也就是说每个数据块都有两个个Owner实例,那么证明在近期有两个实例先后修改或访问过它。


实验第20 步:

在任一个实例上执行:

select distinct block#, "MASTER_Instance" from myview order by 1;



BLOCK#

MASTER_Instance

1

387

1

2

388

1

3

389

1

4

390

1

5

391

1

6

392

1

7

393

1

8

394

1

9

395

1

10

396

1

...

...

...

109

502

1

110

503

1

111

504

1

112

505

1

113

506

1

114

507

1

115

508

1

116

509

1

117

510

1

118

511

1

119

512

2从这变成实例2

120

523

2

121

524

2

122

525

2

123

526

2

124

527

2

125

528

2

126

529

2

127

530

2

128

531

2

129

532

2

130

533

2

...

...

...

220

628

2

221

629

2

222

630

2

223

631

2

224

632

2

225

633

2

226

635

2

227

636

2

228

637

2

229

638

2

230

639

2

231

640

1

232

641

1

233

642

1

234

643

1

235

644

1

236

645

1

237

646

1

238

647

1

239

648

1


这说明:从10g以后版本开始,数据块的状态和属主等信息被存储成每128个块的信息一个master单元,即128个数据块的状态和属主等信息构成一个“gcs mastership bucket”。但是要说明以下:一个“gcs mastership bucket”不一定要存满128个块的状态和属主等信息。这样就能理解:超过128个块的表的数据块可以被多个实例分布式地分段master


实验第21步:

在任一个实例上执行:

select count(*) from myview where "OWNER_Instance" <> "MASTER_Instance";



COUNT(*)

1

239


从以上结果可以看到存在大量的数据块的master实例和owner实例不是同一个实例的情况。这是可以预料到的:我们在两个实例上同时密集地OLTP同一张表!这样会有大量的实例间的通信。以下内容来自此刻的AWR报告:


Top 5 Timed Events

Event

Waits

Time(s)

Avg Wait(ms)

% Total Call Time

Wait Class

gc cr block busy

85,181

181

2

44.5

Cluster 对方CR块请求收到,但是无法立即发送

CPU time


79


19.4


gcs log flush sync

37,349

35

1

8.6

Other 日志系统太忙flush不过来

gc cr multi block request

1,623

27

16

6.5

Cluster ← placeholder请求多

gc current grant busy

13,162

20

2

5.0

Cluster 由于master实例和owner实例不是同一个实例导致master实例发送磁盘授权信息延迟或接收延迟。


RAC Statistics


Begin

End

Number of Instances:

2

2


Global Cache Load Profile


Per Second

Per Transaction

Global Cache blocks received:

264.26

1,108.00

Global Cache blocks served:

356.69

1,495.53

GCS/GES messages received:

452.07

1,895.44

GCS/GES messages sent:

462.24

1,938.10

DBWR Fusion writes:

0.16

0.67

Estd Interconnect traffic (KB)

5,146.16



Global Cache Efficiency Percentages (Target local+remote 100%)

Buffer access - local cache %:

99.69

Buffer access - remote cache %:

0.30

Buffer access - disk %:

0.00


Global Cache and Enqueue Services - Workload Characteristics:

Avg global enqueue get time (ms):

0.3

Avg global cache cr block receive time (ms):

2.0

Avg global cache current block receive time (ms):

1.4

Avg global cache cr block build time (ms):

0.1

Avg global cache cr block send time (ms):

0.0

Global cache log flushes for cr blocks served %:

23.9

Avg global cache cr block flush time (ms):

1.5

Avg global cache current block pin time (ms):

0.0

Avg global cache current block send time (ms):

0.0

Global cache log flushes for current blocks served %:

0.2

Avg global cache current block flush time (ms):

1.9


Global Cache and Enqueue Services - Messaging Statistics

Avg message sent queue time (ms):

0.2

Avg message sent queue time on ksxp (ms):

0.8

Avg message received queue time (ms):

0.0

Avg GCS message process time (ms):

0.1

Avg GES message process time (ms):

0.0

% of direct sent messages:

73.86

% of indirect sent messages:

13.11

% of flow controlled messages:

13.03


续篇

本文创建t04209_uname表,和update用的脚本:

create_t04209_uname.sql.zip

update2_t04209_uname.sql.zip

update_t04209_uname.sql.zip

4

鲜花

握手

雷人

路过

鸡蛋

刚表态过的朋友 (4 人)

相关阅读

QQ|手机版|Botang唐波's Oracle Station    

GMT+8, 2017-6-16 16:35 , Processed in 0.124012 second(s), 22 queries .

返回顶部