<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                > **Redis 場景使用** [TOC] ## 說明 ## **最近在整理Redis的一些使用場景, 包含我在工作當中的例子和網上看到比較好的文章。** ---------- ##參考文章## > 平凡希:https://www.cnblogs.com/xiaoxi/p/7007695.html ## String ## <h5>介紹</h5> String 數據結構是簡單的key-value類型,value其實不僅是String,也可以是數字。 常用命令:get、set、incr、decr、mget等。 應用場景:String是最常用的一種數據類型,普通的key/ value 存儲都可以歸為此類,即可以完全實現目前 Memcached 的功能,并且效率更高。還可以享受Redis的定時持久化,操作日志及 Replication等功能。除了提供與 Memcached 一樣的get、set、incr、decr 等操作外,Redis還提供了下面一些操作: 獲取字符串長度 往字符串append內容 設置和獲取字符串的某一段內容 設置及獲取字符串的某一位(bit) 批量設置一系列字符串的內容 使用場景:常規key-value緩存應用。常規計數: 微博數, 粉絲數。 實現方式:String在redis內部存儲默認就是一個字符串,被redisObject所引用,當遇到incr,decr等操作時會轉成數值型進行計算,此時redisObject的encoding字段為int。 <h5>存儲信息1</h5> 用戶ID為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結構來存儲,主要有以下2種存儲方式: ![請輸入圖片描述][1] 將用戶相關的信息轉換為JSON字符串,存儲在string類型中 $userInfo=['name'=>'depp', 'age'=>'25','sex'=>'age',]; Redis::set("user:1",json_encode($userInfo)); dd(json_decode(Redis::get("user:1"))); 第一種方式將用戶ID作為查找key,把其他信息封裝成一個對象以序列化的方式存儲,這種方式的缺點是,增加了序列化/反序列化的開銷,并且在需要修改其中一項信息時,需要把整個對象取回,并且修改操作需要對并發進行保護,引入CAS等復雜問題。 <h5>存儲信息2</h5> 第二種方法是這個用戶信息對象有多少成員就存成多少個key-value對兒,用用戶ID+對應屬性的名稱作為唯一標識來取得對應屬性的值,雖然省去了序列化開銷和并發問題,但是用戶ID為重復存儲,如果存在大量這樣的數據,內存浪費還是非常可觀的 ![請輸入圖片描述][2] $shopConfing =[ 's:1:mset'=>1, //是否開啟會員體系 's:1:svset'=>1, //是否開啟短視頻功能 's:1:lset'=>1, //是否開始直播功能 ]; Redis::mset($shopConfing); dd(Redis::keys("shop:1:*")); <h5>計數器</h5> Redis string提供的incr 跟 decr 方法也可以實現簡單的計數器功能。 Redis::set("v:z:1",1); //設置點贊 //增加點贊數 Redis::incr("v:z:1",1); //得到點贊數 dd(Redis::get("v:z:1")); > 其他計數器,統計數類似場景:微博的評論數、點贊數、分享數,抖音作品的收藏數,京東商品的銷售量、評價數等 <h5>短信驗證碼小例子</h5> //發送短信證碼 $code=rand(1000,9999); // 發送短信處理 /** send message **/ //存儲驗證碼 Redis::setex("code:17600128033","120",$code); // 接收驗證碼 $inCode="7580"; $mobileNumber="17600128033"; if($inCode == Redis::get("code:".$mobileNumber)){ dd ("驗證碼正確"); }else{ dd ("驗證碼錯誤,驗證碼為:".Redis::get("code:".$mobileNumber)); } ## Hash ## Redis hash 是一個 string 類型的 field(字段) 和 value(值) 的映射表,hash 特別適合用于存儲對象。 常用命令:hget,hset,hgetall 等。 <h5>存儲信息3</h5> 除了上述string 存儲信息的方式外,我們還可以用Hash類型來存儲。 Redis的Hash實際是內部存儲的Value為一個HashMap,并提供了直接存取這個Map成員的接口,使得Hash既沒有序列化開銷和并發問題,用戶ID也不會重復存儲,非常適合存儲對象。 ![請輸入圖片描述][3] Redis::hset('user:1','name','zhangsan'); Redis::hset('user:1','sex','男'); Redis::hset('user:1','age','20'); dd(Redis::hgetall('user:1')); <h5>注意點</h5> 這里同時需要注意,Redis提供了接口(hgetall)可以直接取到全部的屬性數據,但是如果內部Map的成員很多,那么涉及到遍歷整個內部Map的操作,由于Redis單線程模型的緣故,這個遍歷操作可能會比較耗時,而另其它客戶端的請求完全不響應,這點需要格外注意。 使用場景:存儲部分變更數據,如用戶信息等。 實現方式: 上面已經說到Redis Hash對應Value內部實際就是一個HashMap,實際這里會有2種不同實現,這個Hash的成員比較少時Redis為了節省內存會采用類似一維數組的方式來緊湊存儲,而不會采用真正的HashMap結構,對應的value redisObject的encoding為zipmap,當成員數量增大時會自動轉成真正的HashMap,此時encoding為ht。 <h5>計數、統計</h5> 同時Hash類型靈活的結構也適合給某一類事物進行各種維度的計數。 例如:電商類:商品維度有各種計數(點贊數,評論數,瀏覽數) 例如:直播類:主播維度有各種計數(動態數、關注數、粉絲數) Redis::hset('video:1','likes',1); //視頻點贊數 Redis::hset('video:1','collections',1); //視頻收藏 //增加視頻、點贊 Redis::hIncrBy('video:1','likes',1); Redis::hIncrBy('video:1','collections',1); //減少點贊數 Redis::hIncrBy('video:1','likes',-1); //獲取點贊數 Redis::hget('video:1','goods:4'); <h5>簡單購物車</h5> 簡單的購物車功能就可以使用Hash結構快速實現。以用戶id為key,商品id為field,商品數量為value,恰好構成了購物車的3個要素,如下圖所示。 ![請輸入圖片描述][4] Redis::hset('card:user:1','goods:1','1'); //用戶1 增加1個商品1到購物車 Redis::hset('card:user:1','goods:2','2'); //用戶2 增加2個商品2到購物車 Redis::hset('card:user:2','goods:1','2'); //用戶2 增加2個商品1到購物車 //添加商品購物車 Redis::hset('card:user:1','goods:4','2'); //獲取購物車內容 Redis::hgetall('card:user:1'); //增加數量 Redis::hIncrBy('card:user:1','goods:4','2'); //減少數量 Redis::hIncrBy('card:user:1','goods:4','-2'); //刪除一個商品 Redis::hdel('card:user:1','goods:4'); //清空購物車 Redis::del('card:user:1'); <h5>hash 和 string的選擇</h5> string 和 hash 兩種類型都可以用作對象存儲。以下的思路可以供大家參考。 當一個對象的屬性相對整體而且而且不易變化時,比較適合用string存儲 比如: 用戶:姓名、年齡、地址、愛好、民族、已婚等等 主播:房間號、姓名、年齡、直播領域 ---------- 當對象的某個屬性需要頻繁修改,且屬性比較零散時,比較適合用hash存儲 比如: 用戶:喜歡的視頻數、喜歡的商品數、點贊數 主播:粉絲數、訂閱數 ## List ## <h5>介紹</h5> 常用命令:lpush,rpush,lpop,rpop,lrange等。 應用場景: Redis list的應用場景非常多,也是Redis最重要的數據結構之一,比如twitter的關注列表,粉絲列表等都可以用Redis的list結構來實現。 List 就是鏈表,相信略有數據結構知識的人都應該能理解其結構。使用List結構,我們可以輕松地實現最新消息排行等功能。List的另一個應用就是消息隊列, 可以利用List的PUSH操作,將任務存在List中,然后工作線程再用POP操作將任務取出進行執行。Redis還提供了操作List中某一段的api,你可以直接查詢,刪除List中某一段的元素。 實現方式: Redis list的實現為一個雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷,Redis內部的很多實現,包括發送緩沖隊列等也都是用的這個數據結構。 Redis的list是每個子元素都是String類型的雙向鏈表,可以通過push和pop操作從列表的頭部或者尾部添加或者刪除元素,這樣List即可以作為棧,也可以作為隊列。 <h5>消息隊列系統</h5> 使用list可以構建隊列系統,使用sorted set甚至可以構建有優先級的隊列系統。 比如:將Redis用作日志收集器 實際上還是一個隊列,多個端點將日志信息寫入Redis,然后一個worker統一將所有日志寫到磁盤。 取最新N個數據的操作 記錄前N個最新登陸的用戶Id列表,超出的范圍可以從數據庫中獲得。 //把當前登錄人添加到鏈表里 for ($a=1;$a<20;$a++){ $ret = Redis::lpush("l:uid", $a); //login:user_id } //保持鏈表只有10位 $ret = Redis::ltrim("l:uid", 0, (10-1)); //獲得前10個最新登陸的用戶Id列表 dd(Redis::lrange("l:uid", 0, (10-1))); 結果: array:10 [▼ 0 => "19" 1 => "18" 2 => "17" 3 => "16" 4 => "15" 5 => "14" 6 => "13" 7 => "12" 8 => "11" 9 => "10" ] <h5>sina微博熱數據:</h5> 在Redis中我們的最新微博ID使用了常駐緩存,這是一直更新的。但是我們做了限制不能超過5000個ID,因此我們的獲取ID函數會一直詢問Redis。只有在start/count參數超出了這個范圍的時候,才需要去訪問數據庫。 我們的系統不會像傳統方式那樣“刷新”緩存,Redis實例中的信息永遠是一致的。SQL數據庫(或是硬盤上的其他類型數據庫)只是在用戶需要獲取“很遠”的數據時才會被觸發,而主頁或第一個評論頁是不會麻煩到硬盤上的數據庫了。 <h5>秒殺場景的簡單實現</h5> 隊列的特性在日常開發中還可以用于流量削鋒跟解耦。這里做流量削鋒的秒殺搶購場景的簡單示例。 //監聽已搶購的數量 Redis::watch("sk:1:num"); //已經秒殺完的商品數量 $skNum = Redis::hget("sk:h:1",'gum'); //秒殺商品Hash信息 $isSkNum = (int)Redis::get("sk:1:num"); if($isSkNum < $skNum ){ $uid = $this->rand(5);//隨機生成用戶id // 暫時用setnx 跟 expire 處理限購 問題是并發情況下會不止10個人進來,但是不影響限購啊 // 沒有考慮到更好的解決方案,先這么處理吧 // Redis::set("sk:su:1", 1 , 'NX', 'EX', "1000"); 不清楚predis下set 同時設置 NX和EX為什么老是不生效,暫時用下邊的方法處理 if(Redis::setnx("sk:su:".$uid,$uid)){ Redis::expire("sk:su:".$uid,10); //設置過期時間,保證10秒內一個用戶只能秒殺成功一次 }else{ Rddis::incr('fail'); echo "10秒內允許搶購一次。"; } //上述代碼不能放在multi之內。 否則if(Redis::setnx("sk:su:".$uid,$uid)) 會報錯 //放在multi當中,相當于未執行,結果不會返回,所以會一直報錯 Redis::multi(); Redis::incr('sk:1:num'); Redis::lpush("sk:l:1",$uid); Redis::exec(); }else{ Redis::incr('fail'); echo "不好意思,秒殺已經結束了。"; } ---------- ab 1000請求 100并發的請求結果: 127.0.0.1:6379> get sk:1:num "10" 127.0.0.1:6379> lrange sk:l:1 0 -1 1) "t106A0502910239" 2) "160A50HR21k23R9" 3) "160i7O502f12Y39" 4) "160j5021W23UzZ9" 5) "Wd160c5i0212539" 6) "1Pw60I502Ae1239" 7) "146050RgG213239" 8) "1605p0aL212p3u9" 9) "16050wyAa2123Y9" 10) "16050fi2012f3j9" <h5>熱點數據更新</h5> 場景描述:后臺在更新咨詢。前臺用戶在觀看數據。 比如說數據A B C D E F G,一次取兩條數據的, 用戶的進來是A B兩條數據,此時后臺運營人員在后臺插入H F兩條數據,此時鏈表變成了H F A B C D E F G,此時用戶往上滑如何保證是C D 記錄用戶后一個值,傳到后臺,不能下標后移處理。 ## 結尾 ## <p style="background-image: -webkit-linear-gradient(left, #3498db, #f47920 10%, #d71345 20%, #f7acbc 30%,#ffd400 40%, #3498db 50%, #f47920 60%, #d71345 70%, #f7acbc 80%, #ffd400 90%, #3498db);color: transparent;-webkit-text-fill-color: transparent;-webkit-background-clip: text;text-align:center;"> 腹有詩書氣自華,最是書香能致遠。 </p> [1]: https://blog.zxliu.cn/usr/uploads/2020/11/217422969.png [2]: https://blog.zxliu.cn/usr/uploads/2020/11/1945224260.png [3]: https://blog.zxliu.cn/usr/uploads/2020/11/1321091741.png [4]: https://blog.zxliu.cn/usr/uploads/2020/11/2167948208.png
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看