Redis基本操作

Redis

Redis入門

? ?Redis是一個(gè)開源(BSD許可),內(nèi)存存儲的數(shù)據(jù)結(jié)構(gòu)服務(wù)器,可用作數(shù)據(jù)庫,高速緩存和消息隊(duì)列代理。它支持字符串、哈希表、列表、集合、有序集合,位圖,hyperloglogs等數(shù)據(jù)類型。內(nèi)置復(fù)制、Lua腳本、LRU收回、事務(wù)以及不同級別磁盤持久化功能,同時(shí)通過Redis Sentinel提供高可用,通過Redis Cluster提供自動分區(qū)

Redis下載

下載地址:http://download.redis.io/releases/redis-3.2.8.tar.gz

Redis的安裝

? ?這里在mac下模擬安裝,如果需要在linux或者window下安裝的話,請自行百度。這里以3.2.8為例

Redis的啟動和關(guān)閉

啟動:
? ?在命令行輸入命令 redis-server,默認(rèn)鏈接Redis(127.0.0.1:6379) 啟動,如果出現(xiàn)蛋糕圖案說明安裝成功。

關(guān)閉:

  • 使用redis-cli shutdown命令關(guān)閉。
  • 使用進(jìn)程ps -ef | grep redis , kill -9 pid,使用這種方式可能會導(dǎo)致數(shù)據(jù)丟失。

Redis鍵

常用命令:

  • key * :返回所有鍵
  • exists key : 判斷某個(gè)key是否存在
  • expire key : 給指定的鍵設(shè)置過期時(shí)間
  • ttl key : 查看還有多少秒過期,-1表示永不過期,-2表示已過期
  • type key : 查看你的key是什么類型

Redis數(shù)據(jù)類型

  • 字符串
    ? ?string類型是二進(jìn)制安全的。意思是redis的string可以包含任何數(shù)據(jù)。比如jpg圖片或者序列化的對象。
    string類型是Redis最基本的數(shù)據(jù)類型,一個(gè)鍵最大能存儲512MB??梢栽赾onf文件里設(shè)置maxmemory的內(nèi)存大小,單位是字節(jié)。
127.0.0.1:6379> set key1 hello
OK
127.0.0.1:6379> get key1
"hello"
127.0.0.1:6379> 

如果key已經(jīng)存在則覆蓋已經(jīng)存在的值。

  • Hash(哈希)

hset key filed value
hget key filed
hmset key filed value [filed value...]
hmget key filed [filed...]
hgetall key

127.0.0.1:6379> hmset user:1 usernmae zhangsan password 123456 age 18 address xian
OK
127.0.0.1:6379> hgetall user:1
1) "usernmae"
2) "zhangsan"
3) "password"
4) "123456"
5) "age"
6) "18"
7) "address"
8) "xian"
127.0.0.1:6379> 
127.0.0.1:6379> hmget user:1 age
1) "18"

  • List(列表)
    Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個(gè)元素到 列表的頭部(左邊)或者尾部(右邊)。
127.0.0.1:6379> lpush lisi xianren
(integer) 1
127.0.0.1:6379> lpush lisi 18
(integer) 2
127.0.0.1:6379> lpush lisi qinguo
(integer) 3
127.0.0.1:6379> lrange lisi 0 10
1) "qinguo"
2) "18"
3) "xianren"
127.0.0.1:6379> 
  • Set(集合)
    Redis的Set是string類型的無序集合。
127.0.0.1:6379> sadd redis hao haoyong henhaoyong
(integer) 3
127.0.0.1:6379> sadd redis shizhendehaoyong
(integer) 1
127.0.0.1:6379> smembers redis
1) "hao"
2) "haoyong"
3) "henhaoyong"
4) "shizhendehaoyong"
127.0.0.1:6379> 
  • zset有序集合
    Redis zset和set一樣也是string類型元素的集合,且不允許重復(fù)的成員。不同的是每個(gè)元素都會關(guān)聯(lián)一個(gè)double類型的分?jǐn)?shù)。redis正是通過分?jǐn)?shù)來為集合中的成員進(jìn)行從小到大的排序。
127.0.0.1:6379> zadd wangwu 1 a
(integer) 1
127.0.0.1:6379> zadd wangwu 0 b
(integer) 1
127.0.0.1:6379> zadd wangwu 3 c
(integer) 1
127.0.0.1:6379> zadd wagnwu 2 d
(integer) 1
127.0.0.1:6379> zrangebyscore wangwu 0 5
1) "b"
2) "a"
3) "c"
127.0.0.1:6379> 

解析配置文件

  • daemonize no
    默認(rèn)情況下 redis不是作為守護(hù)進(jìn)程運(yùn)行的,如果你想讓它在后臺運(yùn)行,你就把它改成yes。當(dāng)redis作為守護(hù)進(jìn)程運(yùn)行的時(shí)候,它會寫一個(gè) pid 到 /var/run/redis.pid 文件里面。
  • tcp-backlog 511
    在高并發(fā)的環(huán)境下,你需要把這個(gè)值調(diào)高以避免客戶端連接緩慢的問題。
    Linux內(nèi)核會一聲不響的把這個(gè)值縮小成/proc/sys/net/core/somaxconn 對應(yīng)的值,所以你要修改這兩個(gè)值才能達(dá)到你的預(yù)期。
  • tcp-keepalive 300
  • loglevel notice
  • databases 默認(rèn)值16,表示Redis默認(rèn)的數(shù)據(jù)庫實(shí)力數(shù)量,如果需要切換數(shù)據(jù)庫,需要使用select number命令切換,flushall清空整個(gè)Redis服務(wù)器的數(shù)據(jù),包括0-16的所有數(shù)據(jù)庫實(shí)例,所以使用謹(jǐn)慎使用此命令。flushdb用于清空當(dāng)前數(shù)據(jù)庫中所有的key。
  • SNAPSHOTTING
    持久換
  • SECURITY
    默認(rèn)redis是不需要密碼輸入的,如果我們需要設(shè)置密碼登錄,可以通過命令config set requirepass "111111" ,但是下次在使用命令的時(shí)候回提示你輸入密碼,但是redis是運(yùn)行于linux之上的,Redis認(rèn)為Linux是足夠安全的,所以redis默認(rèn)是不需要密碼的。Redis支持密碼,但不建議這么做。
  • LIMISTS限制
    • 1 maxClients
    • 2 maxmemory
    • 3 maxmemory-policy(緩存過期策略6種)
      • volatile-lru -> remove the key with an expire set using an LRU algorithm
      • allkeys-lru -> remove any key according to the LRU algorithm
      • volatile-random -> remove a random key with an expire set
      • allkeys-random -> remove a random key, any key
      • volatile-ttl -> remove the key with the nearest expire time (minor TTL)
      • noeviction -> don't expire at all, just return an error on write operations
    • 4 maxmemroy-samples
      設(shè)置樣本數(shù)量,LRU算法和TTL算法都并非是精準(zhǔn)的算法而是估算值,,所以你可以設(shè)置樣本的大小,Redis默認(rèn)會檢查這么多個(gè)key并選擇其中LRU的那個(gè)

查看數(shù)據(jù)庫大小

使用info命令查看數(shù)據(jù)庫使用情況

used_memory:數(shù)據(jù)占用了多少內(nèi)存(字節(jié)
used_memory_human:數(shù)據(jù)占用了多少內(nèi)存(帶單位的,可讀性好)
used_memory_rss:redis占用了多少內(nèi)存
used_memory_peak:占用內(nèi)存的峰值(字節(jié))
used_memory_peak_human:占用內(nèi)存的峰值(帶單位的,可讀性好)

127.0.0.1:6379> info
......
......
# Memory
used_memory:886548
used_memory_human:865.77K
used_memory_rss:2068480
used_memory_rss_human:1.97M
used_memory_peak:886548
used_memory_peak_human:865.77K
used_memory_peak_perc:100.12%
used_memory_overhead:884987
used_memory_startup:835253
used_memory_dataset:1561
used_memory_dataset_perc:3.04%
......
......

Redis的持久化

  • rdb
    實(shí)現(xiàn)機(jī)制:當(dāng)redis需要做持久化時(shí),redis會fork一個(gè)子進(jìn)程;子進(jìn)程將數(shù)據(jù)寫到磁盤上一個(gè)臨時(shí)RDB文件中;當(dāng)子進(jìn)程完成寫臨時(shí)文件后,將原來的RDB替換掉,這樣的好處就是可以copy-on-write
  • aof
    filesnapshotting方法在redis異常死掉時(shí),最近的數(shù)據(jù)會丟失,Append-only方法可以做到全部數(shù)據(jù)不丟失,但redis的性能就要差些。AOF就可以做到全程持久化,只需要在配置文件中開啟(默認(rèn)是no),appendonly yes開啟AOF之后,redis每執(zhí)行一個(gè)修改數(shù)據(jù)的命令,都會把它添加到aof文件中,當(dāng)redis重啟時(shí),將會讀取AOF文件進(jìn)行“重放”以恢復(fù)到redis關(guān)閉前的最后時(shí)刻。

Redis的事務(wù)

? ?MULTI 命令用于開啟一個(gè)事務(wù),它總是返回 OK。 MULTI 執(zhí)行之后, 客戶端可以繼續(xù)向服務(wù)器發(fā)送任意多條命令, 這些命令不會立即被執(zhí)行, 而是被放到一個(gè)隊(duì)列中, 當(dāng) EXEC命令被調(diào)用時(shí), 所有隊(duì)列中的命令才會被執(zhí)行。
另一方面, 通過調(diào)用 DISCARD , 客戶端可以清空事務(wù)隊(duì)列, 并放棄執(zhí)行事務(wù)
demo如下

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr foo
QUEUED
127.0.0.1:6379> incr bar
QUEUED
127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> 

發(fā)生回滾的的原因

  • 語法錯(cuò)誤
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key value
QUEUED
127.0.0.1:6379> set key
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> errorcommand key
(error) ERR unknown command 'errorcommand'
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get key
(nil)
127.0.0.1:6379> 

? ?當(dāng)遇到語法錯(cuò)誤的時(shí)候,后面執(zhí)行exec的命令時(shí),系統(tǒng)會discarded事務(wù)。

  • 運(yùn)行錯(cuò)誤
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key 1
QUEUED
127.0.0.1:6379> sadd key 2
QUEUED
127.0.0.1:6379> set key 3
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get key
"3"
127.0.0.1:6379> 
  • 為什么不支持事務(wù)
    以下是這種做法的優(yōu)點(diǎn):

    • Redis 命令只會因?yàn)殄e(cuò)誤的語法而失?。ú⑶疫@些問題不能在入隊(duì)時(shí)發(fā)現(xiàn)),或是命令用在了錯(cuò)誤類型的鍵上面:這也就是說,從實(shí)用性的角度來說,失敗的命令是由編程錯(cuò)誤造成的,而這些錯(cuò)誤應(yīng)該在開發(fā)的過程中被發(fā)現(xiàn),而不應(yīng)該出現(xiàn)在生產(chǎn)環(huán)境中。
    • 因?yàn)椴恍枰獙貪L進(jìn)行支持,所以 Redis 的內(nèi)部可以保持簡單且快速。
      Redis的事務(wù)沒有關(guān)系數(shù)據(jù)庫事務(wù)提供的回滾(rollback)功能 。為此開發(fā)者必須在事務(wù)執(zhí)行出錯(cuò)后自己收拾剩下的攤子(將數(shù)據(jù)庫復(fù)原回事務(wù)執(zhí)行前的狀態(tài)等)。
  • 放棄事務(wù)
    使用discard命令,放棄事務(wù),事務(wù)隊(duì)列被清空,并且客戶端會從事務(wù)狀態(tài)中退出

  • watch命令
    watch監(jiān)控一個(gè)鍵的值是否被改過,在一個(gè)事務(wù)中,在沒有執(zhí)行exec命令之前,如果監(jiān)控的值被改動了,則事務(wù)失敗。如果事務(wù)成功,則取消對所有的鍵的監(jiān)控。watch也可以監(jiān)視多個(gè)值watch key1 key2 key3

Redis 分區(qū)

? ?分區(qū)可以讓Redis管理更大的內(nèi)存,Redis將可以使用所有機(jī)器的內(nèi)存。如果沒有分區(qū),你最多只能使用一臺機(jī)器的內(nèi)存。
分區(qū)使Redis的計(jì)算能力通過簡單地增加計(jì)算機(jī)得到成倍提升,Redis的網(wǎng)絡(luò)帶寬也會隨著計(jì)算機(jī)和網(wǎng)卡的增加而成倍增長。

  • Redis集群
    ? ?
    Redis集群是自動分片和高可用的首選方案
  • Twemproxy
    Twemproxy是Twitter維護(hù)的(緩存)代理系統(tǒng),代理Memcached的ASCII協(xié)議和Redis協(xié)議。該代理實(shí)現(xiàn)了一致性hash算法。

Redis的訂閱發(fā)布

Redis的復(fù)制

Redis的Java客戶端Jedis

Spring Boot整合Redis

yml配置文件

spring:
  redis:
    database: 0
    host: 127.0.0.1
    port: 6379
    password:
    pool:
      max-active: 8 # 連接池最大連接數(shù)(使用負(fù)值表示沒有限制)
      max-wait: -1  # 連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒有限制
      max-idle: 8   # 連接池中的最大空閑連接
      min-idle: 0   # 連接池中的最小空閑連接
    timeout: 0      # 鏈接超時(shí)時(shí)間

ServiceImpl.java如下

package com.yao.service;

import com.yao.domain.City;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

/**
 * Created by yaochenglong on 17/11/20.
 * CityServiceImpl demo
 */
@Service
public class CityServiceImpl implements CityService {

    private static Logger logger = Logger.getLogger(CityServiceImpl.class);

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public City findCityById(String id) {
        String key ="city"+id;

        ValueOperations<String,City> operations = redisTemplate.opsForValue();
        Boolean hasKey = redisTemplate.hasKey(key);
        if(hasKey){
            City city = operations.get(key);
            logger.info("CityServiceImpl.findCityById() : 從緩存中獲取了城市>>"+city.getCityName());
            return city;
        }

        //模擬從數(shù)據(jù)庫中獲取數(shù)據(jù)
        City city = new City();
        city.setId("123");
        city.setCityName("西安");
        city.setDescription("愛我大西安");
        operations.set(key,city);
        System.out.println("ityServiceImpl.findCityById() : 從數(shù)據(jù)庫中獲取了城市");
        return city;
    }

    @Override
    public Long updateCity(City city) {

        //Long ret = cityDao.updateCity(city);
          Long ret = 1l;

        // 緩存存在,刪除緩存

        String key = "city_" + city.getId();

        boolean hasKey = redisTemplate.hasKey(key);

        if (hasKey) {

            redisTemplate.delete(key);


            logger.info("CityServiceImpl.updateCity() : 從緩存中刪除城市 >> " + city.toString());

        }


        return ret;

    }
}

Controller 如下

package com.yao.controller;

import com.yao.domain.City;
import com.yao.service.CityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by yaochenglong on 17/11/20.
 */
@RestController
public class CityController {
    @Autowired
    private CityService cityService;

    @GetMapping("/city/get/{id}")
    public String getCity(@PathVariable("id") String id){
        City city = cityService.findCityById(id);
        return city.getCityName();
    }
}

連續(xù)訪問請求兩次,結(jié)果如下:

2017-11-20 22:19:59.985  INFO 1179 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-11-20 22:19:59.985  INFO 1179 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2017-11-20 22:19:59.995  INFO 1179 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 10 ms
ityServiceImpl.findCityById() : 從數(shù)據(jù)庫中獲取了城市
2017-11-20 22:20:01.704  INFO 1179 --- [nio-8080-exec-3] com.yao.service.CityServiceImpl          : CityServiceImpl.findCityById() : 從緩存中獲取了城市>>西安

? ?我們可以看到第一次從數(shù)據(jù)庫中獲取數(shù)據(jù),第二次訪問則從緩存中獲取數(shù)據(jù)。

高可用性

  • Redis哨兵

  • 自動分區(qū)

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

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

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