【數據庫】Redis基礎篇

歡迎關注公衆號:【愛編碼】 若是有須要後臺回覆2019贈送1T的學習資料哦!!html

簡介

Redis是一個開源(BSD許可)的內存數據結構存儲,用做數據庫、緩存和消息代理。它支持諸如字符串、散列、列表、集、帶範圍查詢的排序集、位圖、hyperloglog、帶半徑查詢和流的地理空間索引等數據結構。mysql

Redis具備內置的複製、Lua腳本、LRU清除、事務和不一樣級別的磁盤持久性,並經過Redis Sentinel和Redis集羣的自動分區提供高可用性。redis

原理與架構

Redis使用了單線程架構和I/O多路複用模型來實現高性能的內存數據庫服務。sql

單線程模型

由於Redis是單線程來處理命令的,因此一條命令從客戶端達到服務端不會馬上被執行。全部命令都會進入一個隊列中,而後逐個被執行,所以不會產生併發問題數據庫

爲何單線程還能這麼快

  • 1.純內存訪問,Redis將全部數據放在內存中,內存的響應時長大 約爲100納秒,這是Redis達到每秒萬級別訪問的重要基礎。後端

  • 2.非阻塞I/O,Redis使用epoll做爲I/O多路複用技術的實現,再加上Redis自身的事件處理模型將epoll中的鏈接、讀寫、關閉都轉換爲事件,不在網絡I/O上浪費過多的時間,以下圖所示 緩存

    1. 單線程避免了線程切換和競態產生的消耗。

注:阻塞的操做是會很是影響Redis性能,這個下次再總結安全

API使用場景

命令語法能夠到下面地址查,本節僅僅說使用場景。 www.runoob.com/redis/redis…bash

字符串

  • 1.緩存功能 Redis做爲緩存層,MySQL做爲存儲層,絕大部分請求的數據都是從Redis中獲取。因爲Redis具備支撐高併發的特性,因此緩存一般能起到加速讀寫和下降後端壓力的做用。

相似下面這樣子的僞代碼網絡

// 從MySQL獲取用戶信息
userInfo = mysql.get(id);
// 將userInfo序列化,並存入Redis
redis.setex(userRedisKey, 3600, serialize(userInfo));
// 返回結果
return userInfo
複製代碼
  • 2.計數 例如使用Redis做爲文章點贊數計數的基礎組件,用戶每一次點贊,相應的點贊數就會自增1
long incrLikeCounter(long id) {
    key = "article:like:" + id;
    return redis.incr(key);
}
複製代碼
  • 3.共享Session 使用Redis將用戶的Session進行集中管理,每次用戶更新或者查詢登陸信息都直接從Redis中集中獲取。

  • 4.限速 不少應用出於安全的考慮,會在每次進行登陸時,讓用戶輸入手機驗證碼,從而肯定是不是用戶本人。可是爲了短信接口不被頻繁訪問,會限制用戶每分鐘獲取驗證碼的頻率。 相似以下僞代碼
phoneNum = "138xxxxxxxx";
key = "shortMsg:limit:" + phoneNum;
// SET key value EX 60 NX
isExists = redis.set(key,1,"EX 60","NX");
if(isExists != null || redis.incr(key) <=5){
// 經過
}else{
// 限速
}
複製代碼

哈希

關係型數據表記錄的兩條用戶信息,用戶的屬性做爲表的列,每條用戶信息做爲行。

相比於使用字符串序列化緩存用戶信息,哈希類型變得更加直觀,而且在更新操做上會更加便捷。能夠將每一個用戶的id定義爲鍵後綴,多對fieldvalue對應每一個用戶的屬性。 相似以下僞代碼:

UserInfo getUserInfo(long id){
// 用戶id做爲key後綴
userRedisKey = "user:info:" + id;
// 使用hgetall獲取全部用戶信息映射關係
userInfoMap = redis.hgetAll(userRedisKey);
UserInfo userInfo;
if (userInfoMap != null) {
// 將映射關係轉換爲UserInfo
userInfo = transferMapToUserInfo(userInfoMap);
} else {
// 從MySQL中獲取用戶信息
userInfo = mysql.get(id);
// 將userInfo變爲映射關係使用hmset保存到Redis中
redis.hmset(userRedisKey, transferUserInfoToMap(userInfo));
// 添加過時時間
redis.expire(userRedisKey, 3600);
}
return userInfo;
}
複製代碼

列表

列表是一種比較靈活的數據結構,它能夠充當棧和隊列。

相關命令時間複雜度表:

  • 消息隊列 Redis的lpush+brpop命令組合便可實現阻塞隊列,生產者客戶端使用lrpush從列表左側插入元素,多個消費者客戶端使用brpop命令阻塞式的「搶」列表尾部的元素,多個客戶端保證了消費的負載均衡和高可用性。如圖所示:

口訣:

  • lpush+lpop=Stack(棧)
  • lpush+rpop=Queue(隊列)
  • lpsh+ltrim=Capped Collection(有限集合)
  • lpush+brpop=Message Queue(消息隊列)

集合

集合類型比較典型的使用場景是標籤(tag)。例如一個用戶可能對娛樂、體育比較感興趣,另外一個用戶可能對歷史、新聞比較感興趣,這些興趣點就是標籤。 有了這些數據就能夠獲得喜歡同一個標籤的人,以及用戶的共同喜愛的標籤,這些數據對於用戶體驗以及加強用戶黏度比較重要。 例如一個電子商務的網站會對不一樣標籤的用戶作不一樣類型的推薦,好比對數碼產品比較感興趣的人,在各個頁面或者經過郵件的形式給他們推薦最新的數碼產品,一般會爲網站帶來更多的利益。

相關命令時間複雜度表:

標籤實現基本思路

1.給用戶添加標籤

sadd user:1:tags tag1 tag2 tag5
sadd user:2:tags tag2 tag3 tag5
...
sadd user:k:tags tag1 tag2 tag4
...
複製代碼

2.給標籤添加用戶

sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2 user:3
...
sadd tagk:users user:1 user:2
...
複製代碼

3.使用sinter命令,來計算用戶共同感興趣的標籤

sinter user:1:tags user:2:tags
複製代碼

注:1,2步應該在同一個事務(下一篇文章再講)中執行,不然會致使數據不正確。

更多組合應用:

  • sadd=Tagging(標籤)
  • spop/srandmember=Random item(生成隨機數,好比抽獎)
  • sadd+sinter=Social Graph(社交需求)

有序集合

它保留了集合不能有重複成員的特性,給每一個元素設置一個**分數(score)**做爲排序的依據。

場景

排行榜系統 例如視頻網站須要對用戶上傳的視頻作排行榜,榜單的維度多是多個方面的:按照時間、按照播放數量、按照得到的贊數。

本節使用贊數這個維度,記錄天天用戶上傳視頻的排行榜。 主要須要實現如下4個功能

  • 1.添加用戶贊數
//得到一個贊。
zadd user:ranking:2016_03_15 mike 3   
 //第一個贊以後自增。
zincrby user:ranking:2016_03_15 mike 1
複製代碼
  • 2.取消用戶贊數
zrem user:ranking:2016_03_15 mike
複製代碼
  • 3.展現獲取贊數最多的十個用戶
zrevrangebyrank user:ranking:2016_03_15 0 9
複製代碼
  • 4.展現用戶信息以及用戶分數
hgetall user:info:tom
zscore user:ranking:2016_03_15 mike
zrank user:ranking:2016_03_15 mike
複製代碼

總結

Redis還有什麼場景,歡迎各位大神指教。

本文全部知識點來自於【Redis開發與運維(付磊)】,這本書很是值得一讀。

關注公衆號【愛編碼】回覆付磊便可獲取。

最後

若是對 Java、大數據感興趣請長按二維碼關注一波,我會努力帶給大家價值。以爲對你哪怕有一丁點幫助的請幫忙點個贊或者轉發哦。

關注公衆號【愛編碼】,回覆2019有相關資料哦。

相關文章
相關標籤/搜索