日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

大量更新后数据膨胀_段合并的原理探寻

發(fā)布時(shí)間:2024/2/28 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 大量更新后数据膨胀_段合并的原理探寻 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 問(wèn)題
    • 問(wèn)題探尋
    • lucene的段合并機(jī)制
      • 1. allowedSegCountInt 的計(jì)算方式
      • 2. 第5步的計(jì)算過(guò)程,就是排除正在合并的段
      • 3. 第7步的排列組合
      • 4. score函數(shù)的打分模型,
      • 總結(jié)

問(wèn)題

??在上周的時(shí)候,有一個(gè)索引post,數(shù)據(jù)方突然做了一個(gè)近全表的update,導(dǎo)致了大量的數(shù)據(jù)更新。數(shù)據(jù)積累的情況下跑的有將近1個(gè)小時(shí),但是奇怪的是在數(shù)據(jù)更新完以后索引膨脹了80%。從11g變成了20g.
當(dāng)時(shí)懷疑是段合并的問(wèn)題,但是看具體的segment數(shù)量卻基本上沒(méi)有變化。很是奇怪。經(jīng)歷了半天的時(shí)間,依然沒(méi)有降下來(lái)。后來(lái)打算在這周一如果數(shù)據(jù)量依然是很高的話就直接重建全量索引。
??在周一的時(shí)候,再看數(shù)據(jù)的量已經(jīng)降下來(lái)了,到了12g

GET _cat/indices/post?vhealth status index uuid pri rep docs.count docs.deleted store.size pri.store.size green open post_two vVGUNqf9RfyqPwIei7VD4A 5 2 10011876 2774293 12.2gb 3.9gb

問(wèn)題探尋

??當(dāng)時(shí)覺(jué)得很是奇怪,而且可以確定是段合并的問(wèn)題了。也借著這個(gè)機(jī)會(huì)學(xué)習(xí)一下段合并的原理。
網(wǎng)上查找了不少資料,比較少,但是仔細(xì)找還是能夠找到的,當(dāng)然,最后真正弄明白還是要靠源碼。

??這里只講一下es的index過(guò)程,es的index是過(guò)程是新段和刪除端不斷產(chǎn)生的過(guò)程。lucene不會(huì)直接刪除已經(jīng)存在的segment中的數(shù)據(jù),而是產(chǎn)生新的刪除段關(guān)聯(lián)原數(shù)據(jù)段。同時(shí)如果是update的話也會(huì)創(chuàng)建新的段。

??在這里,我們的情況就是產(chǎn)生了大量的update操作,雖然有些老段中已經(jīng)有很多刪除了,但是因?yàn)閘ucene的段合并策略,總是不能被合并,所以就導(dǎo)致了問(wèn)題。

lucene的段合并機(jī)制

  • 先將所有段按照扣除刪除文檔之后的字節(jié)數(shù)(bytesize * (1.0 - delRatio))降序排列
  • 排除size>2.5G的段(2.5=maxMergedSegmentSize / 2)maxMergedSegmentBytes是一個(gè)設(shè)置值,默認(rèn)為5g,最大合并段
  • 根據(jù)2的結(jié)果計(jì)算allowedSegCountInt,也就是當(dāng)前索引對(duì)應(yīng)的數(shù)據(jù)量理想化的情況下應(yīng)該有多少個(gè)seg
  • 排除正在合并的段
  • 在以上幾個(gè)步驟后得到候選段集合eligible[]
  • 判斷實(shí)際的候選段的數(shù)量(eligible.size)是否大于 allowedSegCountInt ,如果小于,直接返回,不再進(jìn)行合并,反之進(jìn)入第7步
  • 對(duì)eligible進(jìn)行降序的排列組合,得到多個(gè)組合結(jié)果(每個(gè)組合結(jié)果都是eligible的一個(gè)子集)
  • 對(duì)多個(gè)組合進(jìn)行打分,得分最低的一組segment被選中進(jìn)行合并。
  • 1. allowedSegCountInt 的計(jì)算方式

    第三步allowedSegCountInt 的計(jì)算方式

  • 選定最開(kāi)始計(jì)算的階梯值,邏輯如下面的floorSize()函數(shù)
    • 計(jì)算,按照每一層的segsPerTier個(gè)段的數(shù)據(jù)量進(jìn)行計(jì)算,層級(jí)是從小到大,直到無(wú)法達(dá)到某個(gè)層級(jí)的segsPerTier的個(gè)數(shù)。allowedSegCountInt,是理想化的情況下這些數(shù)據(jù)應(yīng)該有的segment數(shù)量,是為了衡量當(dāng)前的段數(shù)量是否合理,如果是合理的狀態(tài),那么就可能不會(huì)在進(jìn)行段合并了。
  • minSegmentBytes = floorSize(minSegmentBytes);// Compute max allowed segs in the indexlong levelSize = minSegmentBytes;//totIndexBytes是出掉大段后的所有段的總量long bytesLeft = totIndexBytes;double allowedSegCount = 0;while(true) {final double segCountLevel = bytesLeft / (double) levelSize;// segsPerTier是設(shè)定值,是每個(gè)階梯的段數(shù)量,默認(rèn)值是10// 當(dāng)段的剩余的bytesLeft在某個(gè)級(jí)別的段上已經(jīng)不夠segsPerTier的時(shí)候就會(huì)中斷循環(huán)// 說(shuō)明已經(jīng)統(tǒng)計(jì)完了,沒(méi)有多余的bytesLeft來(lái)統(tǒng)計(jì)了,這也是唯一的中斷出口if (segCountLevel < segsPerTier) {allowedSegCount += Math.ceil(segCountLevel);break;}//每個(gè)層級(jí)的段數(shù)量相加allowedSegCount += segsPerTier;bytesLeft -= segsPerTier * levelSize;levelSize *= maxMergeAtOnce;}int allowedSegCountInt = (int) allowedSegCount; floorSegmentBytes是設(shè)定的最小段,理論上低于這個(gè)值的段都被認(rèn)為是小段,默認(rèn)的設(shè)置是2mprivate long floorSize(long bytes) {return Math.max(floorSegmentBytes, bytes);}

    2. 第5步的計(jì)算過(guò)程,就是排除正在合并的段

    final List<SegmentCommitInfo> eligible = new ArrayList<>();for(int idx = tooBigCount; idx<infosSorted.size(); idx++) {final SegmentCommitInfo info = infosSorted.get(idx);if (merging.contains(info)) {mergingBytes += size(info, writer);} else if (!toBeMerged.contains(info)) {eligible.add(info);}}

    3. 第7步的排列組合

    就是使用雙層for循環(huán),從大到小進(jìn)行組合,segment的總數(shù)不超過(guò)10個(gè),segment總的數(shù)據(jù)量不超過(guò)maxMergedSegmentBytes。
    如果在遍歷中有超過(guò)maxMergedSegmentBytes的時(shí)候?qū)itTooLarge置標(biāo)志位,會(huì)影響打分
    打分越低越優(yōu)先。最后得到一個(gè)打分最低的segment組合。

    if (eligible.size() > allowedSegCountInt) {// OK we are over budget -- find best merge!MergeScore bestScore = null;List<SegmentCommitInfo> best = null;boolean bestTooLarge = false;long bestMergeBytes = 0;// Consider all merge starts:// 使用雙層for循環(huán),從大到小列舉所有可能for(int startIdx = 0;startIdx <= eligible.size()-maxMergeAtOnce; startIdx++) {long totAfterMergeBytes = 0;//candidate 保存一次組合的結(jié)果final List<SegmentCommitInfo> candidate = new ArrayList<>();boolean hitTooLarge = false;for(int idx = startIdx;idx<eligible.size() && candidate.size() < maxMergeAtOnce;idx++) {final SegmentCommitInfo info = eligible.get(idx);final long segBytes = size(info, writer);//如果加入這個(gè)段(info)以后總量大于 設(shè)定的最大合并段的值,就再排除這個(gè)段,但是置標(biāo)志位hitTooLarge,表明當(dāng)前組合的總量是接近最大段的,相對(duì)來(lái)說(shuō)合并的效率更好,后期的話就不用再合并了if (totAfterMergeBytes + segBytes > maxMergedSegmentBytes) {hitTooLarge = true;// NOTE: we continue, so that we can try// "packing" smaller segments into this merge// to see if we can get closer to the max// size; this in general is not perfect since// this is really "bin packing" and we'd have// to try different permutations.//這里也說(shuō)了,這個(gè)策略并不算完美continue;}candidate.add(info);totAfterMergeBytes += segBytes;}// We should never see an empty candidate: we iterated over maxMergeAtOnce// segments, and already pre-excluded the too-large segments:assert candidate.size() > 0;//這個(gè)地方進(jìn)行打分final MergeScore score = score(candidate, hitTooLarge, mergingBytes, writer);if (verbose(writer)) {message(" maybe=" + writer.segString(candidate) + " score=" + score.getScore() + " " + score.getExplanation() + " tooLarge=" + hitTooLarge + " size=" + String.format(Locale.ROOT, "%.3f MB", totAfterMergeBytes/1024./1024.), writer);}// If we are already running a max sized merge// (maxMergeIsRunning), don't allow another max// sized merge to kick off://score小的優(yōu)先級(jí)更高if ((bestScore == null || score.getScore() < bestScore.getScore()) && (!hitTooLarge || !maxMergeIsRunning)) {best = candidate;bestScore = score;bestTooLarge = hitTooLarge;bestMergeBytes = totAfterMergeBytes;}}if (best != null) {if (spec == null) {spec = new MergeSpecification();}final OneMerge merge = new OneMerge(best);spec.add(merge);for(SegmentCommitInfo info : merge.segments) {toBeMerged.add(info);}if (verbose(writer)) {message(" add merge=" + writer.segString(merge.segments) + " size=" + String.format(Locale.ROOT, "%.3f MB", bestMergeBytes/1024./1024.) + " score=" + String.format(Locale.ROOT, "%.3f", bestScore.getScore()) + " " + bestScore.getExplanation() + (bestTooLarge ? " [max merge]" : ""), writer);}} else {return spec;} } else {return spec;}

    4. score函數(shù)的打分模型,

    這里記住,一定是分?jǐn)?shù)越小優(yōu)先級(jí)越高
    1. 給出初始值 skew (如果在3中的hitTooLarge為true的話 該值為0.1,否則是 當(dāng)前組合中最大段size/ 組合中所有段floorsize之和),floorsize是每個(gè)段所在的層的閾值,也就是大段和小段小段搭配更優(yōu)
    2. score=skew*Math.pow(totAfterMergeBytes, 0.05)//這個(gè)地方索命壓縮后size越小越好,這一點(diǎn)說(shuō)明是小段優(yōu)先
    3. score = score*Math.pow(nonDelRatio, 2)//留存比率的平方,這個(gè)2是可以手動(dòng)調(diào)節(jié)的,刪除率越高越好

    /** Expert: scores one merge; subclasses can override. */protected MergeScore score(List<SegmentCommitInfo> candidate, boolean hitTooLarge, long mergingBytes, IndexWriter writer) throws IOException {long totBeforeMergeBytes = 0;long totAfterMergeBytes = 0;long totAfterMergeBytesFloored = 0;for(SegmentCommitInfo info : candidate) {final long segBytes = size(info, writer);totAfterMergeBytes += segBytes;totAfterMergeBytesFloored += floorSize(segBytes);totBeforeMergeBytes += info.sizeInBytes();}// Roughly measure "skew" of the merge, i.e. how// "balanced" the merge is (whether the segments are// about the same size), which can range from// 1.0/numSegsBeingMerged (good) to 1.0 (poor). Heavily// lopsided merges (skew near 1.0) is no good; it means// O(N^2) merge cost over time:final double skew;//這里如果大段置位了,也就是這一組曾經(jīng)超過(guò)過(guò)大段,雖然后來(lái)又替換,但是應(yīng)該是接近大段的。這樣下次就不用合并了,所以給的優(yōu)先級(jí)比較高// 這樣的話就會(huì)給更高的優(yōu)先級(jí)if (hitTooLarge) {// Pretend the merge has perfect skew; skew doesn't// matter in this case because this merge will not// "cascade" and so it cannot lead to N^2 merge cost// over time:skew = 1.0/maxMergeAtOnce;} else {//對(duì)于其他情況,就用這個(gè)組合中最大的segment的size 除以組合內(nèi)所有元素的size,理論上除非組合中所有元素一樣大,否則,skew肯定大于0.1, 段的差異越大,這個(gè)值越大skew = ((double) floorSize(size(candidate.get(0), writer)))/totAfterMergeBytesFloored;}// Strongly favor merges with less skew (smaller// mergeScore is better):// mergeScore 越小越好double mergeScore = skew;// Gently favor smaller merges over bigger ones. We// don't want to make this exponent too large else we// can end up doing poor merges of small segments in// order to avoid the large merges://對(duì)merge后的總量size取指數(shù)運(yùn)算,這樣說(shuō)來(lái),合并后總量越大對(duì)應(yīng)計(jì)算的mergeScore越大,優(yōu)先級(jí)也就越低, 越小則優(yōu)先級(jí)越高,但是,因?yàn)橹笖?shù)很小,所以影響不是很大,也就是更偏向于先合并小段// 輕輕地偏愛(ài)較小的合并而不是較大的合并,我們不想使此指數(shù)太大,否則我們最終可能會(huì)因?yàn)闉榱吮苊獯蠛喜⒍鴮?duì)小段進(jìn)行不良合并mergeScore *= Math.pow(totAfterMergeBytes, 0.05);// Strongly favor merges that reclaim deletes://這個(gè)是保留率,就是刪除以后的總量和執(zhí)行刪除前的總量final double nonDelRatio = ((double) totAfterMergeBytes)/totBeforeMergeBytes;//這里看對(duì)壓縮比還是比較重視的,保有率越低越好,reclaimDeletesWeight是一個(gè)設(shè)置值,用來(lái)控制壓縮率在打分中所占的權(quán)重,默認(rèn)是2,建議的是不超過(guò)3,如果是0的話,壓縮率就不影響打分了mergeScore *= Math.pow(nonDelRatio, reclaimDeletesWeight);final double finalMergeScore = mergeScore;return new MergeScore() {@Overridepublic double getScore() {return finalMergeScore;}@Overridepublic String getExplanation() {return "skew=" + String.format(Locale.ROOT, "%.3f", skew) + " nonDelRatio=" + String.format(Locale.ROOT, "%.3f", nonDelRatio);}};}

    總結(jié)

    總結(jié)來(lái)說(shuō)就是

  • 如果10個(gè)seg合并后總量接近5G,那么就優(yōu)先級(jí)處于更高
  • 否則10個(gè)seg越均衡優(yōu)先級(jí)系數(shù)會(huì)加一些
  • 10個(gè)seg的總量更小,優(yōu)先級(jí)系數(shù)會(huì)大一些
  • 刪除率更高,優(yōu)先級(jí)系數(shù)更高
    綜合上面的幾個(gè)因素來(lái)考慮
    在update進(jìn)行中的時(shí)候最開(kāi)始的時(shí)候傾向于合并小段,小段優(yōu)先級(jí)更好,而且大量的index操作會(huì)產(chǎn)生大量的小段,之前的比較穩(wěn)定的中段沒(méi)有機(jī)會(huì)合并,所以刪除后的文檔也無(wú)法及時(shí)清理,等后面小段處理的差不多了,中段才有機(jī)會(huì)處理,并且存儲(chǔ)量也逐漸下來(lái)了。
  • 參考
    https://blog.csdn.net/duanduanpeng/article/details/72633217
    https://blog.csdn.net/jollyjumper/article/details/24786147
    https://blog.csdn.net/zhengxgs/article/details/78971141
    https://blog.csdn.net/kimichen123/article/details/77477251
    https://www.jianshu.com/p/9b872a41d5bb
    文檔刪除的原理,lucene
    https://blog.csdn.net/liujava621/article/details/40948417

    超強(qiáng)干貨來(lái)襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的大量更新后数据膨胀_段合并的原理探寻的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。