幼儿饰品瑜伽美体用品微软
投稿投诉
微软创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

RocketMQ源码之DLedger存储实现DLedgerM

  头条创作挑战赛一、前言
  前文我们分析了RocketMQ源码之broker高可用CommitLog管理组件DLedgerCommitLog,本文我们分析DLedgerCommitLog中的mmap内存映射文件存储组件:DLedgerMmapFileStore;二、源码分析DLedgerMmapFileStore抽象父类DLedgerStore;DLedgerMmapFileStore成员变量;DLedgerMmapFileStore构造函数;flush数据服务线程;清理空间服务线程;文件内存映射存储实现启动;追加数据;对数据文件进行截断;以follower身份追加数据;根据索引去查询一个数据条目;数据存储格式及编码;1、DLedgerMmapFileStore抽象父类DLedgerStore存储组件抽象类publicabstractclassDLedgerStore{获取到当前server的成员状态publicMemberStategetMemberState(){returnnull;}作为leader把一个entry追加到磁盘里去publicabstractDLedgerEntryappendAsLeader(DLedgerEntryentry);作为follower把一个entry追加到磁盘里去再追加的时候,我是需要知道是哪个leader同步了这个entry给我的paramentryahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a条目paramleaderTermleader选举周期paramleaderIdleaderidreturnpublicabstractDLedgerEntryappendAsFollower(DLedgerEntryentry,longleaderTerm,StringleaderId);根据索引获取ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志aentrypublicabstractDLedgerEntryget(Longindex);获取已经提交的index索引publicabstractlonggetCommittedIndex();在一轮term里更新已经提交index索引publicvoidupdateCommittedIndex(longterm,longcommittedIndex){}获取结尾termpublicabstractlonggetLedgerEndTerm();获取结尾indexpublicabstractlonggetLedgerEndIndex();获取开始indexpublicabstractlonggetLedgerBeginIndex();更新结尾index和termprotectedvoidupdateLedgerEndIndexAndTerm(){if(getMemberState()!null){getMemberState()。updateLedgerIndexAndTerm(getLedgerEndIndex(),getLedgerEndTerm());}}在存储组件里发起一次flush操作publicvoidflush(){}对指定的leaderterm和id发起一个entry的截断,truncatepubliclongtruncate(DLedgerEntryentry,longleaderTerm,StringleaderId){return1;}存储组件启动publicvoidstartup(){}存储组件停止publicvoidshutdown(){}}2、DLedgerMmapFileStore成员变量基于mmap内存映射文件的存储组件实现,是我们需要重点研究的publicclassDLedgerMmapFileStoreextendsDLedgerStore{publicstaticfinalStringCHECKPOINTFILEcheckpoint;publicstaticfinalStringENDINDEXKEYendIndex;publicstaticfinalStringCOMMITTEDINDEXKEYcommittedIndex;publicstaticfinalintMAGIC11;publicstaticfinalintCURRENTMAGICMAGIC1;publicstaticfinalintINDEXUNITSIZE32;privatestaticLoggerloggerLoggerFactory。getLogger(DLedgerMmapFileStore。class);追加entries钩子publicListappendHooksnewArrayList();开始index索引privatelongledgerBeginIndex1;结束index索引privatelongledgerEndIndex1;已经提交的index索引privatelongcommittedIndex1;已经提交的pos位置privatelongcommittedPos1;结束term条目privatelongledgerEndTerm;dledger核心配置组件privateDLedgerConfigdLedgerConfig;server节点成员状态privateMemberStatememberState;mmap内存映射数据文件listprivateMmapFileListdataFileList;mmap内存映射索引文件listprivateMmapFileListindexFileList;线程本地副本里面的entry缓冲组件privateThreadLocalByteBufferlocalEntryBuffer;线程本地副本里面的index缓冲组件privateThreadLocalByteBufferlocalIndexBuffer;flush数据服务组件privateFlushDataServiceflushDataService;清理空间服务组件privateCleanSpaceServicecleanSpaceService;磁盘是否已经满了标识privatevolatilebooleanisDiskFullfalse;最近一次检查点时间戳privatelonglastCheckPointTimeMsSystem。currentTimeMillis();是否已经加载过的boolean标识privateAtomicBooleanhasLoadednewAtomicBoolean(false);是否已经完成恢复的boolean标识privateAtomicBooleanhasRecoverednewAtomicBoolean(false);完整存储路径setprivatevolatileSetStringfullStorePathsCollections。emptySet();}3、DLedgerMmapFileStore构造函数publicDLedgerMmapFileStore(DLedgerConfigdLedgerConfig,MemberStatememberState){赋值一个dledger配置组件this。dLedgerConfigdLedgerConfig;赋值一个server成员状态组件this。memberStatememberState;我们的dledger数据存储路径里面如果说包含有多路径分隔符if(dLedgerConfig。getDataStorePath()。contains(DLedgerConfig。MULTIPATHSPLITTER)){把数据文件list封装为一个多路径mmap内存映射文件listthis。dataFileListnewMultiPathMmapFileList(dLedgerConfig,dLedgerConfig。getMappedFileSizeForEntryData(),this::getFullStorePaths);}else{把数据文件list封装为一个mmap文件listthis。dataFileListnewMmapFileList(dLedgerConfig。getDataStorePath(),dLedgerConfig。getMappedFileSizeForEntryData());}把索引文件list封装成一个mmap内存映射文件listthis。indexFileListnewMmapFileList(dLedgerConfig。getIndexStorePath(),dLedgerConfig。getMappedFileSizeForEntryIndex());线程副本的内存分配,localentry的内存分配,4mblocalEntryBufferThreadLocal。withInitial(()ByteBuffer。allocate(410241024));线程副本的内存分配,localindex的内存分配,一个索引单元大小(32个字节)2localIndexBufferThreadLocal。withInitial(()ByteBuffer。allocate(INDEXUNITSIZE2));构建从内存里flush数据到磁盘文件里的服务组件flushDataServicenewFlushDataService(DLedgerFlushDataService,logger);构建清理空间服务组件cleanSpaceServicenewCleanSpaceService(DLedgerCleanSpaceService,logger);}4、flush数据服务线程分析
  实际flush动作会调用MmapFileListflush方法,RocketMQ源码分析之文件内存映射对象层MappedFile核心方法分析过,不再赘叙;flush数据服务classFlushDataServiceextendsShutdownAbleThread{publicFlushDataService(Stringname,Loggerlogger){super(name,logger);}他会不断的周期性的运行,但是支持关闭他OverridepublicvoiddoWork(){try{longstartSystem。currentTimeMillis();他会周期性的去触发数据文件的flush动作DLedgerMmapFileStore。this。dataFileList。flush(0);他会周期性的去触发索引文件的flush动作DLedgerMmapFileStore。this。indexFileList。flush(0);longelapsed;if((elapsedDLedgerUtils。elapsed(start))500){logger。info(Flushdatacost{}ms,elapsed);}如果说超过了一个检查点时间间隔,还需要去发起一次检查点持久化if(DLedgerUtils。elapsed(lastCheckPointTimeMs)dLedgerConfig。getCheckPointInterval()){persistCheckPoint();lastCheckPointTimeMsSystem。currentTimeMillis();}休眠flush间隔时间waitForRunning(dLedgerConfig。getFlushFileInterval());}catch(Throwablet){logger。info(Errorin{},getName(),t);DLedgerUtils。sleep(200);}}}5、清理空间服务线程清理空间服务线程classCleanSpaceServiceextendsShutdownAbleThread{获取到磁盘空间已经使用比例doublestoreBaseRatioDLedgerUtils。getDiskPartitionSpaceUsedPercent(dLedgerConfig。getStoreBaseDir());数据存储路径里物理占用比例doubledataRatiocalcDataStorePathPhysicRatio();publicCleanSpaceService(Stringname,Loggerlogger){super(name,logger);}OverridepublicvoiddoWork(){try{storeBaseRatioDLedgerUtils。getDiskPartitionSpaceUsedPercent(dLedgerConfig。getStoreBaseDir());dataRatiocalcDataStorePathPhysicRatio();longhourOfMs3600L1000L;longfileReservedTimeMsdLedgerConfig。getFileReservedHours()hourOfMs;if(fileReservedTimeMshourOfMs){logger。warn(ThefileReservedTimeMs{}issmallerthanhourOfMs{},fileReservedTimeMs,hourOfMs);fileReservedTimeMshourOfMs;}Ifthediskisfull,shouldpreventmoredatatogetinDLedgerMmapFileStore。this。isDiskFullisNeedForbiddenWrite();booleantimeUpisTimeToDelete();booleancheckExpiredisNeedCheckExpired();booleanforceCleanisNeedForceClean();booleanenableForceCleandLedgerConfig。isEnableDiskForceClean();intintervalForcibly1201000;if(timeUpcheckExpired){intcountgetDataFileList()。deleteExpiredFileByTime(fileReservedTimeMs,100,intervalForcibly,forceCleanenableForceClean);if(count0(forceCleanenableForceClean)isDiskFull){logger。info(Cleanspacecount{}timeUp{}checkExpired{}forceClean{}enableForceClean{}diskFull{}storeBaseRatio{}dataRatio{},count,timeUp,checkExpired,forceClean,enableForceClean,isDiskFull,storeBaseRatio,dataRatio);}if(count0){DLedgerMmapFileStore。this。reviseLedgerBeginIndex();}}getDataFileList()。retryDeleteFirstFile(intervalForcibly);waitForRunning(100);}catch(Throwablet){logger。info(Errorin{},getName(),t);DLedgerUtils。sleep(200);}}privatebooleanisTimeToDelete(){StringwhenDLedgerMmapFileStore。this。dLedgerConfig。getDeleteWhen();if(DLedgerUtils。isItTimeToDo(when)){returntrue;}returnfalse;}privatebooleanisNeedCheckExpired(){if(storeBaseRatiodLedgerConfig。getDiskSpaceRatioToCheckExpired()dataRatiodLedgerConfig。getDiskSpaceRatioToCheckExpired()){returntrue;}returnfalse;}privatebooleanisNeedForceClean(){if(storeBaseRatiodLedgerConfig。getDiskSpaceRatioToForceClean()dataRatiodLedgerConfig。getDiskSpaceRatioToForceClean()){returntrue;}returnfalse;}privatebooleanisNeedForbiddenWrite(){if(storeBaseRatiodLedgerConfig。getDiskFullRatio()dataRatiodLedgerConfig。getDiskFullRatio()){returntrue;}returnfalse;}计算数据存储路径物理比例publicdoublecalcDataStorePathPhysicRatio(){SetStringfullStorePathnewHashSet();StringstorePathdLedgerConfig。getDataStorePath();String〔〕pathsstorePath。trim()。split(DLedgerConfig。MULTIPATHSPLITTER);doubleminPhysicRatio100;遍历每一个path路径for(Stringpath:paths){doublephysicRatioDLedgerUtils。isPathExists(path)?DLedgerUtils。getDiskPartitionSpaceUsedPercent(path):1;minPhysicRatioMath。min(minPhysicRatio,physicRatio);if(physicRatiodLedgerConfig。getDiskSpaceRatioToForceClean()){fullStorePath。add(path);}}DLedgerMmapFileStore。this。setFullStorePaths(fullStorePath);returnminPhysicRatio;}}6、文件内存映射存储实现启动对存储组件可以去执行startup启动函数Overridepublicvoidstartup(){数据文件和索引文件加载load();数据恢复recover();flush数据服务组件启动flushDataService。start();清理空间服务组件cleanSpaceService。start();}publicvoidload(){if(!hasLoaded。compareAndSet(false,true)){return;}mmap内存映射数据文件加载和mmap内存映射索引文件加载if(!this。dataFileList。load()!this。indexFileList。load()){logger。error(Loadfilefailed,thisusuallyindicatesfatalerror,youshouldcheckitmanually);System。exit(1);}}7、追加数据我们可以把一条数据entry追加到我们的存储组件里来OverridepublicDLedgerEntryappendAsLeader(DLedgerEntryentry){当前节点的状态是否是Leader,如果不是,则抛出异常PreConditions。check(memberState。isLeader(),DLedgerResponseCode。NOTLEADER);当前磁盘是否已满,其判断依据是DLedger的根目录或数据文件目录的使用率超过了允许使用的最大值,默认值为85PreConditions。check(!isDiskFull,DLedgerResponseCode。DISKFULL);从线程本地副本里获取到一个自己当前线程的数据缓冲区和索引缓冲区ByteBufferdataBufferlocalEntryBuffer。get();ByteBufferindexBufferlocalIndexBuffer。get();把entry数据编码到数据缓冲区里去DLedgerEntryCoder。encode(entry,dataBuffer);通过数据缓冲区里面的remaining可以获取到entry大小intentrySizedataBuffer。remaining();对server成员状态加锁synchronized(memberState){PreConditions。check(memberState。isLeader(),DLedgerResponseCode。NOTLEADER,null);PreConditions。check(memberState。getTransferee()null,DLedgerResponseCode。LEADERTRANSFERRING,null);所以说endindex1了以后,从1到0,随着追加数据累加的索引值longnextIndexledgerEndIndex1;设置一下索引值entry。setIndex(nextIndex);通过server成员状态获取到term第几轮entry。setTerm(memberState。currTerm());设置魔数entry。setMagic(CURRENTMAGIC);把累加索引、当前term、魔数,写入到了数据缓冲区里去DLedgerEntryCoder。setIndexTerm(dataBuffer,nextIndex,memberState。currTerm(),CURRENTMAGIC);我准备把这条数据预追加到我们的数据文件mmapfiles里去longprePosdataFileList。preAppend(dataBuffer。remaining());entry。setPos(prePos);PreConditions。check(prePos!1,DLedgerResponseCode。DISKERROR,null);DLedgerEntryCoder。setPos(dataBuffer,prePos);在正式写入数据之前可以回调我们的追加hook钩子for(AppendHookwriteHook:appendHooks){writeHook。doHook(entry,dataBuffer。slice(),DLedgerEntry。BODYOFFSET);}数据文件mmapfiles追加对应的数据longdataPosdataFileList。append(dataBuffer。array(),0,dataBuffer。remaining());PreConditions。check(dataPos!1,DLedgerResponseCode。DISKERROR,null);PreConditions。check(dataPosprePos,DLedgerResponseCode。DISKERROR,null);关于dledger索引追加写入DLedgerEntryCoder。encodeIndex(dataPos,entrySize,CURRENTMAGIC,nextIndex,memberState。currTerm(),indexBuffer);索引文件mmapfiles追加一条索引进文件longindexPosindexFileList。append(indexBuffer。array(),0,indexBuffer。remaining(),false);PreConditions。check(indexPosentry。getIndex()INDEXUNITSIZE,DLedgerResponseCode。DISKERROR,null);if(logger。isDebugEnabled()){logger。info(〔{}〕AppendasLeader{}{},memberState。getSelfId(),entry。getIndex(),entry。getBody()。length);}每次追加一条数据写入,写入完了以后endIndex就会累加ledgerEndIndex;ledgerEndTermmemberState。currTerm();拿到成员状态的当前termif(ledgerBeginIndex1){ledgerBeginIndexledgerEndIndex;}updateLedgerEndIndexAndTerm();returnentry;}}8、对数据文件进行截断对数据文件做一个截断,有一部分数据就直接不要了Overridepubliclongtruncate(DLedgerEntryentry,longleaderTerm,StringleaderId){PreConditions。check(memberState。isFollower(),DLedgerResponseCode。NOTFOLLOWER,null);获取到线程本地副本里的数据缓冲区和索引缓冲区ByteBufferdataBufferlocalEntryBuffer。get();ByteBufferindexBufferlocalIndexBuffer。get();DLedgerEntryCoder。encode(entry,dataBuffer);intentrySizedataBuffer。remaining();synchronized(memberState){PreConditions。check(memberState。isFollower(),DLedgerResponseCode。NOTFOLLOWER,roles,memberState。getRole());PreConditions。check(leaderTermmemberState。currTerm(),DLedgerResponseCode。INCONSISTENTTERM,termd!d,leaderTerm,memberState。currTerm());PreConditions。check(leaderId。equals(memberState。getLeaderId()),DLedgerResponseCode。INCONSISTENTLEADER,leaderIds!s,leaderId,memberState。getLeaderId());直接去根据索引读取一条数据出来booleanexistedEntry;try{DLedgerEntrytmpget(entry。getIndex());existedEntryentry。equals(tmp);}catch(Throwableignored){existedEntryfalse;}longtruncatePosexistedEntry?entry。getPos()entry。getSize():entry。getPos();if(truncatePos!dataFileList。getMaxWrotePosition()){logger。warn(〔TRUNCATE〕leaderId{}index{}truncatePos{}!maxPos{},thisisusuallyhappenedontheoldleader,leaderId,entry。getIndex(),truncatePos,dataFileList。getMaxWrotePosition());}对这个位置开始的数据发起一个截断dataFileList。truncateOffset(truncatePos);if(dataFileList。getMaxWrotePosition()!truncatePos){logger。warn(〔TRUNCATE〕rebuildfordatawrotePos:{}!truncatePos:{},dataFileList。getMaxWrotePosition(),truncatePos);PreConditions。check(dataFileList。rebuildWithPos(truncatePos),DLedgerResponseCode。DISKERROR,rebuilddatatruncatePosd,truncatePos);}修订数据文件mmapfiles的已经flush位置reviseDataFileListFlushedWhere(truncatePos);if(!existedEntry){longdataPosdataFileList。append(dataBuffer。array(),0,dataBuffer。remaining());PreConditions。check(dataPosentry。getPos(),DLedgerResponseCode。DISKERROR,d!d,dataPos,entry。getPos());}数据文件做了一个截断,索引文件也需要做一个截断longtruncateIndexOffsetentry。getIndex()INDEXUNITSIZE;indexFileList。truncateOffset(truncateIndexOffset);if(indexFileList。getMaxWrotePosition()!truncateIndexOffset){logger。warn(〔TRUNCATE〕rebuildforindexwrotePos:{}!truncatePos:{},indexFileList。getMaxWrotePosition(),truncateIndexOffset);PreConditions。check(indexFileList。rebuildWithPos(truncateIndexOffset),DLedgerResponseCode。DISKERROR,rebuildindextruncatePosd,truncateIndexOffset);}reviseIndexFileListFlushedWhere(truncateIndexOffset);DLedgerEntryCoder。encodeIndex(entry。getPos(),entrySize,entry。getMagic(),entry。getIndex(),entry。getTerm(),indexBuffer);longindexPosindexFileList。append(indexBuffer。array(),0,indexBuffer。remaining(),false);PreConditions。check(indexPosentry。getIndex()INDEXUNITSIZE,DLedgerResponseCode。DISKERROR,null);ledgerEndTermentry。getTerm();ledgerEndIndexentry。getIndex();reviseLedgerBeginIndex();updateLedgerEndIndexAndTerm();returnentry。getIndex();}}9、以follower身份追加数据以follower身份追加数据OverridepublicDLedgerEntryappendAsFollower(DLedgerEntryentry,longleaderTerm,StringleaderId){PreConditions。check(memberState。isFollower(),DLedgerResponseCode。NOTFOLLOWER,roles,memberState。getRole());PreConditions。check(!isDiskFull,DLedgerResponseCode。DISKFULL);数据缓冲区和索引缓冲区ByteBufferdataBufferlocalEntryBuffer。get();ByteBufferindexBufferlocalIndexBuffer。get();DLedgerEntryCoder。encode(entry,dataBuffer);intentrySizedataBuffer。remaining();synchronized(memberState){PreConditions。check(memberState。isFollower(),DLedgerResponseCode。NOTFOLLOWER,roles,memberState。getRole());longnextIndexledgerEndIndex1;PreConditions。check(nextIndexentry。getIndex(),DLedgerResponseCode。INCONSISTENTINDEX,null);PreConditions。check(leaderTermmemberState。currTerm(),DLedgerResponseCode。INCONSISTENTTERM,null);PreConditions。check(leaderId。equals(memberState。getLeaderId()),DLedgerResponseCode。INCONSISTENTLEADER,null);在指定位置里追加数据进去longdataPosdataFileList。append(dataBuffer。array(),0,dataBuffer。remaining());PreConditions。check(dataPosentry。getPos(),DLedgerResponseCode。DISKERROR,d!d,dataPos,entry。getPos());DLedgerEntryCoder。encodeIndex(dataPos,entrySize,entry。getMagic(),entry。getIndex(),entry。getTerm(),indexBuffer);追加索引数据longindexPosindexFileList。append(indexBuffer。array(),0,indexBuffer。remaining(),false);PreConditions。check(indexPosentry。getIndex()INDEXUNITSIZE,DLedgerResponseCode。DISKERROR,null);ledgerEndTermentry。getTerm();ledgerEndIndexentry。getIndex();if(ledgerBeginIndex1){ledgerBeginIndexledgerEndIndex;}更新结尾index和termupdateLedgerEndIndexAndTerm();returnentry;}}10、根据索引去查询一个数据条目根据索引去查询一个数据条目OverridepublicDLedgerEntryget(Longindex){indexCheck(index);定义好索引内存缓冲片段和数据内存缓冲片段SelectMmapBufferResultindexSbrnull;SelectMmapBufferResultdataSbrnull;try{直接通过索引文件mmapfiles去查询数据index本身其实第几条索引,每一条索引可以是一个单元是有自己大小,所以定位索引的偏移量indexunitsize,从那个位置开始读取unitsize大小的一条数据indexSbrindexFileList。getData(indexINDEXUNITSIZE,INDEXUNITSIZE);PreConditions。check(indexSbr!nullindexSbr。getByteBuffer()!null,DLedgerResponseCode。DISKERROR,Getnullindexford,index);indexSbr。getByteBuffer()。getInt();magiclongposindexSbr。getByteBuffer()。getLong();intsizeindexSbr。getByteBuffer()。getInt();根据数据位置和大小,再次从数据文件mmapfiles里面读取出来一条数据就可以了dataSbrdataFileList。getData(pos,size);PreConditions。check(dataSbr!nulldataSbr。getByteBuffer()!null,DLedgerResponseCode。DISKERROR,Getnulldataford,index);把这个数据做一个解码DLedgerEntrydLedgerEntryDLedgerEntryCoder。decode(dataSbr。getByteBuffer());PreConditions。check(posdLedgerEntry。getPos(),DLedgerResponseCode。DISKERROR,d!d,pos,dLedgerEntry。getPos());returndLedgerEntry;}finally{把之前读取的索引和数据的缓冲片段做一个释放SelectMmapBufferResult。release(indexSbr);SelectMmapBufferResult。release(dataSbr);}}11、数据存储格式及编码
  日志条目
  DLedgerEntryCoderencode()编码paramentryahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a条目parambyteBuffer缓冲区publicstaticvoidencode(DLedgerEntryentry,ByteBufferbyteBuffer){byteBuffer。clear();intsizeentry。computeSizeInBytes();alwaysputmagiconthefirstposition魔数,4字节byteBuffer。putInt(entry。getMagic());条目总长度,包含Header(协议头)消息体,占4字节byteBuffer。putInt(size);当前条目的index,占8字节byteBuffer。putLong(entry。getIndex());当前条目所属的投票轮次,占8字节byteBuffer。putLong(entry。getTerm());该条目的物理偏移量,类似于commitlog文件的物理偏移量,占8字节byteBuffer。putLong(entry。getPos());保留字段,当前版本未使用,占4字节byteBuffer。putInt(entry。getChannel());当前版本未使用,占4字节byteBuffer。putInt(entry。getChainCrc());body的CRC校验和,用来区分数据是否损坏,占4字节。byteBuffer。putInt(entry。getBodyCrc());用来存储body的长度,占4个字节。byteBuffer。putInt(entry。getBody()。length);具体消息的内容。byteBuffer。put(entry。getBody());byteBuffer。flip();}
  日志索引
  DLedgerEntryCoderencodeIndex()ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a索引编码paramposahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a条目在文件的偏移量paramsize条目大小parammagic魔数paramindex索引paramterm投票轮次parambyteBuffer缓冲区publicstaticvoidencodeIndex(longpos,intsize,intmagic,longindex,longterm,ByteBufferbyteBuffer){byteBuffer。clear();魔数,4字节byteBuffer。putInt(magic);ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a条目在文件的偏移量,8字节byteBuffer。putLong(pos);条目大小,4字节byteBuffer。putInt(size);ahrefhttps:www。bs178。comrizhitargetblankclassinfotextkey日志a条目索引,8字节byteBuffer。putLong(index);投票轮次,8字节byteBuffer。putLong(term);byteBuffer。flip();}

咳嗽痰多,痰稠还黏腻!李医生教你一个方,健脾祛湿,益肺除痰大家好,我是李医生。立秋刚过,暑气未消。这个时候啊,一天之内气温变化大,稍不注意就容易着凉,出现发热怕冷,咳嗽痰多,鼻塞流涕的情况。今天李医生就教你一个方药,驱逐寒……夏日皮肤问题多?3个方法,有效抗衰老,养出美白肌夏天紫外线强,皮肤问题多(日光性皮炎、毛囊炎、长痣等),要密切关注痣的问题。痣(一般指色素痣)是人类常见的良性皮肤肿瘤,大多数增生缓慢,或持续多年无变化,反复刺激(紫外线……14年前,北京奥运会上顶替刘岩独舞的殷硕,如今怎么样了?出生于舞蹈世家,21岁的殷硕在08年北京奥运会上顶替刘岩,在《丝路》节目中为全世界观众带来了两分钟精彩的独舞,被网友称为飞天女神。此后邀约不断,进入东方歌舞团,上多台舞蹈……放松身心,你永远可以相信云南2022年的暑假,被疫情逼疯了的人们,造就了半个中国的人都在云南。云南之于中国是北欧级的存在,环境优美、气候宜人这是大多数人比较熟知的描述。以下且听我细细道来。气候……贵州征集2022最美车窗风景线5月29日起报名5月29日,贵州启动车窗风景线,山地贵州行2022贵州最美风景在路上自驾路线征集活动,本次征集活动是国际山地旅游日的子活动之一。加榜梯田王晓摄韭菜坪征集活动旨……国产芯片厂商高兴了芯片大神JimKeller称,RISCV必众所周知,国内的众多芯片企业,一直在大力发展RISCV芯片,因为这个芯片是免费、开源的,不会被卡脖子。特别是阿里,不仅基于RISCV开发芯片,更是开发芯片平台、IP等,助……姚明的队友系列著名姚黑鲍勃苏拉火箭姚麦时代的第一年,球队的控球后卫位置有巨大的短板,在范甘迪强调防守的战术体系里,控卫的职责是防守中努力防守,进攻中控制节奏,在阵地进攻中第一时间找姚明和麦迪两个强点,利用二……国乒24人集体宣布退赛,刘国梁做争议决定!又被日本抢走重要冠北京时间12月9日,在国际乒联举办的葡萄牙世青赛的比赛当中,中国队在19岁级别的5个单项里面拿到了三个冠军,丢掉了其中的两个。男双遭遇到一轮游,混……iPhone12换小米12,我发现MIUI三个实用小功能,用6年苹果老用户初次尝试安卓,选定小米12。换机一周,我总结了MIUI13三个非常实用的小功能,iPhone12ProMax不具备,用一次就回不去了。一、小米闻声小米……有6类股票我会避而不买,你买了吗?看彼得林奇怎么说的昨天写了一篇选股的13条准则,今天分享一下哪些类型的股票是我们要极力避开的。股票投资是在很多的不确定性里面去挑选成功概率比较高的一些公司的游戏,所以要避免所有钱押注到单独……一孕妇刚生完头胎一月又要生二胎,在场的医生都十分诧异从来没有见过这么离奇的孕妇,生完头胎一个月产妇马上又要生二胎,从医二十年的医生都表示十分诧异。医生为范晓莉做了一次全面检查。然而接下来的一幕让所有人惊出一身冷汗!令所有人……暗黑2起源战网开荒玩法(新手攻略篇)哈喽,大家好,我是大家喜爱的电玩张麻子,最近玩了个刚开荒的起源微变暗金乱入战网,感觉挺有意思的,很多老铁不会玩,上手有点蒙圈,今天给大家搞一个新手攻略篇玩法介绍。首先呢,……
38岁李宇春身患重病坐轮椅出行余生珍贵,金山银山都不如平平安最近38岁的李宇春身患重病坐轮椅出行细节曝光,让我们对人生更是有了新的触动。许多明星让我们看到他们功成名就的同时,也在他们到了一定年纪的背后看到了他们身上积攒多年的伤痛。……谣言的定义科学吗?谣零零计划谣言,指的是没有相应事实基础,却被捏造出来并通过一定手段推动传播的言论。受众未被明确或暗示虚构的前提下,被捏造及传播的与事实不同甚至相反的言论即是谣言。以上是百……山姆必囤美食Top12,全家都爱吃来源:宝妈生活研究所有娃后,山姆超市就成了我给娃囤货的首选,现在娃都上幼儿园了,依旧保持着每月在那儿大采购1次的习惯。在此期间,我也挖到了不少山姆好物,今天就来和宝妈们分……青春逢盛世,奋斗正当时长路漫漫,唯有奋斗,沿途的风景总是最美。人生未有穷途,整装尚待奔赴,未来被历史照亮,我们要以义无反顾的奋斗姿态,去创造让世界刮目相看的人间奇迹。为梦狂奔的路上,有风急雨骤……孩子发烧不是小事情孩子一发烧家长就着急,为什么孩子会发烧,体温为什么会超过38度,37度5以上,这里面底层的逻辑是由于体内的炎症因子释放,各位看看炎症的炎怎么写,两个火,所以我们中医经常说我们要……台式机组装配置清单大全,普通办公专业设计娱乐游戏台式机组装,就像房屋装修,可以完全按照自己的喜好去DIY,但种类繁多的配件又让人必须得花精力去琢磨,如何才能在有限的预算内,达成最理想的效果。当然台式机组装也有捷径,可以直接照……又飒又美!中国18岁体操女神展示世锦赛金牌,前3上演超萌身高北京时间11月6日凌晨,体操世锦赛首个单项决赛日,中国选手韦筱圆以全场最高的6。6难度得到14。966分,成功卫冕女子高低杠冠军。韦筱圆,毫无疑问是目前中国体操女队最大的亮点了……120平米使用的家庭路由器,推荐这三款今天朋友问120平米的家里用什么千兆WiFi6路由器,最好有儿童管理。600以元有三个选择,中兴AX5400Pro,华为AX6还有小米AX6000。华为AX6……穿越火线枪战王者什么枪更容易上手,小编教你新手如何选择穿越火线枪战王者是一款非常经典的枪战游戏了,是很多玩家们都喜欢游玩的一款枪战游戏,在穿越火线里面有各种各样的枪械,但是每种枪械的上手难度是不一样的,所以新手玩家选择一把容易上手……小蓝帽护卫海洋蓝一湾海水抱远山,朝听鸟语暮看霞,青岛的海实在是太美了!刘海豹自豪地抚摸着自己戴的那顶小蓝帽。3年前,他对青岛大海的印象一言难尽:大片的浒苔被海浪冲到岸边,暴晒后发出恶臭;……7场4胜3平!北京国安这次换帅走对了,斯坦利帮御林军找回强队本赛季,国安初期由谢峰执掌教鞭,但谢峰未能带领国安找到感觉,赛季中期,国安果断换帅,请回了原预备队主帅斯坦利。而斯坦利上任之后,国安7场比赛4胜3平保持不败,包括击败海港、逼平……发箍与短发来源春雏集知识星球你觉得,我把头发也弄上去怎么样?,同事边说边把前额的头发梳上去,露出了平常见不着的脑门。看习惯就好了,我盯着他回道,看见同事用手机屏幕当做镜子,看……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网