版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
技术创新,变革未来借鉴Oracle深入修改MySQL/PostgreSQL内核内容介绍借鉴Oracle增进PG/MYSQL内核实践:逻辑读的改进事务ID的可改进之处借鉴Oracle的计算与存储分离、可计算存储架构数据库最频繁的操作:逻辑读RedoSize是字节数,并不是次数。每秒超过52万次逻辑读,如果一次逻辑以读次可数以而节省论1:毫最高的是logicalread。秒,52万次逻辑读,共可以节省520秒的CPU消耗。性能还不是最主要的。试想,如果一个路口,每秒要经
过52万辆车,万一这个路口出现事故,那怕只停一秒,就
会有52万辆车拥堵。这就是竞争带来的隐患。对于高频的操作,除性能之外,竞争,也是要关注的点。
PostgreSQL逻辑读:ShardBuffer的HASH表NODE NODEPostgreSQL逻辑读:BufferAlloc()函数//计算HASH值10121015INIT_BUFFERTAG(newTag,smgr->smgr_rnode.node,forkNum,blockNum);newHash=BufTableHashCode(&newTag);//根据HASH值,得到BufferMappingPartitionLock1016 newPartitionLock=BufMappingPartitionLock(newHash);//以共享模式持有BufferMappingPartitionLock1019 LWLockAcquire(newPartitionLock,LW_SHARED);//搜索HASH表1020 buf_id=BufTableLookup(&newTag,newHash);//如果找到了,Buffer命中,进入条件。如果没找到,跳过此if语句,开始物理读102110221057if(buf_id>=
0){…………return
buf;}开始物理读PostgreSQL逻辑读:BufferAlloc()函数//如果找到了,进入条件。如果没找到,跳过此if语句,开始物理读10211022if(buf_id>=
0){//得到BufferDescripter结构:1028 buf=GetBufferDescriptor(buf_id);//在BufferDescripter结构上中Pin锁:1030 valid=PinBuffer(buf,strategy);//释放BufferMappingPartitionLock1033 LWLockRelease(newPartitionLock);//BufferAlloc()结束,进入读取行数据模块1056 returnbuf;1057 }//Buffer未命中,开始物理读10631078LWLockRelease(newPartitionLock);buf=StrategyGetBuffer(strategy,
&buf_state);PostgreSQL逻辑读:BufferAlloc()函数//Buffer未命中,开始物理读1063 LWLockRelease(newPartitionLock);//选择一个可覆盖页(牺牲页):1078 buf=StrategyGetBuffer(strategy,&buf_state);//计算牺牲页的HASH值11801181oldTag=buf->tag;oldHash=
BufTableHashCode(&oldTag);//计算牺牲页对应的BufferMappingPartitionLock1182 oldPartitionLock=
BufMappingPartitionLock(oldHash);//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//在HASH表中,新的位置,插入一个Bucket1221 buf_id=BufTableInsert(&newTag,newHash,buf->buf_id);PostgreSQL逻辑读:BufferAlloc()函数//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//加BufferMappingPartitionLock,独占模式。
//在HASH表中,新的位置,插入一个Bucket1221 buf_id=BufTableInsert(&newTag,newHash,buf->buf_id);//删除牺牲页在HASH表中的Bucket1321 BufTableDelete(&oldTag,oldHash);//释放BufferMappingPartitionLock13231326LWLockRelease(oldPartitionLock);LWLockRelease(newPartitionLock);内容介PostgreSQL逻辑读:HASH锁BufferMappingPartitionLock计算规则:127#defineBufTableHashPartition(hashcode)\128 ((hashcode)%NUM_BUFFER_PARTITIONS)/*Numberofpartitionsofthesharedbuffermapping
hashtable*/#defineNUM_BUFFER_PARTITIONS
128即:MainLWLockArray[45+HASH值%128].lock#defineBufMappingPartitionLock(hashcode)
\(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET+
\131BufTableHashPartition(hashcode)].lock)HASH值%128代表了什么:BufferMappingPartitionLock数量有128个。
MySQL逻辑读:HASH表buf_pool:page_hash:cells:n_cells:sync_obj.rw_locksn_sync_obj:
16Lock
0Lock
1…………Lock
15Node
0Node
1………………………………Cells:pageframelock……pageframelock……buf_block_t:MySQL逻辑读简要流程从buf_page_get_gen()开始:4157 Buf_fetch_normalfetch(page_id,page_size);4167 return
(fetch.single_page());进入Buf_fetch_normal::single_page():3968template<typenameT>3969buf_block_t*Buf_fetch<T>::single_page(){3975if(static_cast<T*>(this)->get(block)==DB_NOT_FOUND)
{3976return
(nullptr);3977}MySQL逻辑读简要流程3415dberr_tBuf_fetch_normal::get(buf_block_t*&block){3417 for(;;)
{//
计算HASH值
得到HASH表锁
搜索HASH链3421 block=
lookup();//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果HASH表中找到不相应Buffer,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读//如果逻辑读没有命中,开始物理读MySQL逻辑读简要流程3489template<typename
T>3490buf_block_t*Buf_fetch<T>::lookup()
{//计算HASH值,并根据HASH值得到Hash表锁3491 m_hash_lock=buf_page_hash_lock_get(m_buf_pool,m_page_id);//
加HASH表锁3495 rw_lock_s_lock(m_hash_lock);//
搜索HASH表3516if(block==nullptr)
{3517block=reinterpret_cast<buf_block_t
*>(3518buf_page_hash_get_low(m_buf_pool,
m_page_id));3519}MySQL逻辑读简要流程//计算HASH值,并根据HASH值得到3491 m_hash_lock=buf_page_hash_lock_get(m_buf_pool,m_page_id);2003/**Getappropriatepage_hash_lock.
*/2004#definebuf_page_hash_lock_get(buf_pool,page_id)\2005 hash_get_lock((buf_pool)->page_hash,
(page_id).fold())hash_get_lock((buf_pool)->page_hash,
(page_id).fold())计
算Fload值:page_id_t::flod():179 m_fold=(m_space<<20)+m_space+m_page_no;相当于:m_space*1024*1024+m_space+m_page_noMySQL逻辑读简要流程//计算HASH值,并根据HASH值得到HASHLock:3491 m_hash_lock=buf_page_hash_lock_get(m_buf_pool,m_page_id);key:参数,就是flod。UT_HASH_RANDOM_MASK2:宏定义,值1653893711。table_size:buf_pool->page_hash->n_cells,17393。
hash_get_lock((buf_pool)->page_hash,
(page_id).fold())hash_get_sync_obj_index(table,
fold);ut_2pow_remainder(hash_calc_hash(fold,table),table->n_sync_obj)ut_hash_ulint(fold,
table->n_cells) //
最终的计算HASH值的函数:121 key=key^UT_HASH_RANDOM_MASK2;122123 return(key%
table_size);ut_2pow_remainder的定义:188#defineut_2pow_remainder(n,m)((n)&((m)-1))n:hash_calc_hash(fold,table)的返回值,刚计算出的HASH值m:table->n_sync_obj,即buf_pool->page_hash->n_sync_obj,值为16。ut_2pow_remainder的作用:Hash值%m。
最终,HASH锁的定位:buf_pool->sync_obj.rw_locks+宏ut_2pow_remainder的结果MySQL逻辑读简要流程//计算HASH值,并根据HASH值得到3491 m_hash_lock=buf_page_hash_lock_get(m_buf_pool,m_page_id);hash_get_lock((buf_pool)->page_hash,(page_id).fold())hash_get_Msyync_SobQj_LindexH(tAablSe,HfoldL);ock数量:ut_2pow_remainder(hash_calc_hash(fold,table),table->n_sync_obj)16个。MySQL逻辑读简要流程物理读时的HASH表锁:在buf_read_page_low()中:90 bpage=buf_page_init_for_read(err,mode,page_id,page_size,unzip);在buf_page_init_for_read()中:4616 mutex_enter(&buf_pool->LRU_list_mutex);4617 4618 hash_lock=buf_page_hash_lock_get(buf_pool,page_id);4619 4620 rw_lock_x_lock(hash_lock);46214622 buf_page_t*watch_page;逻辑读简要流程总结逻辑读流程总结:①
计算HASH值②
根据HASH值,计算并得到HASH表锁③
共享方式申请HASH表锁④
搜索HASH表⑤
如果找到目标Buffer⑥ Pin住Buffer⑦
释放HASH表锁如果HASH表中没有找到目标Buffer换独占HASH表锁物理读Oracle逻辑读流程CBCLatch:全称CacheBuffersChainsLatch,就是HASH表锁,也就是PG中的BufferParittionMappingLock,MySQL中的HashLock。
Oracle的HASH函数代码int
sp1=0x11;intsp2=0x7f;int
sp3=0x7;inthash_header=0x394953140;hash(intp1,intp2){intuk=p1;int
rdba=p2;intv1,v2;inttarget_addr;uk=uk<<0x11+rdba;uk=(0x9e370001*uk)&0x00000000FFFFFFFF;uk=uk>>sp1;v1=uk&sp2;v1=v1<<0x4;v2=uk>>0xsp3;v2=v2<<0x4;target_addr=hash_header+v2+v1;}Oracle的HASH函数代码Oracle中HASH表中Bucket的数量:计算规则,buffer数量的两倍。CBCLatch数量:HASHBucket数量的除4。
假设有64GB的数据缓存(BufferCache、ShardBuffers、BufferPool),HASH锁的数量:页数量:8,388,608HashBucket数量:16,777,216HASH锁数量:4,194,304PostgreSQL
:
128个MySQL:16*Instance个HASH锁的影响逻辑影读间响并的不关阻键塞
点:物理读。因为物理读会造成竞争。逻辑以读与前物文理例读子互相中阻每塞秒52万次逻辑读为例,假设HashLock的数量是128,520000/128,等于4062。也就是说,每秒中会有4062次逻辑读要申物理请读与同物一理个读H互a相s阻h塞Lock。相当于每秒52万辆车,不是过一个路口,是过128个路口,这当然分
散了只有一个路口的竞争,但是128个路口也有点不够啊。每个路口
每秒会有4062辆车。
HASH锁的影响HASH锁数量少,在马达驱动的机械硬盘
时代,不是问题。机械硬盘20毫秒的I/O已经可以认为是
还可以的速度。如今的硬件设备,I/O响应时间已经可
以降至20微秒(提升1000倍)。HASH锁导致的高竞争频率,在先进的硬
件设备下,已经有可能成为竞争的焦点。
修改内核
减少竞争
增进性能PostgreSQL:#defineBufTableHashPartition(hashcode)\((hashcode)%NUM_BUFFER_PARTITIONS)#defineBufMappingPartitionLock(hashcode)\130131(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET+\BufTableHashPartition(hashcode)].lock)/*Numberofpartitionsofthesharedbuffermappinghashtable*/#defineNUM_BUFFER_PARTITIONS128即:MainLWLockArray[45+HASH值%128].lock它在src/include/storage/lwlock.h文件中修改内核
减少竞争
增进性能hashtable*//*Number
o#define
NUM即:MainLWLockArray它在src/include修改代码十分简单Lock增加了100倍。相比对外围功能动算是修改源码。fpartitionsofthesharedbuffermapping_BUFFER_PARTITIONS12800[45+HASH值%128].lock/storage/lwlock.h文件中,将128改为12800,将BufferMappingPatition辄成千上万行的修改,加两“0”,这种修改几乎不能修改内核
减少竞争
增进性能错误:sharedbufferhashtablecorrupted[postgres@pg03vage]$ERROR: sharedbufferhashtablecorruptedCONTEXT: SQLstatement"EXECUTEcmtest(14988750)"PL/pgSQLfunctioninline_code_blockline13atEXECUTEERROR: sharedbufferhashtablecorrupted像宪法一样,字少,但核心,哪怕动一个字,都有可能产生难以预料的后果修改内核
减少竞争
增进性能Bucket
1…………Bucket
9Bucket
NBucket
1Bucket
2……Bucket
74……Bucket
256NodeLink3559065930rnodeforkNumblockNumIDLink2247461194NodernodeforkNumblockNumID修改内核
减少竞争
增进性能Bucket
1…………Bucket
9Bucket
NBucket
1Bucket
2……Bucket
74……Bucket
256NodeLink3559065930rnodeforkNumblockNumIDLink2247461194NodernodeforkNumblockNumID3559065930%
128=743559065930%
12800=3302247461194%
128=742247461194%
12800=11594修改内核
减少竞争
增进性能mysql>showvariableslike'innodb_page_hash_locks';+ + +|Variable_name |Value|+ + +|innodb_page_hash_locks|16 |+ + +1rowinset(0.02sec)两点限制:只能增大到1024只在Debug模式下,才有此参数修改内核
减少竞争
增进性能修改内核
减少竞争
增进性能修改内核
减少竞争
增进性能使用的动态内核跟踪语言:systemtap,统计脚本comp2.stp,局部代码:统计逻辑读次数:probeprocess("postgres").function("FileRead"){if($amount==8192)pread_num<<<1}统计逻辑读时间:probeprocess("postgres").function("BufferAlloc"){lgr[pid(),"BufferAlloc"]=1tm1[pid()]=gettimeofday_us()}probeprocess("postgres").function("ReadBuffer_common").return{lgr[pid(),"BufferAlloc"]=0lgr[pid(),"LWLockAcquire"]=0lgr[pid(),"StrategyGetBuffer"]=0lnum<<<1tm2<<<gettimeofday_us()-tm1[pid()]修改内核
减少竞争
增进性能succ:成功获得BufferMappingPartitionLock次数fail:申请BufferMappingPartitionLock失败,遇到阻塞次数succ_p和fail_p,是物理读时成功获得锁的次数,和遇到阻塞次数count:逻辑读次数avg:逻辑读平均响应时间max:逻辑读最长响应时间pysical:物理读次数无标题的列:BufferMappingPartitionLock申请失败的次数和物理读的比值。如果此列值为20,说明100次物理读,
会引发20次锁竞争。
修改内核
减少竞争
增进性能修改前:修改后:修改内核
减少竞争
增进性能慢速存储设备上的测试,每秒物理读次数较低,HASH锁数量多与少,基本不影响竞争。
修改内核
减少竞争
增进性能修改前:修改后:修改内核
减少竞争
增进性能修改前:修改后:修改内核
减少竞争
增进性能修改前总耗时:16,026,303.292毫秒
修改后总耗时:14,443,980.719毫秒MySQL的事务ID获取机制UNIV_INLINEtrx_id_ttrx_sys_get_new_trx_id(){ut_ad(trx_sys_mutex_own());318/*VERYimportant:afterthedatabaseisstarted,max_trx_idvalueisdivisiblebyTRX_SYS_TRX_ID_WRITE_MARGIN,andthefollowingifwillevaluatetoTRUEwhenthisfunctionisfirsttimecalled,andthevaluefortrxidwillbewrittentodisk-basedheader!Thustrxidvalueswillnotoverlapwhenthedatabaseisrepeatedlystarted!*/325if(!(trx_sys->max_trx_id%TRX_SYS_TRX_ID_WRITE_MARGIN)){trx_sys_flush_max_trx_id();328 }329330 return(trx_sys->max_trx_id++);331}MySQL的事务ID获取机制Select操作,在trx_start_low()中调用trx_sys_get_new_trx_id():1280 trx_sys_mutex_enter();12811282 trx->id=trx_sys_get_new_trx_id();DML操作,在trx_set_rw_mode()中调用trx_sys_get_new_trx_id():3059 mutex_enter(&trx_sys->mutex);30603061 ut_ad(trx->id==0);3062 trx->id=trx_sys_get_new_trx_id();PostgreSQL事务ID的获取只读事务(Select)不会增加事务ID读写事务增加事务ID的方式:GetNewTransactionId():76 LWLockAcquire(XidGenLock,LW_EXCLUSIVE); //以独占方式,得到全局的XidGenLock锁77full_xid=ShmemVariableCache->nextFullXid;//从ShmemVariableCache->nextFullXid中,得到XID(即事
务ID)xid=XidFromFullTransactionId(full_xid);#defineXidFromFullTransactionId(x) ((uint32)(x).value)PostgreSQL事务ID的获取增加ShmemVariableCache->nextFullXid:185 FullTransactionIdAdvance(&ShmemVariableCache->nextFullXid);staticinline
voidFullTransactionIdAdvance(FullTransactionId*des
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 厂区环保运维员岗位面试题及答案
- 病区抢救药品效期排查管理规定
- 2025年饲料中氨基酸检测人员技能比武试题附带解析
- 医院门诊流程管理手册(标准版)
- 医院信息化管理与医疗事故防范手册
- 管网沟槽开挖技术交底
- 2025-2026年江苏省护士资格考试专业实务模拟试题
- 2026年人教版高三物理选修3-1第一章电场习题
- 2025-2026年天津市北师大版高三生物第4课遗传学基础测试题
- 成都一诊-2026届高三-2025年12月-政治-试题
- 2026年浙江经贸职业技术学院高职单招笔试英语试题库含答案解析3套试卷
- 青海2026年省考公务员《行政职业能力测验》考试真题(完整版)
- 2026语文新教材 2026年秋期新教材统编版六年级上册语文教材分析解读 教学课件
- 节能技术在化工中创新课题申报书
- 《中华人民共和国生态环境法典》应知应会测试题100道
- 船台施工方案
- 2025年重庆市从“五方面人员”中选拔乡镇领导班子成员考试历年参考题库含答案详解
- 诸暨水务集团招聘试卷
- 岗位hes责任制度
- 2026第二届全国红旗杯班组长大赛考试备考核心试题库500题
- 医疗器械公司介绍
评论
0/150
提交评论