# 下載 cd /tmp wget http://download.redis.io/releases/redis-3.2.11.tar.gz # 解壓 tar -zxvf redis-3.2.11.tar.gz # 創建軟鏈接 ln -s redis-3.2.11 redis # 編譯安裝 cd redis make make install # 查看redis-開頭的可執行文件 cd src ll | grep redis- # 顯示以下 -rwxr-xr-x 1 root root 2432576 Nov 25 18:00 redis-benchmark -rw-rw-r-- 1 root root 29559 Sep 21 22:20 redis-benchmark.c -rw-r--r-- 1 root root 108448 Nov 25 18:00 redis-benchmark.o -rwxr-xr-x 1 root root 25168 Nov 25 18:00 redis-check-aof -rw-rw-r-- 1 root root 6328 Sep 21 22:20 redis-check-aof.c -rw-r--r-- 1 root root 33688 Nov 25 18:00 redis-check-aof.o -rwxr-xr-x 1 root root 5191328 Nov 25 18:00 redis-check-rdb -rw-rw-r-- 1 root root 12789 Sep 21 22:20 redis-check-rdb.c -rw-r--r-- 1 root root 54496 Nov 25 18:00 redis-check-rdb.o -rwxr-xr-x 1 root root 2585448 Nov 25 18:00 redis-cli -rw-rw-r-- 1 root root 90678 Sep 21 22:20 redis-cli.c -rw-r--r-- 1 root root 366344 Nov 25 18:00 redis-cli.o -rwxr-xr-x 1 root root 5191328 Nov 25 18:00 redis-sentinel -rwxr-xr-x 1 root root 5191328 Nov 25 18:00 redis-server -rwxrwxr-x 1 root root 60852 Sep 21 22:20 redis-trib.rb # 回到redis目錄 cd .. # 啓動redis redis-server # 能夠用下面三種方式驗證redis服務器是否正常 # 查詢redis進程 ps -ef | grep redis root 30253 27126 0 18:10 pts/0 00:00:00 redis-server *:6379 root 30279 30259 0 18:19 pts/1 00:00:00 grep --color=auto redis # 查詢redis端口占用 netstat -antpl | grep redis tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 30253/redis-server tcp6 0 0 :::6379 :::* LISTEN 30253/redis-server # 用redis客戶端進行鏈接,而後執行ping,返回PONG redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> ping PONG
生產環境建議指定配置文件啓動,單機多實例配置文件能夠用端口區分開,好比像下面這樣:php
mv redis.conf redis-6380.conf vim redis-6380.conf
暫時咱們僅指定如下幾項基礎配置:java
# 是否以守護進程方式啓動 daemonize yes # redis對外端口 port 6380 # 工做目錄 dir ./ # 日誌文件 logfile "6380.log"
用指定配置文件方式從新啓動Redisnode
redis-server redis-6380.conf ps -ef | grep redis root 30339 1 0 18:55 ? 00:00:00 redis-server 127.0.0.1:6380 root 30344 30259 0 18:56 pts/1 00:00:00 grep --color=auto redis
redis-cli鏈接mysql
# 咱們在任意目錄下啓動redis客戶端 redis-cli -h 127.0.0.1 -p 6379 127.0.0.1:6379> ping PONG 127.0.0.1:6379> incr number (integer) 1 127.0.0.1:6379> set hello world OK 127.0.0.1:6379> set foo bar OK 127.0.0.1:6379> get hello "world" 127.0.0.1:6379>
redis-cli返回值redis
127.0.0.1:6379> ping PONG
127.0.0.1:6379> hget hello (error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> incr number (integer) 1
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> get hello "world"
127.0.0.1:6379> set foo bar OK 127.0.0.1:6379> mget hello foo 1) "world" 2) "bar"
除了上面幾個最基本的配置,redis還有下面這些高級配置:sql
後續穿插講解shell
能夠經過如下命令列出配置:vim
# 列出配置文件的配置項,去除註釋行和空行 cat redis.conf | grep -v '#' | grep -v '^$'
bind 127.0.0.1 protected-mode yes port 6379 tcp-backlog 511 timeout 0 tcp-keepalive 300 daemonize yes supervised no pidfile /var/run/redis_6379.pid loglevel notice logfile "" databases 16 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir ./ slave-serve-stale-data yes slave-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no slave-priority 100 appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 aof-rewrite-incremental-fsync yes
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4 OK 127.0.0.1:6379> dbsize (integer) 4 127.0.0.1:6379> sadd myset a b c d e (integer) 5 127.0.0.1:6379> dbsize (integer) 5
127.0.0.1:6379> set a b OK 127.0.0.1:6379> exist a (integer) 1 127.0.0.1:6379> del a (integer) 1 127.0.0.1:6379> exists a (integer) 0
127.0.0.1:6379> set a b OK 127.0.0.1:6379> get a "b" 127.0.0.1:6379> del a (integer) 1 127.0.0.1:6379> get a (nil)
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> expire hello 20 (integer) 1 127.0.0.1:6379> ttl hello (integer) 16 127.0.0.1:6379> get hello "world" 127.0.0.1:6379> ttl hello (integer) 7 127.0.0.1:6379> ttl hello (integer) -2 (-2表明key已經不存在了) 127.0.0.1:6379> get hello (nil)
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> expire hello 20 (integer) 1 127.0.0.1:6379> ttl hello (integer) 16 (還有16秒過時) 127.0.0.1:6379> persist hello (integer) 1 127.0.0.1:6379> ttl hello (integer) -1 (-1表明key存在,而且沒有設置過時時間) 127.0.0.1:6379> get hello "wordl"
redis數據類型:string hash list set zsetapi
127.0.0.1:6379> set a b OK 127.0.0.1:6379> type a string 127.0.0.1:6379> sadd myset 1 2 3 (integer) 3 127.0.0.1:6379> type myset set
命令 | 時間複雜度 |
---|---|
keys | O(n) |
dbsize | O(1) |
del | O(1) |
exists | O(1) |
expire | O(1) |
type | O(1) |
Redis單線程設計,所以使用時要注意幾點:緩存
長(慢)命令:keys, flushall, flushdb, slow lua script, mutil/exec, operate big value(collection)
使用場景
命令
127.0.0.1:6379> set hello "world" OK 127.0.0.1:6379> get hello "world" 127.0.0.1:6379> del hello 1 127.0.0.1:6379> get hello (nil)
127.0.0.1:6379> get counter (nil) 127.0.0.1:6379> incr counter (integer) 1 127.0.0.1:6379> get counter "1" 127.0.0.1:6379> incrby counter 99 (integer) 100 127.0.0.1:6379> decr counter (integer) 99 127.0.0.1:6379> get counter "99"
127.0.0.1:6379> exists php (integer) 0 (0表明不存在) 127.0.0.1:6379> set php good OK 127.0.0.1:6379> sexnx php bad (integer) 0 127.0.0.1:6379> set php best xx OK 127.0.0.1:6379> get php "best" 127.0.0.1:6379> exists java (integer) 0 127.0.0.1:6379> set java best (integer) 1 127.0.0.1:6379> set java easy xx OK 127.0.0.1:6379> get java "easy" 127.0.0.1:6379> exists lua (integer) 0 127.0.0.1:6379> set lua hehe xx (nil)
127.0.0.1:6379> mset hello world java best php good OK 127.0.0.1:6379> mget hello java php "world" "best" "good"
127.0.0.1:6379> set hello world OK 127.0.0.1:6379> getset hello php "world" 127.0.0.1:6379> get hello "php" 127.0.0.1:6379> append hello ",java" (integer) 8 127.0.0.1:6379> get hello "pho,java" 127.0.0.1:6379> strlen hello (integer) 8 127.0.0.1:6379> set hello "足球" OK 127.0.0.1:6379> strlen hello (integer) 4 (一箇中文佔2個字節)
127.0.0.1:6379> incr counter (integer) 1 127.0.0.1:6379> incrbyfloat counter 1.1 "2.1" 127.0.0.1:6379> get counter "2.1" 127.0.0.1:6379> set hello javabest OK 127.0.0.1:6379> getrange hello 0 2 "jav" 127.0.0.1:6379> setrange hello 4 p (integer) 8 127.0.0.1:6379> get hello "javapest"
命令 | 含義 | 時間複雜度 |
---|---|---|
set key value | 設置key-value | O(1) |
get key | 獲取key-value | O(1) |
del key | 刪除key-value | O(1) |
setnx setxx | 根據key是否存在設置key-value | O(1) |
incr decr | 計數 | O(1) |
mget mset | 批量操做key-value | O(n) |
實戰
incr userid:pageview(單線程:無競爭)
緩存視頻的基本信息(數據源在MySQL中)
僞代碼以下:
public VideoInfo get(long id) { String redisKey = redisPrefix + id; VideoInfo videoInfo = redis.get(redisKey); if (videoInfo == null) { videoInfo = mysql.get(id); if (videoInfo != null) { // 序列化 redis.set(redisKey, serialize(videoInfo)); } } return videoInfo; }
利用了redis的單線程,即便是多個服務同時來獲取ID,也得一個個來。
命令
# hset 設置field-value對 127.0.0.1:6379> hset user:1:info age 23 (integer) 1 # hget 獲取field的value 127.0.0.1:6379> hget user:1:info age "23" 127.0.0.1:6379> hset user:1:info name ronaldo (integer) 1 # hgetall 獲取全部key-value對 127.0.0.1:6379> hgetall user:1:info 1) "age" 2) "23" 3) "name" 4) "ronaldo" # hdel 刪除key-value對 127.0.0.1:6379> hdel user:1:info age (integer) 1 127.0.0.1:6379> hgetall user:1:info 1) "name" 2) "ronaldo"
127.0.0.1:6379> hgetall user:1:info 1) "age" 2) "23" 3) "name" 4) "ronaldo" # hexists 判斷filed是否存在 127.0.0.1:6379> hexists user:1:info name (integer) 1 # 判斷field長度 127.0.0.1:6379> hlen user:1:info (integer) 2
# hmset 設置多個filed-value對 127.0.0.1:6379> hmset user:2:info age 30 name kaka page 50 OK 127.0.0.1:6379> hlen user:2:info (integer) 3 # hmget 獲取多個field的value 127.0.0.1:6379> hmget user:2:info age name 1) "30" 2) "kaka"
# hgetall key:返回hash key對應全部的field和value 127.0.0.1:6379> hgetall user:2:info 1) "age" 2) "30" 3) "name" 4) "kaka" 5) "page" 6) "50" # hvals key:返回hash key對應全部filed的value 127.0.0.1:6379> hvals user:2:info 1) "30" 2) "kaka" 3) "50" # hkeys key:返回hash key對應全部field 127.0.0.1:6379> hkeys user:2:info 1) "age" 2) "name" 3) "page"
string | hash |
---|---|
get | hget |
set setnx | hset hsetnx |
del | hdel |
incr incrby decr decrby | hincrby |
mset | hmset |
mget | hmget |
命令 | 時間複雜度 |
---|---|
hget hset hdel | O(1) |
hexists | O(1) |
hincrby | O(1) |
hgetall hvals hkeys | O(n) |
hmget hmset | O(n) |
實戰
hincrby user:1:info pageview count
緩存視頻的基本信息(數據源在MySQL中)
僞代碼以下:
public VideoInfo get(long id) { String redisKey = redisPrefix + id; Map<String, String> hashMap = redis.hgetAll(redisKey); VideoInfo videoInfo = transferMapToVideo(hashMap); if (videoInfo == null) { videoInfo = mysql.get(id); if (videoInfo != null) { redis.hmset(redisKey, transferVideoToMap(videoInfo)); } } return videoInfo; }
有序可重複列表
數據結構
命令
實戰規則
集合元素無序不可重複
API介紹
127.0.0.1:6379> sadd user:1:follow it news his sports (integer) 4 127.0.0.1:6379> smembers user:1:follow 1) "news" 2) "his" 3) "it" 4) "sports" 127.0.0.1:6379> spop user:1:follow "news" 127.0.0.1:6379> smembers user:1:follow 1) "his" 2) "it" 3) "sports" 127.0.0.1:6379> scard user:1:follow (integer) 3 127.0.0.1:6379> sismember user:1:follow entertainment (integer) 0
有序不可重複集合
API介紹
API使用演示
# zadd 添加集合元素 127.0.0.1:6379> zadd player:rank 1000 ronaldo 900 messi 800 c-ronaldo 600 kaka (integer) 4 # zscore 獲取分值 127.0.0.1:6379> zscore player:rank kaka "600" # zcard 獲取元素個數 127.0.0.1:6379> zcard player:rank (integer) 4 # zrank 獲取排名,從0開始算 127.0.0.1:6379> zrank player:rank ronaldo (integer) 3 # zrem 刪除元素 127.0.0.1:6379> zrem player:rank messi (integer) 1 # zrange 獲取指定索引範圍內的升序元素 127.0.0.1:6379> zrange player:rank 0 -1 withscores 1) "kaka" 2) "600" 3) "c-ronaldo" 4) "800" 5) "ronaldo" 6) "1000"
127.0.0.1:6379> zadd player:rank 1000 ronaldo 900 messi 800 c-ronaldo 600 kaka (integer) 4 127.0.0.1:6379> zrange player:rank 0 -1 1) "kaka" 2) "c-ronaldo" 3) "messi" 4) "ronaldo" 127.0.0.1:6379> zcount player:rank 700 901 (integer) 2 127.0.0.1:6379> zrangebyscore player:rank 700 901 1) "c-ronaldo" 2) "messi" 127.0.0.1:6379> zremrangebyrank player:rank 0 1 (integer) 2 127.0.0.1:6379> zrange player:rank 0 -1 1) "messi" 2) "ronaldo" 127.0.0.1:6379> zrange player:rank 0 -1 withscores 1) "messi" 2) "900" 3) "ronaldo" 4) "1000"
API查漏補缺
zset總結
操做類型 | 命令 |
---|---|
基本操做 | zadd zrem zcard zincrby zscore |
範圍操做 | zrange zrangebyscore zcount zremrangebyrank |
集合操做 | zunionstore zinterstore |
Redis開源客戶端涵蓋各類語言:
這裏主要詳細介紹下Redis的Java開源客戶端工具Jedis的使用
獲取jedis
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> <type>jar</type> <scope>compile</scope> </dependency>
jedis直連
Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.set("hello", "world"); String value = jedis.get("hello");
Jedis構造函數
Jedis(String host, int port, int connectionTimeout, int soTimeout)
這裏只列了經常使用參數,其餘像密碼,或基於安全的SSL,用到的時候自行查閱便可。
簡單使用
// 1. string jedis.set("hello", world); // OK jedis.get("hello"); // "world" jedis.incr("counter"); // 1
// 2. hash jedis.hset("myhash", "f1", "v1"); jedis.hset("myhash", "f2", "v2"); jedis.hgetAll("myhash"); // {f1=v1, f2=v2}
// 3. list jedis.rpush("mylist", 1); jedis.rpush("mylist", 2); jedis.rpush("mylist", 3); jedis.lrange("mylist", 0, -1); // [1, 2, 3]
// 4. set jedis.sadd("myset", "a"); jedis.sadd("myset", "b"); jedis.sadd("myset", "a"); jedis.smembers("myset"); // [b, a]
// 5. zset jedis.zadd("myzset", 99, "tom"); jedis.zadd("myzset", 66, "peter"); jedis.zadd("myzset", 33, "james"); jedis.zrangeWithScores("myzset", 0, -1); // [[["james"], 33.0], [["peter"], 66.0], [["tom"], 99.0]]
Jedis鏈接池
GenericObjectPoolConfig poolConfig = new GenericObjectPollConfig(); JedisPool jedisPool = new JedisPool(poolConfig, "127.0.0.1", 6379);
Jedis jedis = null; try { // 1. 從鏈接池獲取Jedis對象 jedisPool.getResource(); // 2. 執行操做 jedis.set("hello", "world"); } catch(Exception e) { e.printStackTrace(); } finally { if (jedis != null) { // 3. 若是使用JedisPool,close操做不是關閉鏈接,而是歸還鏈接池 jedis.close(); } }