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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

美团在Redis上踩过的一些坑-2.bgrewriteaof问题

發布時間:2024/8/26 数据库 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 美团在Redis上踩过的一些坑-2.bgrewriteaof问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請注明出處哈:http://carlosfu.iteye.com/blog/2254154


?? ?

?一、背景

1. AOF:

? ? Redis的AOF機制有點類似于Mysql binlog,是Redis的提供的一種持久化方式(另一種是RDB),它會將所有的寫命令按照一定頻率(no, always, every seconds)寫入到日志文件中,當Redis停機重啟后恢復數據庫。

? ? ?

?

2. AOF重寫:

? ? ?(1) 隨著AOF文件越來越大,里面會有大部分是重復命令或者可以合并的命令(100次incr = set key 100)

? ? ?(2) 重寫的好處:減少AOF日志尺寸,減少內存占用,加快數據庫恢復時間。

? ??

?

?

?

二、單機多實例可能存在Swap和OOM的隱患:

? ? 由于Redis的單線程模型,理論上每個redis實例只會用到一個CPU, 也就是說可以在一臺多核的服務器上部署多個實例(實際就是這么做的)。但是Redis的AOF重寫是通過fork出一個Redis進程來實現的,所以有經驗的Redis開發和運維人員會告訴你,在一臺服務器上要預留一半的內存(防止出現AOF重寫集中發生,出現swap和OOM)。

? ??

?

?

?

三、最佳實踐

1. meta信息:作為一個redis云系統,需要記錄各個維度的數據,比如:業務組、機器、實例、應用、負責人多個維度的數據,相信每個Redis的運維人員都應該有這樣的持久化數據(例如Mysql),一般來說還有一些運維界面,為自動化和運維提供依據

? ? 例如如下:

?

?

? ??

?

2. AOF的管理方式:

?(1) 自動:讓每個redis決定是否做AOF重寫操作(根據auto-aof-rewrite-percentage和auto-aof-rewrite-min-size兩個參數):

??

??

?(2) crontab: 定時任務,可能仍然會出現多個redis實例,屬于一種折中方案。

?

?(3) remote集中式:

? ? ? ?最終目標是一臺機器一個時刻,只有一個redis實例進行AOF重寫。

? ? ? ?具體做法其實很簡單,以機器為單位,輪詢每個機器的實例,如果滿足條件就運行(比如currentSize和baseSize滿足什么關系)bgrewriteaof命令。

? ? ? ?期間可以監控發生時間、耗時、頻率、尺寸的前后變化? ? ? ? ? ??

策略 優點 缺點
自動 無需開發

1. 有可能出現(無法預知)上面提到的Swap和OOM

2. 出了問題,處理起來其實更費時間。

AOF控制中心(remote集中式)

1. 防止上面提到Swap和OOM。

2. 能夠收集更多的數據(aof重寫的發生時間、耗時、頻率、尺寸的前后變化),更加有利于運維和定位問題(是否有些機器的實例需要拆分)。

控制中心需要開發。

?

一臺機器輪詢執行bgRewriteAof代碼示例:

Java代碼??
  • package?com.sohu.cache.inspect.impl;??
  • ??
  • import?com.sohu.cache.alert.impl.BaseAlertService;??
  • import?com.sohu.cache.entity.InstanceInfo;??
  • import?com.sohu.cache.inspect.InspectParamEnum;??
  • import?com.sohu.cache.inspect.Inspector;??
  • import?com.sohu.cache.util.IdempotentConfirmer;??
  • import?com.sohu.cache.util.TypeUtil;??
  • import?org.apache.commons.collections.MapUtils;??
  • import?org.apache.commons.lang.StringUtils;??
  • import?redis.clients.jedis.Jedis;??
  • ??
  • import?java.util.Collections;??
  • import?java.util.LinkedHashMap;??
  • import?java.util.List;??
  • import?java.util.Map;??
  • import?java.util.concurrent.TimeUnit;??
  • ??
  • ??
  • public?class?RedisIsolationPersistenceInspector?extends?BaseAlertService?implements?Inspector?{??
  • ??
  • ????public?static?final?int?REDIS_DEFAULT_TIME?=?5000;??
  • ??
  • ????@Override??
  • ????public?boolean?inspect(Map<InspectParamEnum,?Object>?paramMap)?{??
  • ????????//?某臺機器和機器下所有redis實例??
  • ????????final?String?host?=?MapUtils.getString(paramMap,?InspectParamEnum.SPLIT_KEY);??
  • ????????List<InstanceInfo>?list?=?(List<InstanceInfo>)?paramMap.get(InspectParamEnum.INSTANCE_LIST);??
  • ????????//?遍歷所有的redis實例??
  • ????????for?(InstanceInfo?info?:?list)?{??
  • ????????????final?int?port?=?info.getPort();??
  • ????????????final?int?type?=?info.getType();??
  • ????????????int?status?=?info.getStatus();??
  • ????????????//?非正常節點??
  • ????????????if?(status?!=?1)?{??
  • ????????????????continue;??
  • ????????????}??
  • ????????????if?(TypeUtil.isRedisDataType(type))?{??
  • ????????????????Jedis?jedis?=?new?Jedis(host,?port,?REDIS_DEFAULT_TIME);??
  • ????????????????try?{??
  • ????????????????????//?從redis?info中索取持久化信息??
  • ????????????????????Map<String,?String>?persistenceMap?=?parseMap(jedis);??
  • ????????????????????if?(persistenceMap.isEmpty())?{??
  • ????????????????????????logger.error("{}:{}?get?persistenceMap?failed",?host,?port);??
  • ????????????????????????continue;??
  • ????????????????????}??
  • ????????????????????//?如果正在進行aof就不做任何操作,理論上要等待它完畢,否則??
  • ????????????????????if?(!isAofEnabled(persistenceMap))?{??
  • ????????????????????????continue;??
  • ????????????????????}??
  • ????????????????????//?上一次aof重寫后的尺寸和當前aof的尺寸??
  • ????????????????????long?aofCurrentSize?=?MapUtils.getLongValue(persistenceMap,?"aof_current_size");??
  • ????????????????????long?aofBaseSize?=?MapUtils.getLongValue(persistenceMap,?"aof_base_size");??
  • ????????????????????//?閥值大于60%??
  • ????????????????????long?aofThresholdSize?=?(long)?(aofBaseSize?*?1.6);??
  • ????????????????????double?percentage?=?getPercentage(aofCurrentSize,?aofBaseSize);??
  • ????????????????????//?大于60%且超過60M??
  • ????????????????????if?(aofCurrentSize?>=?aofThresholdSize?&&?aofCurrentSize?>?(64?*?1024?*?1024))?{??
  • ????????????????????????//?bgRewriteAof?異步操作。??
  • ????????????????????????boolean?isInvoke?=?invokeBgRewriteAof(jedis);??
  • ????????????????????????if?(!isInvoke)?{??
  • ????????????????????????????logger.error("{}:{}?invokeBgRewriteAof?failed",?host,?port);??
  • ????????????????????????????continue;??
  • ????????????????????????}?else?{??
  • ????????????????????????????logger.warn("{}:{}?invokeBgRewriteAof?started?percentage={}",?host,?port,?percentage);??
  • ????????????????????????}??
  • ????????????????????????//?等待Aof重寫成功(bgRewriteAof是異步操作)??
  • ????????????????????????while?(true)?{??
  • ????????????????????????????try?{??
  • ????????????????????????????????//?before?wait?1s??
  • ????????????????????????????????TimeUnit.SECONDS.sleep(1);??
  • ????????????????????????????????Map<String,?String>?loopMap?=?parseMap(jedis);??
  • ????????????????????????????????Integer?aofRewriteInProgress?=?MapUtils.getInteger(loopMap,?"aof_rewrite_in_progress",?null);??
  • ????????????????????????????????if?(aofRewriteInProgress?==?null)?{??
  • ????????????????????????????????????logger.error("loop?watch:{}:{}?return?failed",?host,?port);??
  • ????????????????????????????????????break;??
  • ????????????????????????????????}?else?if?(aofRewriteInProgress?<=?0)?{??
  • ????????????????????????????????????//?bgrewriteaof?Done??
  • ????????????????????????????????????logger.warn("{}:{}?bgrewriteaof?Done?lastSize:{}Mb,currentSize:{}Mb",?host,?port,??
  • ????????????????????????????????????????????getMb(aofCurrentSize),??
  • ????????????????????????????????????????????getMb(MapUtils.getLongValue(loopMap,?"aof_current_size")));??
  • ????????????????????????????????????break;??
  • ????????????????????????????????}?else?{??
  • ????????????????????????????????????//?wait?1s??
  • ????????????????????????????????????TimeUnit.SECONDS.sleep(1);??
  • ????????????????????????????????}??
  • ????????????????????????????}?catch?(Exception?e)?{??
  • ????????????????????????????????logger.error(e.getMessage(),?e);??
  • ????????????????????????????}??
  • ????????????????????????}??
  • ????????????????????}?else?{??
  • ????????????????????????if?(percentage?>?50D)?{??
  • ????????????????????????????long?currentSize?=?getMb(aofCurrentSize);??
  • ????????????????????????????logger.info("checked?{}:{}?aof?increase?percentage:{}%?currentSize:{}Mb",?host,?port,??
  • ????????????????????????????????????percentage,?currentSize?>?0???currentSize?:?"<1");??
  • ????????????????????????}??
  • ????????????????????}??
  • ????????????????}?finally?{??
  • ????????????????????jedis.close();??
  • ????????????????}??
  • ????????????}??
  • ????????}??
  • ????????return?true;??
  • ????}??
  • ??
  • ????private?long?getMb(long?bytes)?{??
  • ????????return?(long)?(bytes?/?1024?/?1024);??
  • ????}??
  • ??
  • ????private?boolean?isAofEnabled(Map<String,?String>?infoMap)?{??
  • ????????Integer?aofEnabled?=?MapUtils.getInteger(infoMap,?"aof_enabled",?null);??
  • ????????return?aofEnabled?!=?null?&&?aofEnabled?==?1;??
  • ????}??
  • ??
  • ????private?double?getPercentage(long?aofCurrentSize,?long?aofBaseSize)?{??
  • ????????if?(aofBaseSize?==?0)?{??
  • ????????????return?0.0D;??
  • ????????}??
  • ????????String?format?=?String.format("%.2f",?(Double.valueOf(aofCurrentSize?-?aofBaseSize)?*?100?/?aofBaseSize));??
  • ????????return?Double.parseDouble(format);??
  • ????}??
  • ??
  • ????private?Map<String,?String>?parseMap(final?Jedis?jedis)?{??
  • ????????final?StringBuilder?builder?=?new?StringBuilder();??
  • ????????boolean?isInfo?=?new?IdempotentConfirmer()?{??
  • ????????????@Override??
  • ????????????public?boolean?execute()?{??
  • ????????????????String?persistenceInfo?=?null;??
  • ????????????????try?{??
  • ????????????????????persistenceInfo?=?jedis.info("Persistence");??
  • ????????????????}?catch?(Exception?e)?{??
  • ????????????????????logger.warn(e.getMessage()?+?"-{}:{}",?jedis.getClient().getHost(),?jedis.getClient().getPort(),??
  • ????????????????????????????e.getMessage());??
  • ????????????????}??
  • ????????????????boolean?isOk?=?StringUtils.isNotBlank(persistenceInfo);??
  • ????????????????if?(isOk)?{??
  • ????????????????????builder.append(persistenceInfo);??
  • ????????????????}??
  • ????????????????return?isOk;??
  • ????????????}??
  • ????????}.run();??
  • ????????if?(!isInfo)?{??
  • ????????????logger.error("{}:{}?info?Persistence?failed",?jedis.getClient().getHost(),?jedis.getClient().getPort());??
  • ????????????return?Collections.emptyMap();??
  • ????????}??
  • ????????String?persistenceInfo?=?builder.toString();??
  • ????????if?(StringUtils.isBlank(persistenceInfo))?{??
  • ????????????return?Collections.emptyMap();??
  • ????????}??
  • ????????Map<String,?String>?map?=?new?LinkedHashMap<String,?String>();??
  • ????????String[]?array?=?persistenceInfo.split("\r\n");??
  • ????????for?(String?line?:?array)?{??
  • ????????????String[]?cells?=?line.split(":");??
  • ????????????if?(cells.length?>?1)?{??
  • ????????????????map.put(cells[0],?cells[1]);??
  • ????????????}??
  • ????????}??
  • ??
  • ????????return?map;??
  • ????}??
  • ??
  • ????public?boolean?invokeBgRewriteAof(final?Jedis?jedis)?{??
  • ????????return?new?IdempotentConfirmer()?{??
  • ????????????@Override??
  • ????????????public?boolean?execute()?{??
  • ????????????????try?{??
  • ????????????????????String?response?=?jedis.bgrewriteaof();??
  • ????????????????????if?(response?!=?null?&&?response.contains("rewriting?started"))?{??
  • ????????????????????????return?true;??
  • ????????????????????}??
  • ????????????????}?catch?(Exception?e)?{??
  • ????????????????????String?message?=?e.getMessage();??
  • ????????????????????if?(message.contains("rewriting?already"))?{??
  • ????????????????????????return?true;??
  • ????????????????????}??
  • ????????????????????logger.error(message,?e);??
  • ????????????????}??
  • ????????????????return?false;??
  • ????????????}??
  • ????????}.run();??
  • ????}??
  • }??
  • ?

    ?

    ?

    ?

    附圖一張:

    ?

    ?

    總結

    以上是生活随笔為你收集整理的美团在Redis上踩过的一些坑-2.bgrewriteaof问题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。