<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      面試必會->Redis篇

      01- 你們項目中哪里用到了Redis ?

      在我們的項目中很多地方都用到了Redis , Redis在我們的項目中主要有三個作用 :

      1. 使用Redis做熱點(diǎn)數(shù)據(jù)緩存/接口數(shù)據(jù)緩存
      2. 使用Redis存儲一些業(yè)務(wù)數(shù)據(jù) , 例如 : 驗證碼 , 用戶信息 , 用戶行為數(shù)據(jù) , 數(shù)據(jù)計算結(jié)果 , 排行榜數(shù)據(jù)等
      3. 使用Redis實(shí)現(xiàn)分布式鎖 , 解決并發(fā)環(huán)境下的資源競爭問題

      02- Redis的常用數(shù)據(jù)類型有哪些 ?

      Redis 有 5 種基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),它們分別是:string(字符串)、list(列表)、hash(字典)、set(集 合) 和 zset(有序集合)

      03- Redis的數(shù)據(jù)持久化策略有哪些 ?

      Redis 提供了兩種方式,實(shí)現(xiàn)數(shù)據(jù)的持久化到硬盤。

      1. RDB 持久化(全量),是指在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤。
      2. AOF持久化(增量),以日志的形式記錄服務(wù)器所處理的每一個寫、刪除操作

      RDB和AOF一起使用, 在Redis4.0版本支持混合持久化方式 ( 設(shè)置 aof-use-rdb-preamble yes )

      04- Redis的數(shù)據(jù)過期策略有哪些 ?

      1. 惰性刪除 :只會在取出 key 的時候才對數(shù)據(jù)進(jìn)行過期檢查。這樣對 CPU 最友好,但是可能會造成太多過期 key 沒有被刪除。

        數(shù)據(jù)到達(dá)過期時間,不做處理。等下次訪問該數(shù)據(jù)時,我們需要判斷

        1. 如果未過期,返回數(shù)據(jù)
        2. 發(fā)現(xiàn)已過期,刪除,返回nil
      2. 定期刪除 : 每隔一段時間抽取一批 key 執(zhí)行刪除過期 key 操作。并且,Redis 底層會通過限制刪除操作執(zhí)行的時長和頻率來減少刪除操作對 CPU 時間的影響。

        默認(rèn)情況下 Redis 定期檢查的頻率是每秒掃描 10 次,用于定期清除過期鍵。當(dāng)然此值還可以通過配置文件進(jìn)行設(shè)置,在 redis.conf 中修改配置“hz”即可,默認(rèn)的值為hz 10

        定期刪除的掃描并不是遍歷所有的鍵值對,這樣的話比較費(fèi)時且太消耗系統(tǒng)資源。Redis 服務(wù)器采用的是隨機(jī)抽取形式,每次從過期字典中,取出 20 個鍵進(jìn)行過期檢測,過期字典中存儲的是所有設(shè)置了過期時間的鍵值對。如果這批隨機(jī)檢查的數(shù)據(jù)中有 25% 的比例過期,那么會再抽取 20 個隨機(jī)鍵值進(jìn)行檢測和刪除,并且會循環(huán)執(zhí)行這個流程,直到抽取的這批數(shù)據(jù)中過期鍵值小于 25%,此次檢測才算完成

        Redis 服務(wù)器為了保證過期刪除策略不會導(dǎo)致線程卡死,會給過期掃描增加了最大執(zhí)行時間為 25ms

      定期刪除對內(nèi)存更加友好,惰性刪除對 CPU 更加友好。兩者各有千秋,所以 Redis 采用的是 定期刪除+惰性刪除

      05- Redis的數(shù)據(jù)淘汰策略有哪些 ?

      Redis 提供 8 種數(shù)據(jù)淘汰策略:

      淘汰易失數(shù)據(jù)(具有過期時間的數(shù)據(jù))

      1. volatile-lru(least recently used):從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
      2. volatile-lfu(least frequently used):從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰
      3. volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰
      4. volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰

      淘汰全庫數(shù)據(jù)

      1. allkeys-lru(least recently used):當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最近最少使用的 key(這個是最常用的)
      2. allkeys-lfu(least frequently used):當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,在鍵空間中,移除最不經(jīng)常使用的 key
      3. allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰

      不淘汰

      1. no-eviction:禁止驅(qū)逐數(shù)據(jù),也就是說當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時,新寫入操作會報錯。這個應(yīng)該沒人使用吧!

      06- 你們使用Redis是單點(diǎn)還是集群 ? 哪種集群 ?

      我們Redis使用的是哨兵集群 , 一主二從 , 三個哨兵 , 三臺Linux機(jī)器

      07- Redis集群有哪些方案, 知道嘛 ?

      我所了解的Redis集群方案

      1. 主從復(fù)制集群 : 讀寫分離, 一主多從 , 解決高并發(fā)讀的問題
      2. 哨兵集群 : 主從集群的結(jié)構(gòu)之上 , 加入了哨兵用于監(jiān)控集群狀態(tài) , 主節(jié)點(diǎn)出現(xiàn)故障, 執(zhí)行主從切換 , 解決高可用問題
      3. Cluster分片集群 : 多主多從 , 解決高并發(fā)寫的問題, 以及海量數(shù)據(jù)存儲問題 , 每個主節(jié)點(diǎn)存儲一部分集群數(shù)據(jù)

      08- 什么是 Redis 主從同步?

      Redis 的主從同步(replication)機(jī)制,允許 Slave 從 Master 那里,通過網(wǎng)絡(luò)傳輸拷貝到完整的數(shù)據(jù)備份,從而達(dá)到主從機(jī)制。

      主數(shù)據(jù)庫可以進(jìn)行讀寫操作,當(dāng)發(fā)生寫操作的時候自動將數(shù)據(jù)同步到從數(shù)據(jù)庫,而從數(shù)據(jù)庫一般是只讀的,并接收主數(shù)據(jù)庫同步過來的數(shù)據(jù)。一個主數(shù)據(jù)庫可以有多個從數(shù)據(jù)庫,而一個從數(shù)據(jù)庫只能有一個主數(shù)據(jù)庫。


      image


      主從數(shù)據(jù)同步主要分二個階段 :

      第一階段 : 全量復(fù)制階段

      • slave節(jié)點(diǎn)請求增量同步
      • master節(jié)點(diǎn)判斷replid,發(fā)現(xiàn)不一致,拒絕增量同步
      • master將完整內(nèi)存數(shù)據(jù)生成RDB,發(fā)送RDB到slave
      • slave清空本地數(shù)據(jù),加載master的RDB

      第二階段 : 增量復(fù)制階段

      • master將RDB期間的命令記錄在repl_baklog,并持續(xù)將log中的命令發(fā)送給slave
      • slave執(zhí)行接收到的命令,保持與master之間的同步

      09- Redis分片集群中數(shù)據(jù)是怎么存儲和讀取的 ?

      Redis集群采用的算法是哈希槽分區(qū)算法。Redis集群中有16384個哈希槽(槽的范圍是 0 -16383,哈希槽),將不同的哈希槽分布在不同的Redis節(jié)點(diǎn)上面進(jìn)行管理,也就是說每個Redis節(jié)點(diǎn)只負(fù)責(zé)一部分的哈希槽。在對數(shù)據(jù)進(jìn)行操作的時候,集群會對使用CRC16算法對key進(jìn)行計算并對16384取模(slot = CRC16(key)%16383),得到的結(jié)果就是 Key-Value 所放入的槽,通過這個值,去找到對應(yīng)的槽所對應(yīng)的Redis節(jié)點(diǎn),然后直接到這個對應(yīng)的節(jié)點(diǎn)上進(jìn)行存取操作

      10- 你們用過Redis的事務(wù)嗎 ? 事務(wù)的命令有哪些 ?

      Redis 作為 NoSQL 數(shù)據(jù)庫也同樣提供了事務(wù)機(jī)制。在 Redis 中,MULTI / EXEC / DISCARD / WATCH 這四個命令事務(wù)的相關(guān)操作命令

      我們在開發(fā)過程中基本上沒有用到過Redis的事務(wù)

      11- Redis 和 Memcached 的區(qū)別有哪些?

      1. Redis 提供復(fù)雜的數(shù)據(jù)結(jié)構(gòu),豐富的數(shù)據(jù)操作 , Memcached 僅提供簡單的字符串。
      2. Redis原生支持集群模式 , Memcached不支持原生集群
      3. Memcached 不支持持久化存儲,重啟時,數(shù)據(jù)被清空, Redis 支持持久化存儲,重啟時,可以恢復(fù)已持久化的數(shù)據(jù)

      12- Redis的內(nèi)存用完了會發(fā)生什么?

      如果達(dá)到設(shè)置的上限,Redis 的寫命令會返回錯誤信息( 但是讀命令還可以正常返回。)
      也可以配置內(nèi)存淘汰機(jī)制, 當(dāng) Redis 達(dá)到內(nèi)存上限時會沖刷掉舊的內(nèi)容。

      13- Redis和Mysql如何保證數(shù)據(jù)?致?

      1. 先更新Mysql,再更新Redis,如果更新Redis失敗,可能仍然不?致

      2. 先刪除Redis緩存數(shù)據(jù),再更新Mysql,再次查詢的時候在將數(shù)據(jù)添加到緩存中

      這種?案能解決1 ?案的問題,但是在?并發(fā)下性能較低,?且仍然會出現(xiàn)數(shù)據(jù)不?致的問題,
      ?如線程1刪除了 Redis緩存數(shù)據(jù),正在更新Mysql,
      此時另外?個查詢再查詢,那么就會把Mysql中?數(shù)據(jù)?查到 Redis中

      1. 使用MQ異步同步, 保證數(shù)據(jù)的最終一致性

      我們項目中會根據(jù)業(yè)務(wù)情況 , 使用不同的方案來解決Redis和Mysql的一致性問題 :

      1. 對于一些一致性要求不高的場景 , 不做處理

        例如 : 用戶行為數(shù)據(jù) , 我們沒有做一致性保證 , 因為就算不一致產(chǎn)生的影響也很小

      2. 對于時效性數(shù)據(jù) , 設(shè)置過期時間

        例如 : 接口緩存數(shù)據(jù) , 我們會設(shè)置緩存的過期時間為 60S , 那么可能會出現(xiàn)60S之內(nèi)的數(shù)據(jù)不一致, 60S后緩存過期, 重新從數(shù)據(jù)庫加載就一致了

      3. 對于一致性要求比較高但是時效性要求不那么高的場景 , 使用MQ不斷發(fā)送消息完成數(shù)據(jù)同步直到成功為止

        例如 : 首頁廣告數(shù)據(jù) , 首頁推薦數(shù)據(jù)

        數(shù)據(jù)庫數(shù)據(jù)發(fā)生修改----> 發(fā)送消息到MQ -----> 接收消息更新緩存

        消息不丟失/重復(fù)消費(fèi) : 消息狀態(tài)表/消息消費(fèi)表

      4. 對于一致性和時效性要求都比較高的場景 , 使用分布式事務(wù) , Seata的TCC模式

        很少用

      14- 什么是緩存穿透 ? 怎么解決 ?

      緩存穿透是指查詢一條數(shù)據(jù)庫和緩存都沒有的一條數(shù)據(jù),就會一直查詢數(shù)據(jù)庫,對數(shù)據(jù)庫的訪問壓力就會增大,緩存穿透的解決方案

      有以下2種解決方案 :

      • 緩存空對象:代碼維護(hù)較簡單,但是效果不好。
      • 布隆過濾器:代碼維護(hù)復(fù)雜,效果很好

      15- 什么是緩存擊穿 ? 怎么解決 ?

      緩存擊穿是指緩存中沒有但數(shù)據(jù)庫中有的數(shù)據(jù)(一般是緩存時間到期),這時由于并發(fā)用戶特別多,同時讀緩存沒讀到數(shù)據(jù),又同時去數(shù)據(jù)庫去取數(shù)據(jù),引起數(shù)據(jù)庫壓力瞬間增大

      解決方案 :

      • 熱點(diǎn)數(shù)據(jù)提前預(yù)熱
      • 設(shè)置熱點(diǎn)數(shù)據(jù)永遠(yuǎn)不過期。
      • 加鎖 , 限流

      16- 什么是緩存雪崩 ? 怎么解決 ?

      緩存雪崩/緩存失效 指的是大量的緩存在同一時間失效,大量請求落到數(shù)據(jù)庫 導(dǎo)致數(shù)據(jù)庫瞬間壓力飆升。

      造成這種現(xiàn)象的 原因是,key的過期時間都設(shè)置成一樣了。

      解決方案是,key的過期時間引入隨機(jī)因素

      17- 數(shù)據(jù)庫有1000萬數(shù)據(jù) ,Redis只能緩存20w數(shù)據(jù), 如何保證Redis中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù) ?

      配置Redis的內(nèi)容淘汰策略為LFU算法 , 這樣會把使用頻率較低的數(shù)據(jù)淘汰掉 , 留下的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)

      18- Redis分布式鎖如何實(shí)現(xiàn) ?

      Redis分布式鎖主要依靠一個SETNX指令實(shí)現(xiàn)的 , 這條命令的含義就是“SET if Not Exists”,即不存在的時候才會設(shè)置值。

      只有在key不存在的情況下,將鍵key的值設(shè)置為value。如果key已經(jīng)存在,則SETNX命令不做任何操作。

      這個命令的返回值如下。

      • 命令在設(shè)置成功時返回1。
      • 命令在設(shè)置失敗時返回0。

      假設(shè)此時有線程A和線程B同時訪問臨界區(qū)代碼,假設(shè)線程A首先執(zhí)行了SETNX命令,并返回結(jié)果1,繼續(xù)向下執(zhí)行。而此時線程B再次執(zhí)行SETNX命令時,返回的結(jié)果為0,則線程B不能繼續(xù)向下執(zhí)行。只有當(dāng)線程A執(zhí)行DELETE命令將設(shè)置的鎖狀態(tài)刪除時,線程B才會成功執(zhí)行SETNX命令設(shè)置加鎖狀態(tài)后繼續(xù)向下執(zhí)行

      Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(PRODUCT_ID, "binghe");
      

      當(dāng)然我們在使用分布式鎖的時候也不能這么簡單, 會考慮到一些實(shí)際場景下的問題 , 例如 :

      1. 死鎖問題

        在使用分布式鎖的時候, 如果因為一些原因?qū)е孪到y(tǒng)宕機(jī), 鎖資源沒有被釋放, 就會產(chǎn)生死鎖

        解決的方案 : 上鎖的時候設(shè)置鎖的超時時間

        Boolean isLocked = stringRedisTemplate.opsForValue().setIfAbsent(PRODUCT_ID, "binghe", 30, TimeUnit.SECONDS);
        
      2. 鎖超時問題

        如果業(yè)務(wù)執(zhí)行需要的時間, 超過的鎖的超時時間 , 這個時候業(yè)務(wù)還沒有執(zhí)行完成, 鎖就已經(jīng)自動被刪除了

        其他請求就能獲取鎖, 操作這個資源 , 這個時候就會出現(xiàn)并發(fā)問題 , 解決的方案 :

        1. 引入Redis的watch dog機(jī)制, 自動為鎖續(xù)期
        2. 開啟子線程 , 每隔20S運(yùn)行一次, 重新設(shè)置鎖的超時時間
      3. 歸一問題

        如果一個線程獲取了分布式鎖, 但是這個線程業(yè)務(wù)沒有執(zhí)行完成之前 , 鎖被其他的線程刪掉了 , 又會出現(xiàn)線程并發(fā)問題 , 這個時候就需要考慮歸一化問題

        就是一個線程執(zhí)行了加鎖操作后,后續(xù)必須由這個線程執(zhí)行解鎖操作,加鎖和解鎖操作由同一個線程來完成。

        為了解決只有加鎖的線程才能進(jìn)行相應(yīng)的解鎖操作的問題,那么,我們就需要將加鎖和解鎖操作綁定到同一個線程中,可以使用ThreadLocal來解決這個問題 , 加鎖的時候生成唯一標(biāo)識保存到ThreadLocal , 并且設(shè)置到鎖的值中 , 釋放鎖的時候, 判斷線程中的唯一標(biāo)識和鎖的唯一標(biāo)識是否相同, 只有相同才會釋放
        """

        public class RedisLockImpl implements RedisLock{
            @Autowired
            private StringRedisTemplate stringRedisTemplate;
        
            private ThreadLocal<String> threadLocal = new ThreadLocal<String>();
        
            @Override
            public boolean tryLock(String key, long timeout, TimeUnit unit){
         	 String uuid = UUID.randomUUID().toString();
         	 threadLocal.set(uuid);
         	 return stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, timeout, unit);
          }
            @Override
            public void releaseLock(String key){
         	 //當(dāng)前線程中綁定的uuid與Redis中的uuid相同時,再執(zhí)行刪除鎖的操作
         	 if(threadLocal.get().equals(stringRedisTemplate.opsForValue().get(key))){
         	   stringRedisTemplate.delete(key);   
             }
           }
         }
        

        """


      4、可重入問題

      當(dāng)一個線程成功設(shè)置了鎖標(biāo)志位后,其他的線程再設(shè)置鎖標(biāo)志位時,就會返回失敗。

      還有一種場景就是在一個業(yè)務(wù)中, 有個操作都需要獲取到鎖, 這個時候第二個操作就無法獲取鎖了 , 操作會失敗

      例如 : 下單業(yè)務(wù)中, 扣減商品庫存會給商品加鎖, 增加商品銷量也需要給商品加鎖 , 這個時候需要獲取二次鎖

      第二次獲取商品鎖就會失敗 , 這就需要我們的分布式鎖能夠?qū)崿F(xiàn)可重入

      實(shí)現(xiàn)可重入鎖最簡單的方式就是使用計數(shù)器 , 加鎖成功之后計數(shù)器 + 1 , 取消鎖之后計數(shù)器 -1 , 計數(shù)器減為0 , 真正從Redis刪除鎖

      """

      public class RedisLockImpl implements RedisLock{
       @Autowired
       private StringRedisTemplate stringRedisTemplate;
      
       private ThreadLocal<String> threadLocal = new ThreadLocal<String>();
      
       private ThreadLocal<Integer> threadLocalInteger = new ThreadLocal<Integer>();
      
       @Override
       public boolean tryLock(String key, long timeout, TimeUnit unit){
      	 Boolean isLocked = false;
      	 if(threadLocal.get() == null){
      		 String uuid = UUID.randomUUID().toString();
      	  threadLocal.set(uuid);
      		 isLocked = stringRedisTemplate.opsForValue().setIfAbsent(key, uuid, timeout, unit);
      	 }else{
      		 isLocked = true;   
      	 }
      	 //加鎖成功后將計數(shù)器加1
      	 if(isLocked){
      		 Integer count = threadLocalInteger.get() == null ? 0 : threadLocalInteger.get();
      		 threadLocalInteger.set(count++);
      	 }
      	 return isLocked;
       }
      
       @Override
       public void releaseLock(String key){
      	 //當(dāng)前線程中綁定的uuid與Redis中的uuid相同時,再執(zhí)行刪除鎖的操作
      	 if(threadLocal.get().equals(stringRedisTemplate.opsForValue().get(key))){
      		 Integer count = threadLocalInteger.get();
      		 //計數(shù)器減為0時釋放鎖
      		 if(count == null || --count <= 0){
      		   stringRedisTemplate.delete(key);      
      		 }
      	 }
       }
      }
      

      """


      5、阻塞與非阻塞問題

      在使用分布式鎖的時候 , 如果當(dāng)前需要操作的資源已經(jīng)加了鎖, 這個時候會獲取鎖失敗, 直接向用戶返回失敗信息 , 用戶的體驗非常不好 , 所以我們在實(shí)現(xiàn)分布式鎖的時候, 我們可以將后續(xù)的請求進(jìn)行阻塞,直到當(dāng)前請求釋放鎖后,再喚醒阻塞的請求獲得分布式鎖來執(zhí)行方法。

      具體的實(shí)現(xiàn)就是參考自旋鎖的思想, 獲取鎖失敗自選獲取鎖, 直到成功為止 , 當(dāng)然為了防止多條線程自旋帶來的系統(tǒng)資料消耗, 可以設(shè)置一個自旋的超時時間 , 超過時間之后, 自動終止線程 , 返回失敗信息


      image


      19- 你的項目中哪里用到了分布式鎖

      在我最近做的一個項目中 , 我們在任務(wù)調(diào)度的時候使用了分布式鎖

      早期我們在進(jìn)行定時任務(wù)的時候我們采用的是SpringTask實(shí)現(xiàn)的 , 在集群部署的情況下, 多個節(jié)點(diǎn)的定時任務(wù)會同時執(zhí)行 , 造成重復(fù)調(diào)度 , 影響運(yùn)算結(jié)果, 浪費(fèi)系統(tǒng)資源

      這里為了防止這種情況的發(fā)送, 我們使用Redis實(shí)現(xiàn)分布式鎖對任務(wù)進(jìn)行調(diào)度管理 , 防止重復(fù)任務(wù)執(zhí)行

      后期因為我們系統(tǒng)中的任務(wù)越來越多 , 執(zhí)行規(guī)則也比較多 , 而且單節(jié)點(diǎn)執(zhí)行效率有一定的限制 , 所以定時任務(wù)就切換成了XXL-JOB , 系統(tǒng)中就沒有再使用分布式鎖了

      posted @ 2024-06-03 22:02  二價亞鐵  閱讀(177)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 又大又紧又粉嫩18p少妇| 老太脱裤子让老头玩xxxxx| 永久免费无码国产| 国产成人午夜福利在线播放| 国产一区二区不卡精品视频| 老少配老妇老熟女中文普通话 | 久久香蕉国产线熟妇人妻| 亚洲第一福利网站在线观看| 国产福利片无码区在线观看| 99精品人妻少妇一区二区| 安西县| 少妇高潮流白浆在线观看| 精品日本乱一区二区三区| 在线看国产精品自拍内射| 午夜视频免费试看| 国产精品男女爽免费视频| 国语精品一区二区三区| 国产高清自产拍av在线| 国产精品久久久久久久久鸭| 欧美激情一区二区三区成人| 国产成人无码一区二区三区在线 | 一区二区不卡99精品日韩| 国产成人午夜在线视频极速观看| 一本色道婷婷久久欧美| 精品午夜福利无人区乱码| 国产亚洲精品久久yy50| 怡红院一区二区三区在线| 国产福利永久在线视频无毒不卡| 国产精品久久久久久久专区| 欧美激情一区二区三区成人| 免费无码高H视频在线观看| 精品国产午夜福利在线观看| 中文字幕av一区二区| 伊人久久大香线蕉网av| 成年女人片免费视频播放A| 欧美变态口味重另类在线视频| 18禁极品一区二区三区| 视频一区视频二区制服丝袜| 国产人与禽zoz0性伦多活几年| 伦理片午夜视频在线观看| 国产草草影院ccyycom|