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

歡迎訪問 生活随笔!

生活随笔

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

数据库

Redis高级特性及优化

發布時間:2024/9/21 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis高级特性及优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2019獨角獸企業重金招聘Python工程師標準>>>

redis中鍵的生存時間(expire)

redis中可以使用expire命令設置一個鍵的生存時間,到時間后redis會自動刪除它。

?

  • 過期時間可以設置為秒或者毫秒精度。
  • 過期時間分辨率總是 1 毫秒。
  • 過期信息被復制和持久化到磁盤,當 Redis 停止時時間仍然在計算 (也就是說 Redis 保存了過期時間)。
  • ?

    ?

    expire? 設置生存時間(單位/秒)

    ?

    [python]?view plain?copy

    ?

  • expire?key?seconds(秒)??
  • ?

    ?

    ttl 查看鍵的剩余生存時間

    ?

    [python]?view plain?copy

    ?

  • ttl?key??
  • ?

    ?

    persist 取消生存時間

    ?

    [python]?view plain?copy

    ?

  • persist?key??
  • ?

    ?

    expireat [key] unix時間戳1351858600

    示例:

    ?

    [python]?view plain?copy

    ?

  • EXPIREAT?cache?1355292000?????#?這個?key?將在?2012.12.12?過期??
  • ?

    ?

    操作圖示:

    ?

    應用場景:

    ?

  • 限時的優惠活動信息
  • 網站數據緩存(對于一些需要定時更新的數據,例如:積分排行榜)
  • 手機驗證碼
  • 限制網站訪客訪問頻率(例如:1分鐘最多訪問10次)
  • ?

    ?

    ?

    ?

    redis的事務(transaction)

    ?

    redis中的事務是一組命令的集合。事務同命令一樣都是redis的最小執行單元。一組事務中的命令要么都執行,要么都不執行。(例如:轉賬)

    ?

    原理:

    先將屬于一個事務的命令發送給redis進行緩存,最后再讓redis依次執行這些命令。

    ?

    應用場景:

    ?

  • 一組命令必須同時都執行,或者都不執行。
  • 我們想要保證一組命令在執行的過程之中不被其它命令插入。
  • ?

    ?

    命令:

    ?

    [python]?view plain?copy

    ?

  • multi????//事務開始??
  • .....??
  • exec?????//事務結束,開始執行事務中的命令??
  • discard?????//放棄事務??
  • ?

    ?

    錯誤處理

    1:語法錯誤:致命的錯誤,事務中的所有命令都不會執行

    2:運行錯誤:不會影響事務中其他命令的執行

    ?

    Redis 不支持回滾(roll back)

    正因為redis不支持回滾功能,才使得redis在事務上可以保持簡潔和快速。

    ?

    watch命令

    作用:監控一個或者多個鍵,當被監控的鍵值被修改后阻止之后的一個事務的執行。

    但是不能保證其它客戶端不修改這一鍵值,所以我們需要在事務執行失敗后重新執行事務中的命令。

    注意:執行完事務的exec命令之后,watch就會取消對所有鍵值的監控

    unwatch:取消監控

    ?

    ?操作圖示:

    ?

    ?

    ?

    ?

    redis中數據的排序(sort)

    sort命令可以對列表類型,集合類型和有序集合類型進行排序。

    ?

    [python]?view plain?copy

    ?

  • sort?key?[desc]?[limit?offset?count]??
  • ?

    ?

    by 參考鍵(參考鍵可以是字符串類型或者是hash類型的某個字段,hash類型的格式為:鍵名->字段名)

    ?

  • 如果參考鍵中不帶*號則不排序
  • 如果某個元素的參考鍵不存在,則默認參考鍵的值為0
  • ?

    ?

    擴展 get參數

    ?

  • get參數的規則和by參數的規則一樣
  • get # (返回元素本身的值)
  • ?

    ?

    擴展 store參數

    使用store 參數可以把sort的排序結果保存到指定的列表中

    ?

    性能優化

    1:盡可能減少待排序鍵中元素的數量

    2:使用limit參數只獲取需要的數據

    3:如果要排序的數據數量很大,盡可能使用store參數將結果緩存。

    ?

    ?操作圖示:

    ?

    ??

    ?

    ?

    ?

    “發布/訂閱”模式

    ?

    發布:publish

    ?

    [python]?view plain?copy

    ?

  • publish?channel?message??
  • ?

    ?

    訂閱:subscribe

    ?

    [python]?view plain?copy

    ?

  • subscribe?channel?[.....]??
  • ?

    ?

    取消訂閱:unsubscribe

    ?

    [python]?view plain?copy

    ?

  • unsubscribe?[channel]??
  • ?

    ?

    按照規則訂閱:psubscribe

    ?

    [python]?view plain?copy

    ?

  • psubscribe?channel????
  • ?

    ?

    按照規則取消訂閱:punsubscribe

    注意:使用punsubscribe命令只能退訂通過psubscribe 訂閱的頻道。

    ?

    操作圖示:(訂閱頻道后,頻道每發布一條消息,都能動態顯示出來)

    訂閱:

    ?

    ?發布:

    ?

    ?

    ?

    ?

    redis任務隊列

    任務隊列:使用lpush和rpop(brpop)可以實現普通的任務隊列。

    ?brpop是列表的阻塞式(blocking)彈出原語。

    它是 RPOP命令的阻塞版本,當給定列表內沒有任何元素可供彈出的時候,連接將被 BRPOP命令阻塞,直到等待超時或發現可彈出元素為止。

    當給定多個?key?參數時,按參數?key?的先后順序依次檢查各個列表,彈出第一個非空列表的尾部元素。

    ?

    優先級隊列:

    ?

    [python]?view plain?copy

    ?

  • brpop?key1?key2?key3?timeout??

  • 操作圖示:

    ?

    ?

    ?

    ?

    ?

    redis管道(pipeline)

    redis的pipeline(管道)功能在命令行中沒有,但是redis是支持管道的,在java的客戶端(jedis)中是可以使用的。

    測試發現:

    1:不使用管道方式,插入1000條數據耗時328毫秒

    ?

    [java]?view plain?copy

    ?

  • //?測試不使用管道??
  • public?static?void?testInsert()?{??
  • ????long?currentTimeMillis?=?System.currentTimeMillis();??
  • ????Jedis?jedis?=?new?Jedis("192.168.33.130",?6379);??
  • ????for?(int?i?=?0;?i?<?1000;?i++)?{??
  • ????????jedis.set("test"?+?i,?"test"?+?i);??
  • ????}??
  • ????long?endTimeMillis?=?System.currentTimeMillis();??
  • ????System.out.println(endTimeMillis?-?currentTimeMillis);??
  • }??
  • ?

    ?

    2:使用管道方式,插入1000條數據耗時37毫秒

    ?

    [java]?view plain?copy

    ?

  • //?測試管道??
  • public?static?void?testPip()?{??
  • ????long?currentTimeMillis?=?System.currentTimeMillis();??
  • ????Jedis?jedis?=?new?Jedis("192.168.33.130",?6379);??
  • ????Pipeline?pipelined?=?jedis.pipelined();??
  • ????for?(int?i?=?0;?i?<?1000;?i++)?{??
  • ????????pipelined.set("bb"?+?i,?i?+?"bb");??
  • ????}??
  • ????pipelined.sync();??
  • ????long?endTimeMillis?=?System.currentTimeMillis();??
  • ????System.out.println(endTimeMillis?-?currentTimeMillis);??
  • }??
  • ?

    ?

    在插入更多數據的時候,管道的優勢更加明顯:測試10萬條數據的時候,不使用管道要40秒,實用管道378毫秒。

    ?

    ?

    ?

    redis持久化(persistence)

    redis支持兩種方式的持久化,可以單獨使用或者結合起來使用。

    第一種:RDB方式(redis默認的持久化方式)

    第二種:AOF方式

    ?

    ?

    ?

    redis持久化之RDB

    rdb方式的持久化是通過快照完成的,當符合一定條件時redis會自動將內存中的所有數據執行快照操作并存儲到硬盤上。默認存儲在dump.rdb文件中。(文件名在配置文件中dbfilename)

    ?

    redis進行快照的時機(在配置文件redis.conf中)

    ?

    [java]?view plain?copy

    ?

  • save?900?1??//表示900秒內至少一個鍵被更改則進行快照。??
  • save?300?10??//表示300秒內10條被更改則快照??
  • save?60?10000??//60秒內10000條??
  • ?

    ?

    Redis自動實現快照的過程

    1、redis使用fork函數復制一份當前進程的副本(子進程)

    2、父進程繼續接收并處理客戶端發來的命令,而子進程開始將內存中的數據寫入硬盤中的臨時文件

    3、當子進程寫入完所有數據后會用該臨時文件替換舊的RDB文件,至此,一次快照操作完成。

    ?

    注意:redis在進行快照的過程中不會修改RDB文件,只有快照結束后才會將舊的文件替換成新的,也就是說任何時候RDB文件都是完整的。

    這就使得我們可以通過定時備份RDB文件來實現redis數據庫的備份

    RDB文件是經過壓縮的二進制文件,占用的空間會小于內存中的數據,更加利于傳輸。

    ?

    手動執行save或者bgsave命令讓redis執行快照。

    兩個命令的區別在于,save是由主進程進行快照操作,會阻塞其它請求。bgsave是由redis執行fork函數復制出一個子進程來進行快照操作。

    ?

    文件修復:

    ?

    [python]?view plain?copy

    ?

  • redis-check-dump??
  • ?

    ?

    rdb的優缺點

    優點:由于存儲的有數據快照文件,恢復數據很方便。

    缺點:會丟失最后一次快照以后更改的所有數據。

    ?

    ?

    ?

    redis持久化之AOF

    ?

    aof方式的持久化是通過日志文件的方式。默認情況下redis沒有開啟aof,可以通過參數appendonly參數開啟。

    ?

    [python]?view plain?copy

    ?

  • appendonly?yes??
  • ?

    ?

    aof文件的保存位置和rdb文件的位置相同,都是dir參數設置的,默認的文件名是appendonly.aof,可以通過appendfilename參數修改

    ?

    [python]?view plain?copy

    ?

  • appendfilename?appendonly.aof??
  • ?

    ?

    redis寫命令同步的時機

    ?

    [python]?view plain?copy

    ?

  • appendfsync?always?每次都會執行??
  • appendfsync?everysec?默認?每秒執行一次同步操作(推薦,默認)??
  • appendfsync?no不主動進行同步,由操作系統來做,30秒一次??
  • ?

    ?

    aof日志文件重寫

    ?

    [python]?view plain?copy

    ?

  • auto-aof-rewrite-percentage?100(當目前aof文件大小超過上一次重寫時的aof文件大小的百分之多少時會再次進行重寫,如果之前沒有重寫,則以啟動時的aof文件大小為依據)??
  • auto-aof-rewrite-min-size?64mb??
  • ?

    ?

    手動執行bgrewriteaof進行重寫

    重寫的過程只和內存中的數據有關,和之前的aof文件無關。

    所謂的“重寫”其實是一個有歧義的詞語, 實際上, AOF 重寫并不需要對原有的 AOF 文件進行任何寫入和讀取, 它針對的是數據庫中鍵的當前值。

    ?

    文件修復:

    ?

    [python]?view plain?copy

    ?

  • redis-check-aof??
  • ?

    ?

    動態切換redis持久方式,從 RDB 切換到 AOF(支持Redis 2.2及以上)

    ?

    [python]?view plain?copy

    ?

  • CONFIG?SET?appendonly?yes??
  • CONFIG?SET?save?""(可選)??
  • ?

    ?

    注意:

    1、當redis啟動時,如果rdb持久化和aof持久化都打開了,那么程序會優先使用aof方式來恢復數據集,因為aof方式所保存的數據通常是最完整的。如果aof文件丟失了,則啟動之后數據庫內容為空。

    2、如果想把正在運行的redis數據庫,從RDB切換到AOF,建議先使用動態切換方式,再修改配置文件,重啟數據庫。(不能自己修改配置文件,重啟數據庫,否則數據庫中數據就為空了。)

    ?

    ?

    ?

    redis中的config命令

    ?

    使用config set可以動態設置參數信息,服務器重啟之后就失效了。

    ?

    [python]?view plain?copy

    ?

  • config?set?appendonly?yes??
  • config?set?save?"90?1?30?10?60?100"??
  • ?

    ?

    使用config get可以查看所有可以使用config set命令設置的參數

    ?

    [python]?view plain?copy

    ?

  • config?get?*??
  • ?

    ?

    使用config rewrite命令對啟動 Redis 服務器時所指定的 redis.conf 文件進行改寫(Redis 2.8 及以上版本才可以使用),主要是把使用config set動態指定的命令保存到配置文件中。

    ?

    [python]?view plain?copy

    ?

  • config?rewrite??
  • ?

    ?

    注意:config rewrite命令對 redis.conf 文件的重寫是原子性的, 并且是一致的: 如果重寫出錯或重寫期間服務器崩潰, 那么重寫失敗, 原有 redis.conf 文件不會被修改。 如果重寫成功, 那么 redis.conf 文件為重寫后的新文件。

    ?

    ?

    ?

    redis的安全策略

    ?

    設置數據庫密碼

    修改配置

    ?

    [python]?view plain?copy

    ?

  • requirepass?password??
  • ?

    ?

    驗證密碼

    ?

    [python]?view plain?copy

    ?

  • auth?password??
  • ?

    ?

    bind參數(可以讓數據庫只能在指定IP下訪問)

    ?

    [python]?view plain?copy

    ?

  • bind?127.0.0.1??
  • ?

    ?

    命令重命名

    修改命令的名稱

    ?

    [python]?view plain?copy

    ?

  • rename-command?flushall?cleanall??
  • ?

    ?

    禁用命令?

    ?

    [python]?view plain?copy

    ?

  • rename-command?flushall?""??
  • ?

    ?

    ?

    ?

    ?

    redis工具

    redis-cli??命令行

    ?

    [python]?view plain?copy

    ?

  • info/monitor(調試命令)??
  • ?

    ?

    Redisclient(redis數據庫可視化工具,不怎么實用)

    http://www.oschina.net/news/53391/redisclient-1-0

    http://www.oschina.net/news/55634/redisclient-2-0

    ?

    ?

    ?

    ?

    redis info命令

    以一種易于解釋(parse)且易于閱讀的格式,返回關于 Redis 服務器的各種信息和統計數值。

    通過給定可選的參數?section?,可以讓命令只返回某一部分的信息:

    ?

    內容過多,詳細參考

    http://redisdoc.com/server/info.html

    ?

    ?

    ?

    redis內存占用情況

    測試情況:

    100萬個鍵值對(鍵是0到999999值是字符串“hello world”)在32位操作系統的筆記本上 用了100MB

    使用64位的操作系統的話,相對來說占用的內存會多一點,這是因為64位的系統里指針占用了8個字節,但是64位系統也能支持更大的內存,所以運行大型的redis服務還是建議使用64位服務器

    ?

    ?

    ?

    Redis實例最多存keys數

    ?

    理論上Redis可以處理多達2的32次方的keys,并且在實際中進行了測試,每個實例至少存放了2億5千萬的keys

    也可以說Redis的存儲極限是系統中的可用內存值。

    ?

    ?

    ?

    ?

    redis優化1

    ?

    精簡鍵名和鍵值

    鍵名:盡量精簡,但是也不能單純為了節約空間而使用不易理解的鍵名。

    鍵值:對于鍵值的數量固定的話可以使用0和1這樣的數字來表示,(例如:male/female、right/wrong)

    當業務場景不需要數據持久化時,關閉所有的持久化方式可以獲得最佳的性能

    ?

    內部編碼優化(大家可以自己了解)

    redis為每種數據類型都提供了兩種內部編碼方式,在不同的情況下redis會自動調整合適的編碼方式。(如圖所示)

    ?

    ?

    SLOWLOG [get/reset/len]

    ?

    [python]?view plain?copy

    ?

  • slowlog-log-slower-than??//它決定要對執行時間大于多少微秒(microsecond,1秒?=?1,000,000?微秒)的命令進行記錄??
  • slowlog-max-len???//它決定?slowlog?最多能保存多少條日志??
  • ?

    當發現redis性能下降的時候可以查看下是哪些命令導致的

    ?

    ?

    ?

    redis優化2

    ?

    修改linux內核內存分配策略

    原因:

    ?

    redis在運行過程中可能會出現下面問題

    錯誤日志:

    ?

    [java]?view plain?copy

    ?

  • WARNING?overcommit_memory?is?set?to?0!?Background?save?may?fail?under?low?memory?condition.?To?fix?this?issue?add?'vm.overcommit_memory?=?1'?to?/etc/sysctl.conf?and?then?reboot?or?run?the?command?'sysctl?vm.overcommit_memory=1'??
  • ?

    ?

    redis在備份數據的時候,會fork出一個子進程,理論上child進程所占用的內存和parent是一樣的,比如parent占用的內存為8G,這個時候也要同樣分配8G的內存給child,如果內存無法負擔,往往會造成redis服務器的down機或者IO負載過高,效率下降。所以內存分配策略應該設置為 1(表示內核允許分配所有的物理內存,而不管當前的內存狀態如何)。

    內存分配策略有三種

    可選值:0、1、2。

    0, 表示內核將檢查是否有足夠的可用內存供應用進程使用;如果有足夠的可用內存,內存申請允許;否則,內存申請失敗,并把錯誤返回給應用進程。

    1, 不管需要多少內存,都允許申請。

    2, 只允許分配物理內存和交換內存的大小。(交換內存一般是物理內存的一半)

    ?

    向/etc/sysctl.conf添加

    ?

    [python]?view plain?copy

    ?

  • vm.overcommit_memory?=?1????//然后重啟服務器??
  • ?

    或者執行

    ?

    [python]?view plain?copy

    ?

  • sysctl?vm.overcommit_memory=1???//立即生效??
  • ?

    ?

    問題圖示:

    ?

    ?

    ?

    redis優化3

    關閉Transparent Huge Pages(THP)

    THP會造成內存鎖影響redis性能,建議關閉

    ?

    [python]?view plain?copy

    ?

  • Transparent?HugePages?:用來提高內存管理的性能??
  • Transparent?Huge?Pages在32位的RHEL?6中是不支持的??
  • ?

    ?

    使用root用戶執行下面命令

    ?

    [python]?view plain?copy

    ?

  • echo?never?>?/sys/kernel/mm/transparent_hugepage/enabled??
  • ?

    ?

    把這條命令添加到這個文件中/etc/rc.local

    ?

    ?

    ?

    ?

    ?

    redis優化4

    修改linux中TCP 監聽的最大容納數量

    在高并發環境下你需要一個高backlog值來避免慢客戶端連接問題。注意Linux內核默默地將這個值減小到/proc/sys/net/core/somaxconn的值,所以需要確認增大somaxconn和tcp_max_syn_backlog兩個值來達到想要的效果。

    ?

    [python]?view plain?copy

    ?

  • echo?511?>?/proc/sys/net/core/somaxconn??
  • ?

    注意:這個參數并不是限制redis的最大鏈接數。如果想限制redis的最大連接數需要修改maxclients,默認最大連接數為10000。

    ?

    ?

    ?

    ?

    ?

    redis優化5

    ?

    限制redis的內存大小

    通過redis的info命令查看內存使用情況

    如果不設置maxmemory或者設置為0,64位系統不限制內存,32位系統最多使用3GB內存。

    修改配置文件中的maxmemory和maxmemory-policy

    ?

    [python]?view plain?copy

    ?

  • maxmemory:最大內存??
  • maxmemory-policy:內存不足時,數據清除策略??
  • ?

    ?

    如果可以確定數據總量不大,并且內存足夠的情況下不需要限制redis使用的內存大小。如果數據量不可預估,并且內存也有限的話,盡量限制下redis使用的內存大小,這樣可以避免redis使用swap分區或者出現OOM錯誤。

    注意:如果不限制內存,當物理內存使用完之后,會使用swap分區,這樣性能較低,如果限制了內存,當到達指定內存之后就不能添加數據了,否則會報OOM錯誤。可以設置maxmemory-policy,內存不足時刪除數據。

    ?

    拓展

    used_memory是Redis使用的內存總量,它包含了實際緩存占用的內存和Redis自身運行所占用的內存(以字節(byte)為單位,其中used_memory_human上的數據和used_memory是一樣的值,它以M為單位顯示,僅為了方便閱讀)。

    ?

    如果一個Redis實例的內存使用率超過可用最大內存(used_memory >可用最大內存),那么操作系統開始進行內存與swap空間交換,把內存中舊的或不再使用的內容寫入硬盤上(硬盤上的這塊空間叫Swap分區),以便騰出新的物理內存給新頁或活動頁(page)使用。

    ?

    在硬盤上進行讀寫操作要比在內存上進行讀寫操作,時間上慢了近5個數量級,內存是0.1us(微秒)、而硬盤是10ms(毫秒)。如果Redis進程上發生內存交換,那么Redis和依賴Redis上數據的應用會受到嚴重的性能影響。 通過查看used_memory指標可知道Redis正在使用的內存情況,如果used_memory>可用最大內存,那就說明Redis實例正在進行內存交換或者已經內存交換完畢。管理員根據這個情況,執行相對應的應急措施。

    ?

    排查方案:

    若是在使用Redis期間沒有開啟rdb快照或aof持久化策略,那么緩存數據在Redis崩潰時就有丟失的危險。因為當Redis內存使用率超過可用內存的95%時,部分數據開始在內存與swap空間來回交換,這時就可能有丟失數據的危險。

    當開啟并觸發快照功能時,Redis會fork一個子進程把當前內存中的數據完全復制一份寫入到硬盤上。因此若是當前使用內存超過可用內存的45%時觸發快照功能,那么此時進行的內存交換會變的非常危險(可能會丟失數據)。 倘若在這個時候實例上有大量頻繁的更新操作,問題會變得更加嚴重。

    ?

    通過減少Redis的內存占用率,來避免這樣的問題,或者使用下面的技巧來避免內存交換發生:

    1、盡可能的使用Hash數據結構。因為Redis在儲存小于100個字段的Hash結構上,其存儲效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的時候,盡可能的使用Hash結構。比如,在一個web應用程序中,需要存儲一個對象表示用戶信息,使用單個key表示一個用戶,其每個屬性存儲在Hash的字段里,這樣要比給每個屬性單獨設置一個key-value要高效的多。 通常情況下倘若有數據使用string結構,用多個key存儲時,那么應該轉換成單key多字段的Hash結構。 如上述例子中介紹的Hash結構應包含,單個對象的屬性或者單個用戶各種各樣的資料。Hash結構的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存儲或從Hash中取出指定的字段。

    ?

    2、設置key的過期時間。一個減少內存使用率的簡單方法就是,每當存儲對象時確保設置key的過期時間。倘若key在明確的時間周期內使用或者舊key不大可能被使用時,就可以用Redis過期時間命令(expire,expireat, pexpire, pexpireat)去設置過期時間,這樣Redis會在key過期時自動刪除key。 假如你知道每秒鐘有多少個新key-value被創建,那可以調整key的存活時間,并指定閥值去限制Redis使用的最大內存。

    ?

    3、回收key。在Redis配置文件中(一般叫Redis.conf),通過設置“maxmemory”屬性的值可以限制Redis最大使用的內存,修改后重啟實例生效。也可以使用客戶端命令config set maxmemory 去修改值,這個命令是立即生效的,但會在重啟后會失效,需要使用config rewrite命令去刷新配置文件。 若是啟用了Redis快照功能,應該設置“maxmemory”值為系統可使用內存的45%,因為快照時需要一倍的內存來復制整個數據集,也就是說如果當前已使用45%,在快照期間會變成95%(45%+45%+5%),其中5%是預留給其他的開銷。 如果沒開啟快照功能,maxmemory最高能設置為系統可用內存的95%。

    ?

    ?

    當內存使用達到設置的最大閥值時,需要選擇一種key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”屬性值。 若是Redis數據集中的key都設置了過期時間,那么“volatile-ttl”策略是比較好的選擇。但如果key在達到最大內存限制時沒能夠迅速過期,或者根本沒有設置過期時間。那么設置為“allkeys-lru”值比較合適,它允許Redis從整個數據集中挑選最近最少使用的key進行刪除(LRU淘汰算法)。Redis還提供了一些其他淘汰策略,如下:

    ?

    [python]?view plain?copy

    ?

  • volatile-lru:?使用LRU算法從已設置過期時間的數據集合中淘汰數據。??
  • volatile-ttl:從已設置過期時間的數據集合中挑選即將過期的數據淘汰。??
  • volatile-random:從已設置過期時間的數據集合中隨機挑選數據淘汰。??
  • allkeys-lru:使用LRU算法從所有數據集合中淘汰數據。??
  • allkeys-random:從數據集合中任意選擇數據淘汰??
  • no-enviction:禁止淘汰數據。??
  • ?

    ?

    通過設置maxmemory為系統可用內存的45%或95%(取決于持久化策略)和設置“maxmemory-policy”為“volatile-ttl”或“allkeys-lru”(取決于過期設置),可以比較準確的限制Redis最大內存使用率,在絕大多數場景下使用這2種方式可確保Redis不會進行內存交換。倘若你擔心由于限制了內存使用率導致丟失數據的話,可以設置noneviction值禁止淘汰數據。

    ?

    ?

    ?

    redis優化6

    ?

    Redis是個單線程模型,客戶端過來的命令是按照順序執行的,所以想要一次添加多條數據的時候可以使用管道,或者使用一次可以添加多條數據的命令,例如:

    ?

    ?

    ?

    ?

    ?

    Redis應用場景

    ?

    發布與訂閱

    在更新中保持用戶對數據的映射是系統中的一個普遍任務。Redis的pub/sub功能使用了SUBSCRIBE、UNSUBSCRIBE和PUBLISH命令,讓這個變得更加容易。

    ?

    代碼示例:

    ?

    [java]?view plain?copy

    ?

  • //?訂閱頻道數據??
  • public?static?void?testSubscribe()?{??
  • ????//連接Redis數據庫??
  • ????Jedis?jedis?=?new?Jedis("192.168.33.130",?6379);??
  • ????JedisPubSub?jedisPubSub?=?new?JedisPubSub()?{??
  • ??
  • ????????//?當向監聽的頻道發送數據時,這個方法會被觸發??
  • ????????@Override??
  • ????????public?void?onMessage(String?channel,?String?message)?{??
  • ????????????System.out.println("收到消息"?+?message);??
  • ????????????//當收到?"unsubscribe"?消息時,調用取消訂閱方法??
  • ????????????if?("unsubscribe".equals(message))?{??
  • ????????????????this.unsubscribe();??
  • ????????????}??
  • ????????}??
  • ??
  • ????????//?當取消訂閱指定頻道的時候,這個方法會被觸發??
  • ????????@Override??
  • ????????public?void?onUnsubscribe(String?channel,?int?subscribedChannels)?{??
  • ????????????System.out.println("取消訂閱頻道"?+?channel);??
  • ????????}??
  • ??
  • ????};??
  • ????//?訂閱之后,當前進程一致處于監聽狀態,當被取消訂閱之后,當前進程會結束??
  • ????jedis.subscribe(jedisPubSub,?"ch1");??
  • }??
  • ??
  • ??
  • //?發布頻道數據??
  • public?static?void?testPubSub()?throws?Exception?{??
  • ????//鏈接Redis數據庫??
  • ????Jedis?jedis?=?new?Jedis("192.168.33.130",?6379);??
  • ????//發布頻道?"ch1"?和消息?"hello?redis"??
  • ????jedis.publish("ch1",?"hello?redis");??
  • ????//關閉連接??
  • ????jedis.close();??
  • }??
  • ?

    打印結果:

    ?

    ?

    限制網站訪客訪問頻率

    進行各種數據統計的用途是非常廣泛的,比如想知道什么時候封鎖一個IP地址。INCRBY命令讓這些變得很容易,通過原子遞增保持計數;GETSET用來重置計數器;過期屬性expire用來確認一個關鍵字什么時候應該刪除。

    ?

    代碼示例:

    [java]?view plain?copy

    ?

  • //指定Redis數據庫連接的IP和端口??
  • String?host?=?"192.168.33.130";??
  • int?port?=?6379;??
  • Jedis?jedis?=?new?Jedis(host,?port);??
  • ??
  • /**?
  • ?*?限制網站訪客訪問頻率?一分鐘之內最多訪問10次?
  • ?*??
  • ?*?@throws?Exception?
  • ?*/??
  • @Test??
  • public?void?test3()?throws?Exception?{??
  • ????//?模擬用戶的頻繁請求??
  • ????for?(int?i?=?0;?i?<?20;?i++)?{??
  • ????????boolean?result?=?testLogin("192.168.1.100");??
  • ????????if?(result)?{??
  • ????????????System.out.println("正常訪問");??
  • ????????}?else?{??
  • ????????????System.err.println("訪問受限");??
  • ????????}??
  • ????}??
  • ??
  • }??
  • ??
  • /**?
  • ?*?判斷用戶是否可以訪問網站?
  • ?*??
  • ?*?@param?ip?
  • ?*?@return?
  • ?*/??
  • public?boolean?testLogin(String?ip)?{??
  • ????String?value?=?jedis.get(ip);??
  • ????if?(value?==?null)?{??
  • ????????//初始化時設置IP訪問次數為1??
  • ????????jedis.set(ip,?"1");??
  • ????????//設置IP的生存時間為60秒,60秒內IP的訪問次數由程序控制??
  • ????????jedis.expire(ip,?60);??
  • ????}?else?{??
  • ????????int?parseInt?=?Integer.parseInt(value);??
  • ????????//如果60秒內IP的訪問次數超過10,返回false,實現了超過10次禁止分的功能??
  • ????????if?(parseInt?>?10)?{??
  • ????????????return?false;??
  • ????????}?else?{??
  • ????????????//如果沒有10次,可以自增??
  • ????????????jedis.incr(ip);??
  • ????????}??
  • ????}??
  • ????return?true;??
  • }??
  • ?

    打印結果:

    ?

    ?

    ?

    監控變量在事務執行時是否被修改

    ?

    代碼示例:

    ?

    [java]?view plain?copy

    ?

  • //?指定Redis數據庫連接的IP和端口??
  • String?host?=?"192.168.33.130";??
  • int?port?=?6379;??
  • Jedis?jedis?=?new?Jedis(host,?port);??
  • ??
  • /**?
  • ?*?監控變量a在一段時間內是否被修改,若沒有,則執行事務,若被修改,則事務不執行?
  • ?*??
  • ?*?@throws?Exception?
  • ?*/??
  • @Test??
  • public?void?test4()?throws?Exception?{??
  • ????//監控變量a,在事務執行后watch功能也結束??
  • ????jedis.watch("a");??
  • ????//需要數據庫中先有a,并且a的值為字符串數字??
  • ????String?value?=?jedis.get("a");??
  • ????int?parseInt?=?Integer.parseInt(value);??
  • ????parseInt++;??
  • ????System.out.println("線程開始休息。。。");??
  • ????Thread.sleep(5000);??
  • ??
  • ????//開啟事務??
  • ????Transaction?transaction?=?jedis.multi();??
  • ????transaction.set("a",?parseInt?+?"");??
  • ????//執行事務??
  • ????List<Object>?exec?=?transaction.exec();??
  • ????if?(exec?==?null)?{??
  • ????????System.out.println("事務沒有執行.....");??
  • ????}?else?{??
  • ????????System.out.println("正常執行......");??
  • ????}??
  • }??
  • ?

    打印結果:

    變量a沒有被修改時:

    ?

    ?

    變量a被修改時:

    ?

    ?

    ?

    各種計數

    商品維度計數(喜歡數,評論數,鑒定數,瀏覽數,etc)

    采用Redis 的類型: Hash. 如果你對redis數據類型不太熟悉,可以參考 http://redis.io/topics/data-types-intro

    為product定義個key product:,為每種數值定義hashkey, 譬如喜歡數xihuan

    ?

    ?

    用戶維度計數(動態數、關注數、粉絲數、喜歡商品數、發帖數 等)

    用戶維度計數同商品維度計數都采用 Hash. 為User定義個key user:,為每種數值定義hashkey, 譬如關注數follow

    ??

    ?

    ?

    存儲社交關系

    譬如將用戶的好友/粉絲/關注,可以存在一個sorted set中,score可以是timestamp,這樣求兩個人的共同好友的操作,可能就只需要用求交集命令即可。

    ?

    ?

    ?

    用作緩存代替memcached

    緩存內容示例:(商品列表,評論列表,@提示列表,etc)

    相對memcached 簡單的key-value存儲來說,redis眾多的數據結構(list,set,sorted set,hash, etc)可以更方便cache各種業務數據,性能也不亞于memcached。

    例如:

    ?

    [python]?view plain?copy

    ?

  • RPUSH?pagewviews.user:?EXPIRE?pagewviews.user:?60??//注意要update?timeout??
  • ?

    ?

    ?

    反spam系統

    例如:(評論,發布商品,論壇發貼,etc)

    作為一個電商網站被各種spam攻擊是少不免(垃圾評論、發布垃圾商品、廣告、刷自家商品排名等),針對這些spam制定一系列anti-spam規則,其中有些規則可以利用redis做實時分析,譬如:1分鐘評論不得超過2次、5分鐘評論少于5次等(更多機制/規則需要結合drools )。 采用sorted set將最近一天用戶操作記錄起來(為什么不全部記錄?節省memory,全部操作會記錄到log,后續利用hadoop進行更全面分析統計),通過

    ?

    [python]?view plain?copy

    ?

  • redis>?RANGEBYSCORE?user:200000:operation:comment?61307510405600?+inf????//獲得1分鐘內的操作記錄??
  • redis>?ZADD?user:200000:operation:comment?61307510402300?"這是一條評論"??//score?為timestamp?(integer)?1??
  • redis>?ZRANGEBYSCORE?user:200000:operation:comment?61307510405600?+inf???//獲得1分鐘內的操作記錄??

  • 打印結果:

    ?

    ?

    [python]?view plain?copy

    ?

  • 1)?"這是一條評論"??
  • ?

    ?

    ?

    用戶Timeline/Feeds

    在逛有個類似微博的欄目我關注,里面包括關注的人、主題、品牌的動態。redis在這邊主要當作cache使用。

    ?

    ?

    ?

    最新列表&排行榜

    這里采用Redis的List數據結構或sorted set 結構, 方便實現最新列表or排行榜 等業務場景。

    ?

    ?

    消息通知

    其實這業務場景也可以算在計數上,也是采用Hash。如下:

    ?

    ?

    ?

    消息隊列

    當在集群環境時候,java ConcurrentLinkedQueue 就無法滿足我們需求,此時可以采用Redis的List數據結構實現分布式的消息隊列。

    ?

    ?

    顯示最新的項目列表

    Redis使用的是常駐內存的緩存,速度非常快。LPUSH用來插入一個內容ID,作為關鍵字存儲在列表頭部。LTRIM用來限制列表中的項目數最多為5000。如果用戶需要的檢索的數據量超越這個緩存容量,這時才需要把請求發送到數據庫。

    ?

    ?

    刪除和過濾。

    如果一篇文章被刪除,可以使用LREM從緩存中徹底清除掉。

    ?

    ?

    排行榜及相關問題

    排行榜(leader board)按照得分進行排序。ZADD命令可以直接實現這個功能,而ZREVRANGE命令可以用來按照得分來獲取前100名的用戶,ZRANK可以用來獲取用戶排名,非常直接而且操作容易。

    ?

    ?

    按照用戶投票和時間排序

    這就像Reddit的排行榜,得分會隨著時間變化。LPUSH和LTRIM命令結合運用,把文章添加到一個列表中。一項后臺任務用來獲取列表,并重新計算列表的排序,ZADD命令用來按照新的順序填充生成列表。列表可以實現非常快速的檢索,即使是負載很重的站點。

    ?

    ?

    過期項目處理

    使用unix時間作為關鍵字,用來保持列表能夠按時間排序。對current_time和time_to_live進行檢索,完成查找過期項目的艱巨任務。另一項后臺任務使用ZRANGE...WITHSCORES進行查詢,刪除過期的條目。

    ?

    ?

    特定時間內的特定項目

    這是特定訪問者的問題,可以通過給每次頁面瀏覽使用SADD命令來解決。SADD不會將已經存在的成員添加到一個集合。

    ?

    ?

    實時分析

    使用Redis原語命令,更容易實施垃圾郵件過濾系統或其他實時跟蹤系統。

    ?

    ?

    隊列

    在當前的編程中隊列隨處可見。除了push和pop類型的命令之外,Redis還有阻塞隊列的命令,能夠讓一個程序在執行時被另一個程序添加到隊列。你也可以做些更有趣的事情,比如一個旋轉更新的RSS feed隊列。

    ?

    ?

    緩存

    Redis緩存使用的方式與memcache相同。

    網絡應用不能無休止地進行模型的戰爭,看看這些Redis的原語命令,盡管簡單但功能強大,把它們加以組合,所能完成的就更無法想象。當然,你可以專門編寫代碼來完成所有這些操作,但Redis實現起來顯然更為輕松。

    ?

    ?

    手機驗證碼

    使用expire設置驗證碼失效時間

    redis既可以作為數據庫來用,也可以作為緩存系統來用

    轉載于:https://my.oschina.net/rechardchensir/blog/3002100

    總結

    以上是生活随笔為你收集整理的Redis高级特性及优化的全部內容,希望文章能夠幫你解決所遇到的問題。

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