囉裏吧嗦redis

1.redis是什麼
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.
It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.
Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster
Redis是一個開源(BSD許可),內存數據結構存儲,用做數據庫,緩存和消息代理
它支持的數據結構有字符串、哈希表散列(鍵值對)、列表、集合、可隨機查詢的有序集合、bitmaps位圖、hyperloglogs
基數統計、用於半徑查詢的地理位置索引
Redis已經內置功能有主從複製,LUA腳本,最近最少使用算法失效,事物、各類級別硬盤持久化,Redis哨兵保證可用性、Redis集羣自動分片.....
 
簡單來講咱們把redis看成一個高性能的key-value數據庫來使用
 
2.redis的下載安裝配置
  • linux的直接去官網下載就好了,下面都有介紹,經過make命令進行安裝,看不懂英語的百度下如何使用chrome自帶的翻譯插件
windows的比較麻煩,還得去github上下載,訪問比較卡的能夠參考我以前的一篇文章,直接設置hosts, 跳過DNS解析的過程
  • 下載完畢後解壓,隨便找個redis版本,好比redis-windows-master\redis-windows-master\downloads\redis64-3.0.501.zip解壓後放到本身合適的目錄下, 例E:\redis64-3.0.501
  • 在解壓目錄下,按住shift , 鼠標右擊, 選中在此處打開命令窗口, 輸入命令
redis-server.exe redis.windows.conf
若是不想每次都手寫命令,能夠寫個腳本
目錄結構
E:\redis\redis64-3.0.501-6379
在此目錄下 新建一個txt 

@echo off
redis-server.exe redis.windows.conf
@pause

重命名爲startRedisServer.bat
bat結尾的是windows可識別的批處理程序  能夠直接執行命令窗口的命令
@echo off DOS批處理中的,
不想顯示器顯示 dos批處理中 的 每條命令 ,  加 echo off 
「echo off」也是命令,它自己也會顯示,若是連這條也不顯示,就在前面加個「@」。

@自己就是一條指令,意思是跟在它後面的指令的執行及結果都不會在DOS界面上顯示出來

pause暫停命令
運行該命令時,將顯示消息:請按任意鍵繼續 . . .,通常用於看清楚屏幕上顯示的內容

而後新建一個txt,在E:\redis目錄下
@echo off
cd redis64-3.0.501-6379
startRedisServer.bat

重命名爲start6379.cmd


cmd開啓客戶端
@echo off
cd redis64-3.0.501-6379
redis-cli
@pause

 

 
 
添加描述
出現此畫面表明redis運行成功了,在此目錄下接着打開一個命令行
輸入以下命令 >redis-cli > set age 32 ok > get age "32"
注1:若是不想每次都進入目錄下執行命令,可參考前面的zookeeper,在 系統path下配置環境變量,
這樣就能在任意目錄下經過redis-cli訪問redis了(猜想window系統會根據命令行的命令先去 --系統path路徑下找--可執行的文件)
注2:若是不想關閉cmd窗口就終止redis服務,可把redis設置成windows下的服務
設置服務命令

redis-server --service-install redis.windows-service.conf --loglevel verbose


卸載服務:redis-server --service-uninstall

開啓服務:redis-server --service-start

中止服務:redis-server --service-stop

 

經過右擊計算機---計算機管理--服務和應用程序--服務可查看多出了一個redis服務
注3:E:\redis64-3.0.501\redis.windows-service.conf
Redis安裝的服務默認加載的是該文件,自定義配置信息
 
附:redis解壓包和 可視化界面客戶端
redis客戶端工具你們找找吧,超過10M我就不上傳了
 
添加描述
 
 
3.redis實戰,spring和redis的結合
項目中如何使用redis呢,思路3部曲,先導包,再配置,最後測試
我自建的項目都是maven方式管理jar包
首先在pom.xml文件添加依賴,由於我用的spring框架,因此導了一個spring-data-redis,jackson包是爲了能保持對象


<dependencies>

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.7.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.6.2.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.1.0</version>
        </dependency>

</dependencies>

 

在src/main/resources目錄下新建一個redis.properties文件裏面配置redis的信息
#訪問地址
redis.host=127.0.0.1
#訪問端口  
redis.port=6379  
#注意,若是沒有password,此處不設置值,但這一項要保留  
redis.password=  
  
#最大空閒數,數據庫鏈接的最大空閒時間。超過空閒時間,數據庫鏈接將被標記爲不可用,而後被釋放。設爲0表示無限制。  
redis.maxIdle=300  
#鏈接池的最大數據庫鏈接數。設爲0表示無限制  
redis.maxActive=600  
#最大創建鏈接等待時間。若是超過此時間將接到異常。設爲-1表示無限制。  
redis.maxWait=1000  
#在borrow一個jedis實例時,是否提早進行alidate操做;若是爲true,則獲得的jedis實例均是可用的;  
redis.testOnBorrow=true

 

在applicationContext.xml下配置好自動註解掃描,bean文件掃描
<!-- 掃描類包,將標註Spring註解的類自動轉化Bean,同時完成Bean的注入 --> <context:component-scan base-package="com.one.*" /> <!--寫本身的包的路徑 --> <!-- 加載bean配置 --> <import resource="classpath*:conf/beans-*.xml"/> <!-- 由於個人bean文件都是 conf目錄下的 名字以beans-開頭的 例如 beans-redis.xml -->
 
 
目錄結構
在beans-redis.xml文件裏配置bean信息
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
    
    
    <!--  若是在多個spring配置文件中引入<context:property-placeholder .../>標籤,
    最後須要加上ignore-unresolvable="true",不然會報錯。
    
    ignore-unresolvable="true" 
    在加載第一個property-placeholder時出現解析不了的佔位符進行忽略掉 -->
    <!-- 鏈接池基本參數配置,相似數據庫鏈接池 -->
    <context:property-placeholder location="classpath:redis.properties"
        ignore-unresolvable="true" />
    
    <!-- redis鏈接池 -->  
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxTotal" value="${redis.maxActive}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>

    <!-- 鏈接池配置,相似數據庫鏈接池 -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}"></property>
        <property name="port" value="${redis.port}"></property>
        <!-- <property name="password" value="${redis.pass}"></property> -->
        <property name="poolConfig" ref="poolConfig"></property>
    </bean>

    <!--redis操做模版,使用該對象能夠操做redis  -->  
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >    
        <property name="connectionFactory" ref="jedisConnectionFactory" />    
        <!--若是不配置Serializer,那麼存儲的時候缺省使用String,若是用User類型存儲,那麼會提示錯誤User can't cast to String!!  -->    
        <property name="keySerializer" >    
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />    
        </property>    
        <property name="valueSerializer" >    
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />    
        </property>    
        <property name="hashKeySerializer">    
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>    
        </property>    
        <property name="hashValueSerializer">    
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>    
        </property>    
        <!--開啓事務  -->  
        <property name="enableTransactionSupport" value="true"></property>  
    </bean >   


    <!-- 下面這個是整合Mybatis的二級緩存使用的 
    <bean id="redisCacheTransfer" class="cn.qlq.jedis.RedisCacheTransfer">
        <property name="jedisConnectionFactory" ref="jedisConnectionFactory" />
    </bean>-->

</beans>

 

最後編寫測試類開啓測試啦, 工具類網上找找, 下面的代碼注入RedisUtil報錯,涉及的先都去掉
package com.one.redis;

import java.io.InputStream;
import java.util.*;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import redis.clients.jedis.Jedis;

@RunWith(SpringJUnit4ClassRunner.class)
// @ContextConfiguration("classpath:applicationContext-*.xml")
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
// 加載配置文件
@SuppressWarnings("all")
public class RedisTest {

    // @Autowired
    // private RedisUtil redisUtil;

    // 1.導包
    // applicationContext.xml <import resource="classpath*:conf/beans-*.xml"/>
    // beans-redis.xml
    // <bean id="redisTemplate"
    // class="org.springframework.data.redis.core.RedisTemplate" >
    @Resource(name = "redisTemplate")
    private RedisTemplate redisTemplate;

    @Test
    public void testSpringRedis() {
        // stringRedisTemplate的操做
        // String讀寫
        redisTemplate.delete("myStr");
        redisTemplate.opsForValue().set("myStr", "skyLine");
        System.out.println(redisTemplate.opsForValue().get("myStr"));
        System.out.println("---------------");
        // org.springframework.data.redis.RedisConnectionFailureException:
        // Cannot get Jedis connection; nested exception is
        // redis.clients.jedis.exceptions.JedisConnectionException: Could not
        // get a resource from the pool

        // List讀寫
        redisTemplate.delete("myList");
        redisTemplate.opsForList().rightPush("myList", "T");
        redisTemplate.opsForList().rightPush("myList", "L");
        redisTemplate.opsForList().leftPush("myList", "A");
        List<String> listCache = redisTemplate.opsForList().range("myList", 0,
                -1);
        for (String s : listCache) {
            System.out.println(s);
        }
        System.out.println("---------------");

        // Set讀寫
        redisTemplate.delete("mySet");
        redisTemplate.opsForSet().add("mySet", "A");
        redisTemplate.opsForSet().add("mySet", "B");
        redisTemplate.opsForSet().add("mySet", "C");
        redisTemplate.opsForSet().add("mySet", "C");
        Set<String> setCache = redisTemplate.opsForSet().members("mySet");
        for (String s : setCache) {
            System.out.println(s);
        }
        System.out.println("---------------");// ABC

        // Hash讀寫
        redisTemplate.delete("myHash");
        redisTemplate.opsForHash().put("myHash", "BJ", "北京");
        redisTemplate.opsForHash().put("myHash", "SH", "上海");
        redisTemplate.opsForHash().put("myHash", "HN", "河南");
        Map<String, String> hashCache = redisTemplate.opsForHash().entries(
                "myHash");
        for (Map.Entry entry : hashCache.entrySet()) {
            System.out.println(entry.getKey() + " - " + entry.getValue());
        }
        System.out.println("---------------");

        // Redis Incrby 命令將 key 中儲存的數字加上指定的增量值,若是 key 不存在,那麼 key 的值會先被初始化爲 0
        // ,而後再執行 INCR 操做
        double stringValueDouble = redisTemplate.opsForValue().increment(
                "doubleValue", 5);
        System.out.println("經過increment(K key, double delta)方法以增量方式存儲double值:"
                + stringValueDouble);
        // incrBy:將 key 所儲存的值加上給定的增量值(increment) 。
        Jedis jedis = new Jedis("127.0.0.1", 6379);

        jedis.incrBy("key3", 5);
        String v3 = jedis.get("key3");
        System.out.println("結果:" + v3);

    }
    @Test
    public void delete() {

        redisTemplate.delete("myStr");
        redisTemplate.delete("mySet");
        redisTemplate.delete("myHash");
        redisTemplate.delete("key3");
        
        String str = "string";// 1.字符串
        redisUtil.set("str", str);
        System.out.println(redisTemplate.opsForValue().get("str"));
    }

    @Autowired
    private RedisUtil redisUtil;

    @Test
    public void testSpringRedis2() {
        String str = "string";// 1.字符串
        List<String> list = new ArrayList<String>();// list
        list.add("0");
        list.add("中國");
        list.add("2");
        Set<String> set = new HashSet<String>();// set
        set.add("0");
        set.add("中國");
        set.add("2");
        Map<String, Object> map = new HashMap();// map
        map.put("key1", "str1");
        map.put("key2", "中國");
        map.put("key3", "str3");

        redisUtil.del("myStr", "str");// 刪除數據

        // 1.字符串操做
        System.out.println(str);
        
        redisUtil.set("str", str);
        redisUtil.expire("str", 120);// 指定失效時間爲2分鐘
        String str1 = (String) redisUtil.get("str");
        
        System.out.println(redisTemplate.opsForValue().get("str"));
        
        
        System.out.println("str1= " + str1);

        // 2.list操做
        redisUtil.lSet("list", list);
        redisUtil.expire("list", 120);// 指定失效時間爲2分鐘
        List<Object> list1 = redisUtil.lGet("list", 0, -1);
        System.out.println(list1);

        // 3.set操做
        redisUtil.sSet("set", set);
        redisUtil.expire("set", 120);// 指定失效時間爲2分鐘
        Set<Object> set1 = redisUtil.sGet("set");
        System.out.println(set1);

        // 3.map操做
        redisUtil.hmset("map", map);
        redisUtil.expire("map", 120);// 指定失效時間爲2分鐘
        Map<Object, Object> map1 = redisUtil.hmget("map");
        System.out.println(map1);

    }

    // TODO 哨兵集羣

    // TODO CDN
}

 

這裏要說明下,真實這些配置文件的地址其實都在classes 也就是classpath根目錄下
E:\e\eclipse\work\one-parent\one-common\target\classes,若是讀spring源碼就大概能知道,spring是如何先讀xml,而後在經過classpath 判斷 怎麼讀配置文件
有的沒引入單元測試包的
<properties>
    
        <junit.version>4.9</junit.version>
        <spring-version>3.1.2.RELEASE</spring-version>
    </properties>
        
<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring-version}</version>
        </dependency>

 

4.redis哨兵集羣
上面再介紹redis的基本狀況的時候,官網把這個哨兵 sentinel放在最前面講, 應該是很重要, 主要咱們項目中封裝了一層又一層,找了很久才找到redis的真實地址,才知道運用了哨兵集羣
//遍歷哨兵地址和端口號 執行xxx 可忽略 Jedis jedis = new Jedis("", ); HostAndPort master = MyHostAndPort.toHostAndPort(jedis.sentinelGetMasterAddrByName(masterName));
首先是這樣,既然redis要集羣, 那麼就得有集羣管理工具,Redis 的 Sentinel 系統用於管理多個 Redis 服務器(instance),Redis 的 Sentinel 爲Redis提供了高可用性,包括 監控,提醒,自動故障遷移
什麼是高可用, 就是你掛了,我接着跑,生產環境偶爾會遇到服務器宕機,redis鏈接失敗等狀況
  • 先來看redis集羣,簡單來講就是master-slave,主從複製, slave同步master的數據, 用於讀寫分離和容災恢復
參考https://blog.csdn.net/u010648555/article/details/79427606

這麼操做
1.先將E:\redis\redis64-3.0.501複製三份,分別命名爲redis64-3.0.501-6379,redis64-3.0.501-6379,
redis64-3.0.501-6381

2.修改6380 6381下的redis.windows.conf文件,改爲各自對應的端口號,都作6379的從節點

port 6380

# slaveof <masterip> <masterport>
slaveof 127.0.0.1 6379

3.經過上面介紹的cmd腳本形式啓動6379, 而後啓動6380,而後啓動6379客戶端,看下圖
命令info replication

 

 
 
 
主節點可讀可寫,從節點只能讀不可寫,具體的能夠本身試試
發現我寫個打開redis-cli腳本,打開6380,彈出的命令窗口仍是127.0.0.1:6379>, 因而修改redis.windows-service.conf
也沒用,後來查原來是從節點是要加個參數
@echo off cd redis64-3.0.501-6380 redis-cli -p 6380 @pause
 
 
當主節點從新啓動後,從節點的狀態【從節點依然能夠鏈接主節點】
 
 
  • redis主從複製的缺點: 每次slave斷開重連後,都要從新所有同步一遍, 複製延遲,若是master不能寫入,會致使業務出錯,可用性不高,因此採用哨兵模式
  • 接着上文的基礎看redis-sentinel模式的配置,已經有了主從配置,E:\redis\redis64-3.0.501-6379在每一個文件夾下添加一個sentinel.conf的配置文件,這個文件在官網下載linux版本目錄下直接有
 
在複製的redis文件夾裏也加下該文件,而後改一下端口,26380,和 26381
能夠在redis解壓目錄下 經過redis-server.exe redis.windows.conf
redis-server.exe sentinel.conf --sentinel 命令, 先啓動Redis集羣,再啓動哨兵實例

也能夠像以前那樣,寫個腳本執行

示例文件作了詳細的配置說明,啓動不了,估計是裏面哪裏配置有誤,懶得找了,用下面的簡化版sentinel.conf
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 3000
sentinel failover-timeout mymaster 10000
sentinel config-epoch mymaster 0

執行後你會發現該文件有變化,寫入了從服務器的信息
# Generated by CONFIG REWRITE
dir "E:\\redis\\redis64-3.0.501-6379"
sentinel leader-epoch mymaster 0
sentinel known-slave mymaster 127.0.0.1 6380
sentinel known-slave mymaster 127.0.0.1 6381
sentinel current-epoch 0

若是報Invalid argument during startup: Failed to open the .conf file: 
通常都是配置文件的問題,把它從其餘地方關閉

 

 
 
生成哨兵ID(Sentinel ID),並自動識別主服務器和從服務器
啓動後,可使用shutdown命令關閉master,看slave選舉日誌,80 81競爭master,恢復79,79就做爲slave了
Redis-Sentinel是Redis官方推薦的高可用性(HA) 解決方案,Redis-sentinel自己也是一個獨立運行的進程,它能監控多個master-slave集羣,發現master宕機後能進行自動切換。Sentinel能夠監視任意多個主服務器(複用),以及主服務器屬下的從服務器,並在被監視的主服務器下線時,自動執行故障轉移操做。
 
爲了防止sentinel的單點故障,能夠對sentinel進行集羣化,建立多個sentinel。
 

 
5.幾個常見的redis問題
  • Redis 有哪些類型
官方文檔: strings, hashes, 我理解就是hashmap, lists, sets, sorted sets with range queries, 後面3個不知道是啥 bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.
  • Redis 內部結構
瞭解一點,redis使用 c實現的, 使用kev-value的形式存儲數據, 熟悉c語言的更好理解一點結構
1.大多數狀況下數據以字符串形式展示 2.雙端鏈表,Redis list的實現爲一個雙向鏈表,便可以支持反向查找和遍歷 3.字典 4.跳躍表 Redis sorted set的內部使用HashMap和跳躍表(SkipList)來保證數據的存儲和有序
 
 
  • 聊聊 Redis 使用場景
1.項目裏面好比系統參數配置用到的是string, 還有常常要用的好比產品庫存 2.Hash, 項目中用到的是 銀行編碼+緩存惟一標識作key , 身份證 , 用戶ID key , 電子帳號 , 用戶ID 3.Redis的list是每一個子元素都是String類型的雙向鏈表,能夠經過push和pop操做從列表的頭部或者尾部添加或者刪除元素, 這樣List便可以做爲棧,也能夠做爲隊列。 list能夠用在消息隊列場景,最新消息排行 好比一些最新評論,展現在首頁的能夠用redis , 只有點擊--顯示所有--才須要訪問數據庫, 下降數據庫
  • Redis 持久化機制
1.RDB持久化 Redis DataBase 2.AOF持久化 Append Only File
  • Redis 如何實現持久化
1.RDB : 默認的,內存中數據以 快照 的方式寫入到 二進制文件 中,默認的文件名爲dump.rdb 例子: save 900 1 #900秒內若是超過1個key被修改,則發起快照保存 方便備份,恢復快,最大化 Redis 的性能 不能避免在服務器故障時丟失數據:RDB 文件須要保存整個數據集的狀態,並非一個輕鬆的操做 可能會至少 5 分鐘才保存一次 RDB 文件。 在這種狀況下, 一旦發生故障停機, 你就可能會丟失好幾分鐘的數據 2.AOF : 當redis重啓時會經過從新執行文件中保存的寫命令來在內存中重建整個數據庫的內容 AOF 持久化會讓 Redis 變得很是耐久(much more durable) AOF 的默認策略爲每秒鐘 fsync 一次,在這種配置下,Redis 仍然能夠保持良好的性能,而且就算髮生故障停機, 也最多隻會丟失一秒鐘的數據( fsync 會在後臺線程執行,因此主線程能夠繼續努力地處理命令請求) appendonly yes //啓用aof持久化方式 # appendfsync always //每次收到寫命令就當即強制寫入磁盤,最慢的,可是保證徹底的持久化,不推薦使用 appendfsync everysec //每秒鐘強制寫入磁盤一次,在性能和持久化方面作了很好的折中,推薦 # appendfsync no //徹底依賴os,性能最好,持久化沒保證
  • Redis 集羣方案與實現
參考上面的 哨兵集羣
  • Redis 爲何是單線程的
由於Redis是基於內存的操做,CPU不是Redis的瓶頸, 100000+的QPS(每秒內查詢次數) per second Redis的瓶頸最有多是機器內存的大小或者網絡帶寬 瞭解: 單線程的方式是沒法發揮多核CPU 性能,不過咱們能夠經過在單機開多個Redis 實例 能夠在同一個多核的服務器中,能夠啓動多個實例,組成master-master或者master-slave的形式 耗時的讀命令能夠徹底在slave進行 單線程,只是在處理咱們的網絡請求的時候只有一個線程來處理 一個正式的Redis Server運行的時候確定是不止一個線程的
  • 緩存崩潰
集羣,哨兵部署起來 redis備份和預熱 緩存預熱:系統上線後,將相關的緩存數據直接加載到緩存系統,好比咱們用一個job,能夠手動執行,去加載全部須要緩存的信息 項目中, 先查緩存, 緩存不存在則從數據庫查, 查到結果,置入緩存 因爲原有緩存失效,新緩存未到期間(例如:咱們設置緩存時採用了相同的過時時間,在同一時刻出現大面積的緩存過時), 全部本來應該訪問緩存的請求都去查詢數據庫了 一個簡單方案就時講緩存失效時間分散開,好比咱們能夠在原有的失效時間基礎上增長一個隨機值, 好比1-5分鐘隨機,這樣每個緩存的過時時間的重複率就會下降,就很難引起集體失效的事件 緩存標記,咱們項目中就使用了一個標記string字段: 在項目上線後, 將key :isReliable value:1作緩存,設置永久 先去查緩存,若是緩存中沒有,多是redis所有掛了, 也多是真的沒有數據, 那麼查該標記,若是爲空可能就是緩存掛了, 再去查數據庫的裏的表,由於咱們作了分表要一次性查20張表的數據 性能很低 若是不爲空,說明緩存沒掛,在根據業務邏輯進行處理,說明可能真的沒存,直接找對應的表
  • 緩存降級
當訪問量劇增,仍然要保證核心服務可用, 非核心服務提供有損的也能夠,好比原本顯示餘額的 給它顯示一個 "客觀別急" 降級方式:能夠經過一些數據進行自動降級 經過人工開關進行降級 服務降級的目的,是爲了防止Redis服務故障,致使數據庫跟着一塊兒發生雪崩問題。所以,對於不重要的緩存數據, 能夠採起服務降級策略,例如一個比較常見的作法就是,Redis出現問題,不去數據庫查詢,而是直接返回默認值給用戶
緩存穿透: 緩存命中率問題, 用戶查數據,數據庫沒有,則沒有置入緩存,緩存中沒有,每次都去查數據庫 若是一個查詢返回的數據爲空(無論是數據不存在,仍是系統故障),咱們仍然把這個空結果進行緩存,但它的過時時間會很短, 最長不超過五分鐘。經過這個直接設置的默認值存放到緩存,這樣第二次到緩衝中獲取就有值了,而不會繼續訪問數據庫 能夠給key設置一些格式規則,而後查詢以前先過濾掉不符合規則的Key
  • 使用緩存的合理性問題
1.熱點數據 ,固然一些系統參數能夠設置永久 2.包括上面提到的緩存降級,預熱,穿透等等 3.頻繁修改的數據要考慮是否會常常讀
相關文章
相關標籤/搜索