Redis使用建議規(guī)范

合理選擇Redis部署模式

查看推薦配置

冷熱數(shù)據(jù)分離,不要將所有數(shù)據(jù)全部都放到Redis中

建議根據(jù)業(yè)務(wù)只將高頻熱數(shù)據(jù)存儲到Redis中【QPS大于5000】,對于低頻冷數(shù)據(jù)可以使用Mysql/ElasticSearch等基于磁盤的存儲方式,不僅節(jié)省內(nèi)存成本,而且數(shù)據(jù)量小在操作時速度更快、效率更高!

不同的業(yè)務(wù)數(shù)據(jù)要分開存儲

Redis默認(rèn)是提供了32個DataBase來使用,以自然數(shù)來做區(qū)分,如果不選擇DataBase,都會默認(rèn)使用0這個庫

推薦一個部門一個DataBase,然后再做NameSpace的隔離,該操作需要有SDK的支持,一個DataBase可以設(shè)置多個NameSpace,這樣可以便于管理且方便清理

<bean id="jedisConnFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}" />
        <property name="port" value="${redis.port}" />
        <property name="database" value="${redis.default.db}" />
        <property name="password" value="${redis.pass}" />
        <property name="timeout" value="${redis.timeout}" />
        <property name="poolConfig" ref="jedisPoolConfig" />
    </bean>
規(guī)范Key的格式

合適的key,便于查看,統(tǒng)計,排錯。
比如:

平臺名 平臺縮寫
網(wǎng)管 GW

“平臺縮寫“+“-”+“項目名”+“-”+“業(yè)務(wù)含義”
例如:GW-TRADE-USERID
GW是新網(wǎng)關(guān),TRADE是交易項目,USERID為業(yè)務(wù)ID。

存儲的Key一定要設(shè)置超時時間

如果應(yīng)用將Redis定位為緩存Cache使用,對于存放的Key一定要設(shè)置超時時間!因為若不設(shè)置,這些Key會一直占用內(nèi)存不釋放,造成極大的浪費,而且隨著時間的推移會導(dǎo)致內(nèi)存占用越來越大,直到達(dá)到服務(wù)器內(nèi)存上限!另外Key的超時長短要根據(jù)業(yè)務(wù)綜合評估,而不是越長越好!(某些業(yè)務(wù)要求key長期有效??梢栽诿看螌懭霑r,都設(shè)置超時時間,讓超時時間順延。)

 public Boolean set(final byte[] key, final byte[] value, final long liveTime) {
        return redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.set(key, value);
                if (liveTime > 0) {
                    connection.expire(key, liveTime);
                }
                return Boolean.TRUE;
            }
        });
    }
對于必須要存儲的大文本數(shù)據(jù)一定要壓縮后存儲

對于大文本【超過500字節(jié)】寫入到Redis時,一定要壓縮后存儲!大文本數(shù)據(jù)存入Redis,除了帶來極大的內(nèi)存占用外,在訪問量高時,很容易就會將網(wǎng)卡流量占滿,進(jìn)而造成整個服務(wù)器上的所有服務(wù)不可用,并引發(fā)雪崩效應(yīng),造成各個系統(tǒng)癱瘓!

public Boolean setBigValue(final byte[] key, final byte[] value, final long liveTime){
        return redisTemplate.execute(new RedisCallback<Boolean>() {
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] compressedBytes = CompressUtil.compress(value);
                connection.set(key, compressedBytes);
                if (liveTime > 0) {
                    connection.expire(key, liveTime);
                }
                return Boolean.TRUE;
            }
        });
    }

壓縮方式可參考

public class CompressUtil {

    private static final Inflater infl = new Inflater();

    private static final Deflater defl = new Deflater();

    private CompressUtil(){

    }

    public static byte[] uncompress(byte[] inputByte) throws IOException {
        int len = 0;
        infl.setInput(inputByte);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] outByte = new byte[1024];
        try {
            while (!infl.finished()) {
                len = infl.inflate(outByte);
                if (len == 0) {
                    break;
                }
                bos.write(outByte, 0, len);
            }
            infl.end();
        } catch (Exception e) {
        } finally {
            bos.close();
        }
        return bos.toByteArray();
    }

    public static byte[] compress(byte[] inputByte) throws IOException {
        int len = 0;
        defl.setInput(inputByte);
        defl.finish();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] outputByte = new byte[1024];
        try {
            while (!defl.finished()) {
                len = defl.deflate(outputByte);
                bos.write(outputByte, 0, len);
            }
            defl.end();
        } finally {
            bos.close();
        }
        return bos.toByteArray();
    }

}
線上Redis禁止使用Keys正則匹配操作

Redis是單線程處理,在線上KEY數(shù)量較多時,操作效率極低【時間復(fù)雜度為O(N)】,該命令一旦執(zhí)行會嚴(yán)重阻塞線上其它命令的正常請求,而且在高QPS情況下會直接造成Redis服務(wù)崩潰!如果有類似需求,請使用scan命令代替!

//此操作禁止
public Set<byte[]> get(final byte[] pattern){
        return redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
            @Override
            public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.keys(pattern);
            }
        });
    }

謹(jǐn)慎全量操作Hash、Set等集合結(jié)構(gòu)

在使用HASH結(jié)構(gòu)存儲對象屬性時,開始只有有限的十幾個field,往往使用HGETALL獲取所有成員,效率也很高,但是隨著業(yè)務(wù)發(fā)展,會將field擴(kuò)張到上百個甚至幾百個,此時還使用HGETALL會出現(xiàn)效率急劇下降、網(wǎng)卡頻繁打滿等問題【時間復(fù)雜度O(N)】,此時建議根據(jù)業(yè)務(wù)拆分為多個Hash結(jié)構(gòu);或者如果大部分都是獲取所有屬性的操作,可以將所有屬性序列化為一個STRING類型存儲!同樣在使用SMEMBERS操作SET結(jié)構(gòu)類型時也是相同的情況!

根據(jù)業(yè)務(wù)場景合理使用不同的數(shù)據(jù)結(jié)構(gòu)類型

目前Redis支持的數(shù)據(jù)庫結(jié)構(gòu)類型較多:字符串(String),哈希(Hash),列表(List),集合(Set),有序集合(Sorted Set), Bitmap, HyperLogLog和地理空間索引(geospatial)等,需要根據(jù)業(yè)務(wù)場景選擇合適的類型,常見的如:String可以用作普通的K-V、計數(shù)類;Hash可以用作對象等,包含較多屬性的信息;List可以用作消息隊列、粉絲/關(guān)注列表等;Set可以用于推薦;Sorted Set可以用于排行等!

考慮Redis的sharding機制

目前spring-data-redis的JedisConnectionFactory沒有實現(xiàn)sharding的功能,但是其依賴Jedis實現(xiàn)了,所以如果要sharding,需要自己實現(xiàn)邏輯,需要自己去實現(xiàn)封裝

對重要的數(shù)據(jù)使用try/catch

如果必須確保關(guān)鍵性的數(shù)據(jù)可以被放入到 Redis 的實例中,我強烈建議將其放入 try/except 塊中。幾乎所有的Redis客戶端采用的都是“發(fā)送即忘”策略,因此經(jīng)常需要考慮一個 key 是否真正被放到 Redis 數(shù)據(jù)庫中了。至于將 try/expect 放到 Redis 命令中的復(fù)雜性并不是本文要講的,你只需要知道這樣做可以確保重要的數(shù)據(jù)放到該放的地方就可以了。

合理使用Hash
1. 127.0.0.1:6379> HSET foo first_name "Joe"   
3. 127.0.0.1:6379> HSET foo last_name "Engel" 
5. 127.0.0.1:6379> HSET foo address "1 Fanatical Pl"
7. 127.0.0.1:6379> HGETALL foo 
   "first_name"  
   "Joe"  
  "last_name"  
  "Engel"  
  "address"  
  "1 Fanatical Pl"  
14. 127.0.0.1:6379> HGET foo first_name  
  "Joe"  

推薦配置

properties配置
####單機模式#######
##redis的服務(wù)器地址
redis.host=192.168.1.20
##redis的服務(wù)端口 
redis.port=6400 

####哨兵模式
##redis的服務(wù)器地址
redis.sentinel.master.host=192.168.1.20
##redis的服務(wù)端口 
redis.sentinel.master.port=26379
redis.sentinel.slave1.host=192.168.1.21
redis.sentinel.slave1.port=26380
redis.sentinel.slave2=192.168.1.22
redis.sentinel.slave2.port=26381

####集群模式
##redis的服務(wù)器地址
redis.cluster.host1=192.168.1.20
##redis的服務(wù)端口 
redis.cluster.port1=6400
redis.cluster.host2=192.168.1.20
redis.cluster.port2=6400
redis.cluster.host3=192.168.1.20
redis.cluster.port3=6400


##redis密碼
redis.pass=1234xxxxx
##redis連接數(shù)據(jù)庫
redis.default.db=0
##客戶端超時時間單位是毫秒  
redis.timeout=100000
##最大連接數(shù)
redis.maxActive=300
##最大空閑數(shù)
redis.maxIdle=100
##最大建立連接等待時間  
redis.maxWait=1000
##指明是否在從池中取出連接前進(jìn)行檢驗,如果檢驗失敗,則從池中去除連接并嘗試取出另一個
redis.testOnBorrow=true
單機模式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--引入redis配置文件 -->
    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:redis.properties</value>
            </list>
        </property>
    </bean>
    <!--連接池 屬性定義 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxActive" value="${redis.maxActive}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWait" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    <!--定義連接工廠 -->
    <bean id="jedisConnFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis.host}" />
        <property name="port" value="${redis.port}" />
        <property name="database" value="${redis.default.db}" />
        <property name="password" value="${redis.pass}" />
        <property name="timeout" value="${redis.timeout}" />
        <property name="poolConfig" ref="jedisPoolConfig" />
    </bean>
    <!-- redis模板 -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
        p:connectionFactory-ref="jedisConnFactory" p:enableTransactionSupport="true">
        <property name="keySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashValueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
    </bean>
</beans>
哨兵模式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--引入redis配置文件 -->
    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:redis.properties</value>
            </list>
        </property>
    </bean>
    <!--連接池 屬性定義 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxActive" value="${redis.maxActive}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWait" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    <!-- 哨兵模式 -->
    <bean id="redisSentinelConfiguration"
        class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
        <property name="master">
            <bean class="org.springframework.data.redis.connection.RedisNode">
                <property name="name" value="mymaster">
                </property>
            </bean>
        </property>
        <property name="sentinels">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.sentinel.master.host}" />
                    <constructor-arg name="port" value="${redis.sentinel.master.port}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode">
                    <constructor-arg name="host" value="${redis.sentinel.slave1.host}" />
                    <constructor-arg name="port" value="${redis.sentinel.slave1.port}" />
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisNode ">
                    <constructor-arg name="host" value="${redis.sentinel.slave2.host}" />
                    <constructor-arg name="port" value="${redis.sentinel.slave2.port}" />
                </bean>
            </set>
        </property>
    </bean>
    <!--定義連接工廠 -->
    <bean id="jedisConnFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <constructor-arg name="sentinelConfig" ref="redisSentinelConfiguration" />
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <property name="database" value="${redis.database}" />
        <property name="password" value="${redis.pass}" />
        <property name="timeout" value="${redis.timeout}" />
    </bean>
    <!-- redis 模板 -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
        p:connectionFactory-ref="jedisConnFactory" p:enableTransactionSupport="true">
        <property name="keySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashValueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
    </bean>

</beans>
集群模式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--引入redis配置文件 -->
    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:redis.properties</value>
            </list>
        </property>
    </bean>
    <!--連接池 屬性定義 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxActive" value="${redis.maxActive}" />
        <property name="maxIdle" value="${redis.maxIdle}" />
        <property name="maxWait" value="${redis.maxWait}" />
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
    </bean>
    
    <!-- 集群模式 -->
    <bean id="redisClusterConfiguration"
        class="org.springframework.data.redis.connection.RedisClusterConfiguration">
        <property name="maxRedirects" value="${redis.maxRedirects}"></property>
        <property name="clusterNodes">
            <set>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host1}"/>
                    <constructor-arg name="port" value="${redis.cluster.port1}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host2}"/>
                    <constructor-arg name="port" value="${redis.cluster.port2}"/>
                </bean>
                <bean class="org.springframework.data.redis.connection.RedisClusterNode">
                    <constructor-arg name="host" value="${redis.cluster.host3}"/>
                    <constructor-arg name="port" value="${redis.cluster.port3}"/>
                </bean>
            </set>
        </property>
    </bean>
    <!--定義連接工廠 -->
    <bean id="jedisConnFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <constructor-arg name="clusterConfig" ref="redisClusterConfiguration" />
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <property name="database" value="${redis.database}" />
        <property name="password" value="${redis.pass}" />
        <property name="timeout" value="${redis.timeout}" />
    </bean>
    
    <!-- redis 模板 -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
        p:connectionFactory-ref="jedisConnFactory" p:enableTransactionSupport="true">
        <property name="keySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="valueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashKeySerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
        <property name="hashValueSerializer">
            <bean
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />
        </property>
    </bean>

</beans>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)載地址:http://gnucto.blog.51cto.com/3391516/998509 Redis與Me...
    Ddaidai閱讀 21,547評論 0 82
  • 1 Redis介紹1.1 什么是NoSql為了解決高并發(fā)、高可擴(kuò)展、高可用、大數(shù)據(jù)存儲問題而產(chǎn)生的數(shù)據(jù)庫解決方...
    克魯?shù)吕?/span>閱讀 5,715評論 0 36
  • Redis的內(nèi)存優(yōu)化 聲明:本文內(nèi)容來自《Redis開發(fā)與運維》一書第八章,如轉(zhuǎn)載請聲明。 Redis所有的數(shù)據(jù)都...
    meng_philip123閱讀 19,065評論 2 29
  • 靈感來源于美國80年代科幻電影《回到未來》系列等,將霓虹風(fēng)格與復(fù)古元素結(jié)合,為MIUI8制作了一款主題
    卷毛大能閱讀 513評論 0 1
  • 隨手記顯示今天是我記賬的第692天,真堅持了這么久嗎?我都有些差異?,F(xiàn)在,通過隨手記和其云同步的電腦端家財通,我的...
    那山以西閱讀 680評論 2 4

友情鏈接更多精彩內(nèi)容