1. 程式人生 > 實用技巧 >MSIL入門(四)之委託delegate

MSIL入門(四)之委託delegate

一、基礎知識

  1. redis預設有16個數據庫,預設使用第0個,使用select 1切換為第一個資料庫。
  2. 使用dbsize,檢視資料庫容量
  3. 使用key * 檢視所有的key
  4. 清空當前資料庫 flushdb
  5. 清空全部資料庫flushall
  6. redis是單執行緒的,redis是基於記憶體操作,cpu並不能成為redis的瓶頸。redis的瓶頸是根據機器的記憶體和網路頻寬。

Redis 為什麼單執行緒還這麼快?

1 、誤區 1 :高效能的伺服器一定是多執行緒的?

2 、誤區 2 :多執行緒(CPU上下文會切換!)一定比單執行緒效率高!

先去CPU>記憶體>硬碟的速度要有所瞭解!

核心:redis 是將所有的資料全部放在記憶體中的,所以說使用單執行緒去操作效率就是最高的,多執行緒
(CPU上下文會切換:耗時的操作!!!),對於記憶體系統來說,如果沒有上下文切換效率就是最高
的!多次讀寫都是在一個CPU上的,在記憶體情況下,這個就是最佳的方案!

二、五大資料型別

Redis 是一個開源(BSD許可)的,記憶體中的資料結構儲存系統,它可以用作資料庫、快取和訊息中間
件MQ。 它支援多種型別的資料結構,如 字串(strings), 雜湊(hashes), 列表(lists), 集合
(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間
(geospatial) 索引半徑查詢。 Redis 內建了 複製(replication),LUA指令碼(Lua scripting), LRU
驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁碟持久化(persistence), 並通過
Redis哨兵(Sentinel)和自動 分割槽(Cluster)提供高可用性(high availability)。

Redis-Key

127 .0.0.1:6379> keys *  # 檢視所有的key
(empty list or set)
127 .0.0.1:6379> set name kuangshen  # set key
OK
127 .0.0.1:6379> EXISTS name  # 判斷當前的key是否存在
(integer) 1
127 .0.0.1:6379> move name 1 # 移除當前的key
(integer) 1
127 .0.0.1:6379> get name
"qinjiang"
127 .0.0.1:6379> EXPIRE name 10 # 設定key的過期時間,單位是秒
(integer) 1
127 .0.0.1:6379> ttl name  # 檢視當前key的剩餘時間
(integer) 4
127 .0.0.1:6379> type name  # 檢視當前key的一個型別!
string

1、String(字串)

設定獲得值

127 .0.0.1:6379> set key1 v1  # 設定值
OK
127 .0.0.1:6379> get key1 # 獲得值
"v1"
127 .0.0.1:6379> keys * # 獲得所有的key
1 ) "key1"

判斷存在EXISTS ,追加APPEND ,長度STRLEN

127 .0.0.1:6379> EXISTS key1  # 判斷某一個key是否存在
(integer) 1
127 .0.0.1:6379> APPEND key1 "hello" # 追加字串,如果當前key不存在,就相當於setkey
(integer) 7
127 .0.0.1:6379> STRLEN key1  # 獲取字串的長度!
(integer) 7

自增incr 自減decr 步長INCRBY、DECRBY

# i++
# 步長 i+=
127 .0.0.1:6379> set views 0 # 初始瀏覽量為 0
OK
127 .0.0.1:6379> get views
"0"
127 .0.0.1:6379> incr views  # 自增 1 瀏覽量變為 1
(integer) 1
127 .0.0.1:6379> incr views
(integer) 2
127 .0.0.1:6379> get views
"2"
127 .0.0.1:6379> decr views  # 自減 1 瀏覽量-1
(integer) 1
127 .0.0.1:6379> decr views
(integer) 0
127 .0.0.1:6379> decr views
(integer) -1
127 .0.0.1:6379> get views
"-1"
127 .0.0.1:6379> INCRBY views 10 # 可以設定步長,指定增量!
(integer) 9
127 .0.0.1:6379> INCRBY views 10
(integer) 19
127 .0.0.1:6379> DECRBY views 5

獲取字串範圍 GETRANGE

127 .0.0.1:6379> set key1 "hello,kuangshen" # 設定 key1 的值
OK
127 .0.0.1:6379> get key1
"hello,kuangshen"
127 .0.0.1:6379> GETRANGE key1 0 3 # 擷取字串 [0,3]
"hell"
127 .0.0.1:6379> GETRANGE key1 0 -1 # 獲取全部的字串 和 get key是一樣的
"hello,kuangshen"

替換SETRANGE

127 .0.0.1:6379> set key2 abcdefg
OK
127 .0.0.1:6379> get key2
"abcdefg"
127 .0.0.1:6379> SETRANGE key2 1 xx # 替換指定位置開始的字串!
(integer) 7
127 .0.0.1:6379> get key2
"axxdefg"

設定過期時間setex ,不存在在設定setnx

127 .0.0.1:6379> setex key3 30 "hello" # 設定key3 的值為 hello,30秒後過期
OK
127 .0.0.1:6379> ttl key3
(integer) 26
127 .0.0.1:6379> get key3
"hello"
127 .0.0.1:6379> setnx mykey "redis" # 如果mykey 不存在,建立mykey
(integer) 1
127 .0.0.1:6379> keys *
1 ) "key2"
2 ) "mykey"
3 ) "key1"
127 .0.0.1:6379> ttl key3
(integer) -2
127 .0.0.1:6379> setnx mykey "MongoDB" # 如果mykey存在,建立失敗!
(integer) 0
127 .0.0.1:6379> get mykey
"redis"

設定或獲取多個mset、mget

127 .0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同時設定多個值
OK
127 .0.0.1:6379> keys *
1 ) "k1"
2 ) "k2"
3 ) "k3"
127 .0.0.1:6379> mget k1 k2 k3 # 同時獲取多個值
1 ) "v1"
2 ) "v2"
3 ) "v3"

注意:msetnx 是一個原子性的操作,要麼一起成功,要麼一起失敗!

127 .0.0.1:6379> msetnx k1 v1 k4 v4  # msetnx 是一個原子性的操作,要麼一起成功,要麼一起失敗!
(integer) 0
127 .0.0.1:6379> get k4
(nil)

關於string的高階用法

# 物件
set user:1 {name:zhangsan,age:3}  # 設定一個user:1 物件 值為 json字元來儲存一個物件!

127 .0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127 .0.0.1:6379> mget user:1:name user:1:age
1 ) "zhangsan"
2 ) "2"

getset

127 .0.0.1:6379> getset db redis # 如果不存在值,則返回 nil
(nil)
127 .0.0.1:6379> get db
"redis
127 .0.0.1:6379> getset db mongodb  # 如果存在值,獲取原來的值,並設定新的值
"redis"
127 .0.0.1:6379> get db
"mongodb"

2、List(列表)

在redis裡面,我們可以把list玩成 ,棧、佇列、阻塞佇列!

所有的list命令都是用l開頭的,Redis不區分大小命令

左/右插入、左/右移除、獲取

127 .0.0.1:6379> LPUSH list one  # 將一個值或者多個值,插入到列表頭部 (左)
(integer) 1
127 .0.0.1:6379> LPUSH list two
(integer) 2
127 .0.0.1:6379> LPUSH list three
(integer) 3
127 .0.0.1:6379> LRANGE list 0 -1 # 獲取list中值!
1 ) "three"
2 ) "two"
3 ) "one"
127 .0.0.1:6379> LRANGE list 0 1 # 通過區間獲取具體的值!
1 ) "three"
2 ) "two"
127 .0.0.1:6379> Rpush list righr  # 將一個值或者多個值,插入到列表位部 (右)
(integer) 4
127 .0.0.1:6379> LRANGE list 0 -1
1 ) "three"
2 ) "two"
3 ) "one"
4 ) "righr"
127 .0.0.1:6379> LRANGE list 0 -1
1 ) "three"
2 ) "two"
3 ) "one"
4 ) "righr"
127 .0.0.1:6379> Lpop list  # 移除list的第一個元素
"three"
127 .0.0.1:6379> Rpop list  # 移除list的最後一個元素
"righr"
127 .0.0.1:6379> LRANGE list 0 -1
1 ) "two"
2 ) "one"

根據下標取值lindex rindex

127 .0.0.1:6379> LRANGE list 0 -1
1 ) "two"
2 ) "one"
127 .0.0.1:6379> lindex list 1 # 通過下標獲得 list 中的某一個值!
"one"
127 .0.0.1:6379> lindex list 0
"two"

獲取長度Llen rlen

127 .0.0.1:6379> Lpush list one
(integer) 1
127 .0.0.1:6379> Lpush list two
(integer) 2
127 .0.0.1:6379> Lpush list three
(integer) 3
127 .0.0.1:6379> Llen list # 返回列表的長度
(integer) 3

移除指定的值Lrem

127 .0.0.1:6379> LRANGE list 0 -1
1 ) "three"
2 ) "three"
3 ) "two"
4 ) "one"
127 .0.0.1:6379> lrem list 1 one # 移除list集合中指定個數的value,精確匹配
(integer) 1
127 .0.0.1:6379> LRANGE list 0 -1
1 ) "three"
2 ) "three"
3 ) "two"
127 .0.0.1:6379> lrem list 1 three
(integer) 1
127 .0.0.1:6379> LRANGE list 0 -1
1 ) "three"
2 ) "two"
127 .0.0.1:6379> Lpush list three
(integer) 3
127 .0.0.1:6379> lrem list 2 three
(integer) 2
127 .0.0.1:6379> LRANGE list 0 -1
1 ) "two"

trim 修剪

127 .0.0.1:6379> keys *
(empty list or set)
127 .0.0.1:6379> Rpush mylist "hello"
(integer) 1
127 .0.0.1:6379> Rpush mylist "hello1"
(integer) 2
127 .0.0.1:6379> Rpush mylist "hello2"
(integer) 3
127 .0.0.1:6379> Rpush mylist "hello3"
(integer) 4
127 .0.0.1:6379> ltrim mylist 1 2 # 通過下標擷取指定的長度,這個list已經被改變了,截斷了
只剩下擷取的元素!
OK
127 .0.0.1:6379> LRANGE mylist 0 -1
1 ) "hello1"
2 ) "hello2"

rpoplpush

移除列表的最後一個元素,將他移動到新的列表中

127 .0.0.1:6379> rpush mylist "hello"
(integer) 1
127 .0.0.1:6379> rpush mylist "hello1"
(integer) 2
127 .0.0.1:6379> rpush mylist "hello2"
(integer) 3
127 .0.0.1:6379> rpoplpush mylist myotherlist # 移除列表的最後一個元素,將他移動到新的
列表中!
"hello2"
127 .0.0.1:6379> lrange mylist 0 -1 # 檢視原來的列表
1 ) "hello"
2 ) "hello1"
127 .0.0.1:6379> lrange myotherlist 0 -1 # 檢視目標列表中,確實存在改值!
1 ) "hello2"

lset 替換指定下標

127 .0.0.1:6379> EXISTS list # 判斷這個列表是否存在
(integer) 0
127 .0.0.1:6379> lset list 0 item # 如果不存在列表我們去更新就會報錯
(error) ERR no such key
127 .0.0.1:6379> lpush list value1
(integer) 1
127 .0.0.1:6379> LRANGE list 0 0
1 ) "value1"
127 .0.0.1:6379> lset list 0 item # 如果存在,更新當前下標的值
OK
127 .0.0.1:6379> LRANGE list 0 0
1 ) "item"
127 .0.0.1:6379> lset list 1 other # 如果不存在,則會報錯!
(error) ERR index out of range

linsert 插入帶指定某個元素前後

127 .0.0.1:6379> Rpush mylist "hello"
(integer) 1
127 .0.0.1:6379> Rpush mylist "world"
(integer) 2
127 .0.0.1:6379> LINSERT mylist before "world" "other"
(integer) 3
127 .0.0.1:6379> LRANGE mylist 0 -1
1 ) "hello"
2 ) "other"
3 ) "world"
127 .0.0.1:6379> LINSERT mylist after world new
(integer) 4
127 .0.0.1:6379> LRANGE mylist 0 -1
1 ) "hello"
2 ) "other"
3 ) "world"
4 ) "new"

總結

如果移除了所有值,空連結串列,也代表不存在!

在兩邊插入或者改動值,效率最高! 中間元素,相對來說效率會低一點~

訊息排隊!訊息佇列 (Lpush Rpop), 棧( Lpush Lpop)

3、Set(集合)

  • sadd key member:新增值
  • smembers key:檢視key中所有值
  • smember key value:判斷value值是否在key集合中
  • scard key:獲取key集合中的內容元素個數
  • srem key member:移除key集合中的指定元素
  • randmember key [count]:隨機抽取key中count數量的元素
  • spop key [count]:隨機刪除key中count數量的元素
  • smove source destination member:將source中指定的值移動到另外一個set集合中
  • sdiff key [key…]:差集
  • sinter key [key…]:交集
  • sunion key [key…]:並集

4、Hash(雜湊)

  • hset key field value:set一個具體的值,值是一個map集合,field-value
  • hget key field:獲取一個欄位值
  • hmset key field [key field …]:同時set多個值
  • hmget key field [field…]:同時獲取多個值
  • hgetall key:獲取所有的值
  • hdel key field [field…]:刪除hash指定的field欄位,對應的value也會刪除
  • hlen key:獲取hash表的欄位數量
  • hexists key field:判斷key中field欄位是否存在
  • hkeys key:只獲得所有的field
  • hvals key:只獲得所有的value
  • hincrby key field increment:指定增量
  • hsetnx key field value:如果存在則設定值,如果存在則不能設定

5、Zset(有序集合)

  • zdd key score value:增加值
  • zrangebyscore key min max [withscores]:顯示全部的使用者,從小到大 [附帶成績]
  • zrevrangebyscore key key max min [withscores]:顯示全部的使用者,從大到小 [附帶成績]
  • zrem key member [member…]:移除有序集合中的指定元素
  • zcard key:獲取有序集合中的個數
  • zcount key min max:獲取指定區間的成員數量

三、三種特殊資料型別

geospatial(地理位置)

  • geoadd key 經度 緯度 member:新增資料
  • geopos key member:獲得指定城市的經度和緯度
  • geodist key member1 member2 [unit]:檢視member1到member2的距離[單位]
  • georadius key 經度 緯度 半徑 單位:以這個經度緯度為中性尋找半徑以內的位置
  • georadiusbymember key member radius 單位:找出member周圍的元素
  • geohash key member:將二維的經緯度轉換成一維的字串

Hyperloglog(基數)

  • pfadd key element:建立一組元素
  • pfcount key:統計key元素的基數數量
  • pfmerge destkey sourcekey [sourcekey…]:合併兩組->destkey

Bitmap(位儲存)

  • setbit key offset value:設定值
  • getbit key offset:獲取值
  • bitcount key [start end]:統計數量

四、事務

  • Redis事務本質:一組命令的集合,一個事務中所有的命令都會被序列化,在事務執行的過程中,會按照順序執行。
  • Redis事務沒有隔離級別的概念
  • Redis單條命令是儲存原子性的,但是事務不保證原子性

redis的事務

  • 開啟事務(multi)
  • 命令入隊
  • 執行事務(exec) | 放棄事務(discard)

編譯型異常(程式碼有問題,命令有錯),事務中所有的命令都不會被執行

執行時異常,如果事務佇列中存在語法性,那麼執行命令的時候,其他命令式可以正常執行的,錯誤命令丟擲異常

watch監控

悲觀鎖:

認為什麼時候都會出問題,無論做什麼都會加鎖!

樂觀鎖:

認為什麼時候都不會出問題,所以不會上鎖! 更新資料的時候去判斷一下,在此期間是否有人修改過這個資料,

獲取version
更新的時候比較 version

測試多執行緒修改值 , 使用watch 可以當做redis的樂觀鎖操作!

127 .0.0.1:6379> set money 100
OK
127 .0.0.1:6379> set out 0
OK
127 .0.0.1:6379> watch money # 監視 money 物件
OK
127 .0.0.1:6379> multi # 事務正常結束,資料期間沒有發生變動,這個時候就正常執行成功!
OK
127 .0.0.1:6379> DECRBY money 20
QUEUED
127 .0.0.1:6379> INCRBY out 20
QUEUED
127 .0.0.1:6379> exec
1 ) (integer) 80
2 ) (integer) 20

如果修改失敗,解鎖(unwatch)獲取最新(watch)的值就好

五、Jedis

匯入對應的依賴

<!--匯入jedis的包-->
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>

建立物件,命令與redis相同

六、SpringBoot整合

@Configuration
    public class RedisConfig {
        @Bean
        @SuppressWarnings("all")
        public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
            // 我們為了自己開發方便,一般直接使用 <String, Object>      
            RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
            template.setConnectionFactory(factory);
            // Json序列化配置      
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
            ObjectMapper om = new ObjectMapper();
            om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            jackson2JsonRedisSerializer.setObjectMapper(om);
            // String 的序列化      
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
            // key採用String的序列化方式    
            template.setKeySerializer(stringRedisSerializer);
            // hash的key也採用String的序列化方式    
            template.setHashKeySerializer(stringRedisSerializer);
            // value序列化方式採用jackson  
            template.setValueSerializer(jackson2JsonRedisSerializer);
            // hash的value序列化方式採用jackson      
            template.setHashValueSerializer(jackson2JsonRedisSerializer);
            template.afterPropertiesSet();
            return template;
        }
    }

七、Redis.conf詳解

網路

    bind 127.0.0.1 # 繫結的ip
    protected-mode yes # 保護模式
    port 6379 # 埠設定

通用 GENERAL

    daemonize yes  # 以守護程序的方式執行,預設是no,我們需要自己開啟為yes
    pidfile /var/run/redis_6379.pid # 如果以後臺的方式執行,我們就需要指定一個pid檔案
    # 日誌
    # Specify the server verbosity level.
    # This can be one of:
    # debug (a lot of information, useful for development/testing)
    # verbose (many rarely useful info, but not a mess like the debug level)
    # notice (moderately verbose, what you want in production probably)
    # warning (only very important / critical messages are logged)
    loglevel notice
    logfile ""  # 日誌的檔案位置名
    databases 16 # 資料庫的數量,預設是16個
    always-show-logo yes # 是否總是顯示logo

快照

  • 持久化,在規定的時間內,執行了多少次操作,則會持久化到檔案.rdb.aof
  • Redis是記憶體資料庫。,如果沒有持久化,那麼資料會斷點缺失
    save 900 1 # 如果900s內,至少有1個key進行了修改,我們就進行持久化操作
    save 300 10 # 如果300s內,至少有10個key進行了修改,我們就進行持久化操作
    save 60 10000 # 如果60s內,至少有10000個key進行了修改,我們就進行持久化操作
    stop-writes-on-bgsave-error yes # 持久化如果出錯,是否還要繼續工作
    rdbcompression yes # 是否壓縮rdb檔案,需要消耗一些cpu資源
    rdbchecksum yes # 儲存rdb檔案的時候,進行錯誤的檢查校驗
    dir ./ # rdb檔案儲存的目錄

SECURITY 安全

  • 可以設定redis的密碼,預設是沒有密碼的
    config get requirepass # 獲取redis的密碼
    config set requirepass password # 設定redis的密碼
    auth password # 使用密碼進行登入

限制 CLIENTS

    maxclients 10000 # 設定能連線上redis的最大客戶端數量
    maxmemory <bytes> # redis配置最大的記憶體容量
    maxmemory-policy noeviction # 記憶體達到上限之後的處理策略

APPEND ONLY MODE AOF配置

    appendonly no # 預設是不開啟aof模式的,預設是使用rdb方式持久化的,在大部分的情況下,rdb完全夠用
    appendfilename "appendonly.aof" # 持久化的檔名名字
    # appendfsync always # 每次修改都會sync,消耗效能
    appendfsync everysec # 每秒執行一次sync,可能會丟失中這1s的資料
    # appendfsync no # 不執行sync,這個時候作業系統自動同步資料,速度最快

八、Redis持久化

Redis是記憶體資料庫,如果不將記憶體中的資料庫狀態儲存到磁碟,那麼一旦伺服器程序退出,伺服器中的資料庫狀態也會消失。

RDB(Redis DataBase)

  • Redis會單獨建立(fork)一個子程序來進行持久化,會先將資料寫到一個臨時檔案中,等待持久化過程都結束了,再用這個臨時檔案替換上次持久化好的檔案。整個過程中,主程序是不進行任何IO操作的,這就確保了極高的效能。如果需要進行大規模資料的恢復,且對於資料恢復的完整性不是很敏感,那麼RDB方式要比AOF方式更加的高效。RDB的缺點是最後一次持久化的資料,可能丟失。
  • RDB儲存的檔案是dump.rdb,在配置檔案中配置的。
觸發機制
  • save的規則滿足的情況下,會自動觸發rdb規則
  • 執行flushall命令,也會觸發rdb規則
  • 退出redis,也會產生rdb檔案
恢復rdb檔案
  • 只需要將rdb檔案放在我們redis啟動目錄就可以,redis啟動的時候會自動檢查dump.rdb,恢復其中的資料
  • 檢視需要存在的位置:config get dir
優點:
  • 適合大規模的資料恢復
  • 對資料的完整性要求不高
缺點:
  • 需要一定的時間間隔程序操作,如果redis意外崩潰了,最後一次修改的資料就不會生效
  • fork程序的時候,會佔用一定的記憶體空間

AOF(Append Only File)

將我們所有的命令都記錄下來。

  • 以日誌的形式來記錄每個寫操作,將Redis執行過的所有指令記錄下來(讀操作不記錄),只許追加檔案但不可以改寫檔案,redis啟動之初會讀取該檔案重新構建資料,redis重啟的話就根據日誌檔案的內容將寫指令從前到後執行一次以完成資料的恢復工作。
  • AOF儲存的檔案是appendonly.aof檔案
  • redis-check-aof --fix aof檔案:用來修復這個aof檔案

優點:

  • 每一次修改都同步,檔案的完整性會更好
  • 每秒同步一次,可能會丟失一秒的資料
  • 從不同步,效率是最高的

缺點:

  • 相對於資料檔案來說,aof遠遠大於rdb,修復的資料也比rdb慢
  • aof執行效率也要比rdb慢

擴充套件:

  • RDB 持久化方式能夠在指定的時間間隔內對你的資料進行快照儲存
  • AOF 持久化方式記錄每次對伺服器寫的操作,當伺服器重啟的時候會重新執行這些命令來恢復原始 的資料,AOF命令以Redis 協議追加儲存每次寫的操作到檔案末尾,Redis還能對AOF檔案進行後臺重 寫,使得AOF檔案的體積不至於過大。
  • 只做快取,如果你只希望你的資料在伺服器執行的時候存在,你也可以不使用任何持久化
  • 同時開啟兩種持久化方式 在這種情況下,當redis重啟的時候會優先載入AOF檔案來恢復原始的資料,因為在通常情況下AOF 檔案儲存的資料集要比RDB檔案儲存的資料集要完整。 RDB 的資料不實時,同時使用兩者時伺服器重啟也只會找AOF檔案,那要不要只使用AOF呢?作者 建議不要,因為RDB更適合用於備份資料庫(AOF在不斷變化不好備份),快速重啟,而且不會有 AOF可能潛在的Bug,留著作為一個萬一的手段。

效能建議:

  • 因為RDB檔案只用作後備用途,建議只在Slave上持久化RDB檔案,而且只要15分鐘備份一次就夠 了,只保留 save 900 1 這條規則。
  • 如果Enable AOF ,好處是在惡劣情況下也只會丟失不超過兩秒資料,啟動指令碼較簡單隻load自 己的AOF檔案就可以了,代價一是帶來了持續的IO,二是AOF rewrite 的後將 rewrite 過程中產 生的新資料寫到新檔案造成的阻塞幾乎是不可避免的。只要硬碟許可,應該儘量減少AOF rewrite 的頻率,AOF重寫的基礎大小預設值64M太小了,可以設到5G以上,預設超過原大小100%大小重 寫可以改到適當的數值。
  • 如果不Enable AOF ,僅靠 Master-Slave Repllcation 實現高可用性也可以,能省掉一大筆IO,也 減少了rewrite時帶來的系統波動。代價是如果Master/Slave 同時倒掉,會丟失十幾分鐘的資料, 啟動指令碼也要比較兩個 Master/Slave 中的 RDB檔案,載入較新的那個,微博就是這種架構。