Redis上踩過的一些坑-美團
上上週和同事(龍哥)參加了360組織的網際網路技術訓練營第三期,美團網的DBA負責人侯軍偉給大家介紹了美團網在redis上踩得一些坑,講的都是乾貨和坑。
分為5個部分: 1. 背景: 大部分網際網路公司都會有Mysql或者Oracle的DBA,但是在Nosql方面一般不會設定專門的DBA。不過對於一些知名的網際網路公司來說,Nosql的使用量是巨大的,所以通常讓Mysql的DBA或者單獨聘請工程師來維護一些Nosql資料庫,比如: Redis, Hbase, Memcache(其實嚴格講不是nosql), Mongodb, Cassandra。從講座看美團網應該是有專職的Redis DBA。所以作為業務開發人員不需要自己安裝、配置、運維Redis,只需要找Redis DBA來申請就可以了。 這裡為了簡化說明:Redis DBA提供的服務叫做Redis雲,業務開發人員叫做業務端(redis的使用者)- redis.clients.jedis.exceptions.JedisConnectionException
- java.net.SocketException
- java.net.SocketTimeoutException:connect time out
一、背景
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;
- publicclass RedisIsolationPersistenceInspector extends BaseAlertService implements Inspector {
- publicstaticfinalint REDIS_DEFAULT_TIME = 5000;
- @Override
- publicboolean 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) {
- finalint port = info.getPort();
- finalint 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;
- } elseif (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();
- }
- }
- }
- returntrue;
- }
- privatelong getMb(long bytes) {
- return (long) (bytes / 1024 / 1024);
- }
- privateboolean isAofEnabled(Map<String, String> infoMap) {
- Integer aofEnabled = MapUtils.getInteger(infoMap, "aof_enabled", null);
- return aofEnabled != null && aofEnabled == 1;
- }
- privatedouble getPercentage(long aofCurrentSize, long aofBaseSize) {
- if (aofBaseSize == 0) {
- return0.0D;
- }
- String format = String.format("%.2f", (Double.valueOf(aofCurrentSize - aofBaseSize) * 100 / aofBaseSize));
- return Double.parseDouble(format);
- }
-
相關推薦
美團在Redis上踩過的一些坑-3.redis內存占用飆升(轉載)
car shu idl 運維人員 監控 images 我想 依然 服務器 一、現象: redis-cluster某個分片內存飆升,明顯比其他分片高很多,而且持續增長。並且主從的內存使用量並不一致。 二、分析可能原因: 1. redis-clus
美團在Redis上踩過的一些坑
上上週和同事(龍哥)參加了360組織的網際網路技術訓練營第三期,美團網的DBA負責人侯軍偉給大家介紹了美團網在redis上踩得一些坑,講的都是乾貨和坑。 分為5個部分: 1. 背景: 大部分網際網路公司都會有Mysql
美團在Redis上踩過的一些坑-5.redis cluster遇到的一些問題
由於演講時間有限,有關Redis-Cluster,演講者沒做太多介紹,簡單的介紹了一些Redis-Cluster概念作用和遇到的兩個問題,我們在Redis-Cluster也有很多運維經驗,將來的文章會介紹。 但是講演者反覆強調,不要聽信網上對於Redis-Clus
Redis上踩過的一些坑-美團
上上週和同事(龍哥)參加了360組織的網際網路技術訓練營第三期,美團網的DBA負責人侯軍偉給大家介紹了美團網在redis上踩得一些坑,講的都是乾貨和坑。 分為5個部分: 1. 背景: 大部分網際網路公司都會
美團在Redis上踩過的一些坑-2.bgrewriteaof問題
一、背景 1. AOF: Redis的AOF機制有點類似於Mysql binlog,是Redis的提供的一種持久化方式(另一種是RDB),它會將所有的寫命令按照一定頻率(no, always, every seconds)寫入到日誌檔案中,當Redis停
美團在Redis上踩過的一些坑-3.redis記憶體佔用飆升
一、現象: redis-cluster某個分片記憶體飆升,明顯比其他分片高很多,而且持續增長。並且主從的記憶體使用量並不一致。 二、分析可能原因: 1. redis-cluster的bug (這個應該不存在) 2. 客戶端的hash(key)有問題,造成分配不均。(redis使用的是cr
在vue上踩過的坑
1.首先是前後端分離,採用mock造資料 2.元件註冊->全域性註冊->在main.js中import xx from '.....' 然後註冊Vue.component('xxx',xxx) 然後在頁面中呼叫元件 ->
那些年,在nodejs上踩過的坑(一)
自己寫nodejs也有一段時間,踩過很多坑(而且大部分是自己給自己埋),也見過很多別人踩過的坑,原因其實也很簡單,要麼是對這個知識點理解不夠深入,要麼就是編碼的習慣不好。這段響應朋春大牛的號召,打算陸陸續續整理下這些坑,算是給自己一個備忘,同時也希望能對大家有所幫助。 1.
那些年,在nodejs上踩過的坑
原文:http://cnodejs.org/topic/4fc7789a8be5d070121141cd ----------------------------------------------------------- 自己寫nodejs也有一段時間,踩過很多坑(而
那些年在WebView上踩過的坑
之前我在Android中使用WebView與JS互動全解析一文中,介紹了通過Webview和JS的互動方式,但Webview這個控制元件簡直是讓人又愛又恨,各種你想不到的錯誤在各種奇怪的手機上,各種不一樣的版本里,所以我想通過這篇部落格總結Webview開發中的
配置nginx與php-fpm踩過的坑,(附裝nginx,php-fpm,mysql,redis教程)
近來在centos7上搭建了lnmp的環境,遇到了個坑。如果沒有裝nmp的話可以看這個文章 https://blog.csdn.net/qq_39677681/article/details/82025445 我所遇到的坑: 要讓php-fpm能正常在伺服器上正常解析php,要配置這兩個
關於webpack的安裝與使用----及一些踩過的坑
webpack是我們前端開發人員很好用的一個打包工具 因為它支援一鍵打包,以及一些命令也很人性化。目的是將所有的檔案 整合與一個js檔案 避免二次請求 對伺服器減壓 直接走入正題吧。 第一步 首先 新建一個資料夾 資料夾一定不能為中文 否則會出現一些未知的錯誤,這個坑我已經踩過了~~ 直
在ubuntu 14.04上LIFT: Learned Invariant Feature Points 環境配置所踩過的坑流過的淚(3)
1.重灌nvidia 顯示卡驅動 2.重灌cuda8.0和cudnn 3。重新測試 看來執行不能用sudo 最後也沒管 2. theano nvcc compiler not found on $PATH 重新配置檔案 解決方案:重灌了一遍cuda 和c
yarn 上提交shell 指令碼時踩過的坑
遇到一個坑爹的問題,用yarn 跑一個自己寫的指令碼,提示失敗,錯誤結果如下 16/12/22 16:47:47 INFO distributedshell.Client: Initializing Client 16/12/22 16:47:47 INFO
前端總結:CSS/js 踩過的坑以及一些冷知識(永久更新)
css css樣式這一塊坑比較多,有些情況不按常理出牌,在考慮不同螢幕顯示效果, 精確控制樣式和大小時就會遇到這些坑。 1、 行內元素(比如img)預設會在末尾(或底部)留白/間隙,無法去除。解決辦法:通過display:block讓其以塊級元素進行顯示。(同
談談陌陌爭霸在資料庫方面踩過的坑( Redis 篇)
第一次事故出在 2 月 3 日,新年假期還沒有過去。由於整個假期都相安無事,運維也相對懈怠。 中午的時候,有一臺資料服務主機無法被遊戲伺服器訪問到,影響了部分使用者登陸。線上嘗試修復連線無果,只好開始了長達 2 個小時的停機維護。 在維護期間,初步確定了問題。是由於上午一臺從機的記憶體耗盡,導致了從機的資料
swagger實踐 及一些踩過的坑
首先就是我們專案中用的swagger2,編輯的時候已經升級到3.0.0了 有空嘗試下。 然後至少要是個spring的專案,支援@configuration這個註解的版本,我們專案中用的spring4.1.0。 然後就是開開心心的碼程式碼了 @Conf
Vue專案開發的一些問題和踩過的坑
父元件修改子元件data資料 以及 父元件呼叫子元件定義的方法 —— ref 子元件: <template> <div class="keyboard-wrapper" :class="isShow"></div> </t
redis集群部署及踩過的坑
join port rmi ems asm ica 去掉 tar.bz2 方式 本文目標 要在單臺機器上搭建Redis集群,方式是通過不同的TCP端口啟動多個實例,然後組成集群,同時記錄在搭建過程中踩過的坑。 安裝準備 cento
SpringBoot2.0(13)整合Redis詳解及踩過的坑(Could not get a resource from the pool)
SpringBoot2.0整合Redis 首先安裝的過程就不提了。上一個專案的redis是配置在Windows下的,整合很簡單,也沒有做什麼配置。這次為了進行測試,裝在了linux下。在SpringBoot整合的過程中遇到了一些小坑,分享一下。 po