redis總結(jié)

Redis

如何開啟暂衡、關閉惩歉、連接

linux常規(guī)命令開關

yum安裝gcc-c++環(huán)境

yum install gcc-c++

自動配置文件

make

確認是否全部安裝激率,沒安裝的再次安裝

make install

啟動

cd src
./redis-server

可根據(jù)配置文件啟動

/www/server/redis/redis.conf

寶塔Linux面板命令開關

redis安裝目錄

/www/server/redis

啟動

/etc/init.d/redis start

停止

/etc/init.d/redis stop

redis配置文件目錄

/www/server/redis/redis.conf

連接

/www/server/redis/src/redis-cli

redis-benchmark 壓力測試

cd src
./redis-benchmark [options]

參數(shù)列表.png
壓測結(jié)果.png
基礎知識

redis一共有16個數(shù)據(jù)庫娄帖,默認使用第1個

select [index] #切換數(shù)據(jù)庫
flushdb  #清空當前數(shù)據(jù)庫
flushall #清空所有數(shù)據(jù)庫
keys * #查看當前數(shù)據(jù)庫的所有KV

為什么redis是單線程還快

Redis是基于內(nèi)存的操作,CPU不是Redis的瓶頸插龄,Redis的瓶頸最有可能是機器內(nèi)存的大小或者網(wǎng)絡帶寬愿棋。既然單線程容易實現(xiàn),而且CPU不會成為瓶頸均牢,那就順理成章地采用單線程的方案了糠雨。

1.redis是基于內(nèi)存的,內(nèi)存的讀寫速度非撑枪颍快
2.redis是單線程的甘邀,省去了很多上下文切換線程的時間
3.redis使用多路復用技術琅攘,可以處理并發(fā)的連接。非阻塞IO 內(nèi)部實現(xiàn)采用epoll松邪,采用了epoll+自己實現(xiàn)的簡單的事件框架坞琴。epoll中的讀、寫测摔、關閉置济、連接都轉(zhuǎn)化成了事件解恰,然后利用epoll的多路復用特性锋八,絕不在io上浪費一點時間。
https://zhuanlan.zhihu.com/p/58038188

五大數(shù)據(jù)類型

Redis-key

127.0.0.1:6379> flushall #清除所有數(shù)據(jù)庫的緩存
OK
127.0.0.1:6379> flushdb #清除當前數(shù)據(jù)庫的緩存
OK
127.0.0.1:6379> set name pang #設置key-value為name-pang
OK
127.0.0.1:6379> keys * #查詢所以的key
1) "name"
127.0.0.1:6379> set age 18 
OK
127.0.0.1:6379> get name #獲取key為name的value
"pang"
127.0.0.1:6379> expire name 10 #設置name的過期時間為10s
(integer) 1
127.0.0.1:6379> ttl name #查看剩余的有效時間
(integer) 3
127.0.0.1:6379> ttl name #過期的話剩余時間為-2
(integer) -2
127.0.0.1:6379> exists name age #查看name和age是否存在
(integer) 1 #存在數(shù)量為1
127.0.0.1:6379> exists name #查看name是否存在
(integer) 0 #不存在
127.0.0.1:6379> move age 1 #將age這個數(shù)據(jù)移動到1號數(shù)據(jù)庫里
(integer) 1
127.0.0.1:6379> select 1 #選擇數(shù)據(jù)庫1
OK
127.0.0.1:6379[1]> keys * #查看所以key
1) "age"

String類型

127.0.0.1:6379> set name pang #設置key-value為name-pang
OK
127.0.0.1:6379> type name #查看類型
string
127.0.0.1:6379> append key1 +hello #拼接字符串
(integer) 12 #長度為12
127.0.0.1:6379> get key1 
"value1+hello"
127.0.0.1:6379> strlen key1 #查看字符串長度
(integer) 12
127.0.0.1:6379> set views 0 #設置訪問量
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views #自減
(integer) 1
127.0.0.1:6379> incrby views 10 #自增步長為10
(integer) 11
127.0.0.1:6379> decrby views 5 #自減步長為5
(integer) 6
127.0.0.1:6379> set name1 "hello,pang" 
OK
127.0.0.1:6379> getrange name1 0 5 #查看下標0到5的值
"hello,"
127.0.0.1:6379> getrange name1 0 -1 #查看全部
"hello,pang"
127.0.0.1:6379> setrange name1 5 haha #將name1的下標5之后的值覆蓋為haha [5,~
(integer) 10
127.0.0.1:6379> get name1
"hellohahag"
127.0.0.1:6379> setex name1 10 zheng #name1存在設置失效時間為10s并且值為zheng
OK
127.0.0.1:6379> ttl name1 
(integer) 5
127.0.0.1:6379> ttl name1
(integer) 3
127.0.0.1:6379> ttl name1
(integer) -2
127.0.0.1:6379> setnx name1 pang #如果不存在則設置name1的值為pang
(integer) 1
127.0.0.1:6379> get name1
"pang"
127.0.0.1:6379> mset name2 pang age2 18 #設置多值
OK
127.0.0.1:6379> mget name2 age2 #獲取多值
1) "pang"
2) "18"
127.0.0.1:6379> msetnx name3 hahah3 age3 didi3 #不存在設置多值
(integer) 1
127.0.0.1:6379> keys *
1) "name3"
2) "key1"
3) "age3"
4) "name1"
5) "views"
6) "age2"
7) "name2"
8) "name"
127.0.0.1:6379> set user:1 {name:pang,age:18} #存儲對象
OK
127.0.0.1:6379> get user:1
"{name:pang,age:18}"
127.0.0.1:6379> getset name1 yang #先取舊值再設置新值
"pang"

使用場景

  • 計數(shù)器 incrby
  • 統(tǒng)計多單位的數(shù)量 uid:43241:follow 0 有人關注就inrc 取關就decr
  • 粉絲數(shù)
  • 對象緩存

List(列表)

127.0.0.1:6379> lpush mylist 1 2 3 4 #lpush:往左邊插入
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1 
1) "4"
2) "3"
3) "2"
4) "1"
127.0.0.1:6379> lrange mylist 0 2
1) "4"
2) "3"
3) "2"
127.0.0.1:6379> rpush mylist 5 #rpush:往右邊插入
(integer) 5
127.0.0.1:6379> rpush mylist 6
(integer) 6
127.0.0.1:6379> lrange mylist 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "5"
6) "6"
127.0.0.1:6379> lpop mylist 1 #lpop:刪除left前1個數(shù)據(jù)
1) "4"
127.0.0.1:6379> rpop mylist 2 #rpop:刪除right前2個數(shù)據(jù)
1) "6"
2) "5"
127.0.0.1:6379> lrange mylist 0 -1
1) "3"
2) "2"
3) "1"
127.0.0.1:6379> lindex mylist 0 #lindex:查看左邊下標為0的數(shù)據(jù)
"3"
127.0.0.1:6379> lindex mylist 1
"2"
127.0.0.1:6379> llen mylist #llen:查看長度
(integer) 3
127.0.0.1:6379> lpush mylist 1 1 1 1 1 
(integer) 8
127.0.0.1:6379> lrange mylist 0 -1
1) "1"
2) "1"
3) "1"
4) "1"
5) "1"
6) "3"
7) "2"
8) "1"
127.0.0.1:6379> lrem mylist 3 1 #lrem:刪除3個1
(integer) 3
127.0.0.1:6379> rpush list2 one two three four five six 
(integer) 6
127.0.0.1:6379> lrange list2 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
5) "five"
6) "six"
127.0.0.1:6379> ltrim list2 1 2 #ltrim:截取成下標1和小標2的數(shù)據(jù)
OK
127.0.0.1:6379> lrange list2 0 -1
1) "two"
2) "three"
127.0.0.1:6379> linsert list2 after "three"  "four" #linsert:在three的after添加four
(integer) 3
127.0.0.1:6379> lrange list2 0 -1
1) "two"
2) "three"
3) "four"
127.0.0.1:6379> linsert list2 before "two"  "one" #在two的before添加one
(integer) 4

小結(jié)

  • 實際上是一個鏈表护盈,before after 挟纱,left right 都可以插入
  • 如果key不存在創(chuàng)建新鏈表
  • 如果key存在則新增內(nèi)容
  • 在兩邊插入或改動效率最高!

可用于消息隊列(lpush rpop)腐宋,棧(lpush lpop)

Set(集合)

無序不重復

127.0.0.1:6379> sadd myset "i" "love" "yang" #sadd:添加元素
(integer) 3
127.0.0.1:6379> sismember myset love #sismember:查看是否是集合內(nèi)元素
(integer) 1
127.0.0.1:6379> sismember myset pang
(integer) 0
127.0.0.1:6379> smembers myset #smembers:查看集合所有元素
1) "love"
2) "i"
3) "yang"
127.0.0.1:6379> scard myset #scard:查看集合元素個數(shù)
(integer) 3
127.0.0.1:6379> srem myset i #srem:刪除集合元素
(integer) 1
127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379> sadd myset pang wang li zhang
(integer) 4
127.0.0.1:6379> smembers myset 
1) "love"
2) "li"
3) "pang"
4) "zhang"
5) "wang"
6) "yang"
127.0.0.1:6379> srandmember myset 1 #srandmember:隨機取1個值
1) "zhang"
127.0.0.1:6379> srandmember myset 1
1) "pang"
127.0.0.1:6379> srandmember myset 1
1) "li"
127.0.0.1:6379> spop myset 1 #spop:隨機彈出1個值
1) "love"
127.0.0.1:6379> smembers myset
1) "li"
2) "pang"
3) "zhang"
4) "wang"
5) "yang"
127.0.0.1:6379> smove myset myset2 li #smove:移動元素去其他集合
(integer) 1
127.0.0.1:6379> smembers myset2
1) "li"
127.0.0.1:6379> sadd myset2 pang tao lv wang
(integer) 4
127.0.0.1:6379> sdiff myset myset2 #sdiff:差集
1) "zhang"
2) "yang"
127.0.0.1:6379> sinter myset myset2 #sinter:交集
1) "pang"
2) "wang"
127.0.0.1:6379> sunion myset myset2 #sunion:并集
1) "lv"
2) "li"
3) "tao"
4) "pang"
5) "wang"
6) "zhang"
7) "yang"

用法:

  • 共同關注紊服,共同好友,六度分割理論

Hash (哈希)

127.0.0.1:6379> hset myhash field1 value1 field2 value2 #hset:設值
(integer) 2
127.0.0.1:6379> hget myhash field1 #hget:取值
"value1"
127.0.0.1:6379> hget myhash field2
"value2"
127.0.0.1:6379> hgetall myhash #hgetall:取所有的值
1) "field1"
2) "value1"
3) "field2"
4) "value2"
127.0.0.1:6379> hdel myhash field1 #hdel:刪除值
(integer) 1
127.0.0.1:6379> hlen myhash #hlen:查看個數(shù)
(integer) 1
127.0.0.1:6379> hexists myhash field1 #hexists:是否存在
(integer) 0
127.0.0.1:6379> hexists myhash field2
(integer) 1
127.0.0.1:6379> hkeys myhash #hkeys:查看所以keys
1) "field2"
2) "field3"
3) "field4"
127.0.0.1:6379> hsetnx myhash field0 10 #hsetex胸竞,hsetnx:存在或不存在則設值
(integer) 1
127.0.0.1:6379> hincrby myhash field0 10 #hincrby:自增
(integer) 20
#########
127.0.0.1:6379> hset user:1 name zhangsan age 18 #存入對象user:1 
(integer) 2
127.0.0.1:6379> hgetall user:1
1) "name"
2) "zhangsan"
3) "age"
4) "18"

hash更適合儲存對象

Zset(有序集合)

類似于set只是在set的key-value之間加了一個數(shù)量 key-score-value

127.0.0.1:6379> zadd salary 2500 zhangsan #zadd:添加值
(integer) 1
127.0.0.1:6379> zadd salary 1000 lisi
(integer) 1
127.0.0.1:6379> zadd salary 2000 wangwu
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf #zrangebyscore:升序排序
1) "lisi"
2) "wangwu"
3) "zhangsan"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #帶上score [withscores]
1) "lisi"
2) "1000"
3) "wangwu"
4) "2000"
5) "zhangsan"
6) "2500"
127.0.0.1:6379> zcard salary #zcard:查看個數(shù)
(integer) 3
127.0.0.1:6379> zrevrange salary 0 -1 withscores #zrevrange:降序
1) "zhangsan"
2) "2500"
3) "wangwu"
4) "2000"
5) "lisi"
6) "1000"
127.0.0.1:6379> zcount salary 1000 2500 #在score在[1000,2500]區(qū)間的數(shù)據(jù)個數(shù)
(integer) 3
127.0.0.1:6379> zcount salary 1001 2499
(integer) 1

使用:

  • 儲存成績表啊欺嗤,工資表啊
  • 排行榜

三大特殊數(shù)據(jù)類型

geospatial地理位置

geoadd

127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
(integer) 1

geopos

127.0.0.1:6379> geopos china:city beijing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"

geodist 兩地距離

127.0.0.1:6379> geodist china:city beijing shanghai km
"1067.3788"

georadius 以經(jīng)緯度為中心搜索范圍內(nèi)的位置

127.0.0.1:6379> georadius china:city 115 39 1000 km  #經(jīng)緯115 39為中心1000km內(nèi)的位置
1) "beijing"
127.0.0.1:6379> georadius china:city 115 39 1000 km withdist #顯示到中心點區(qū)域和距離
1) 1) "beijing"
   2) "156.4529"
127.0.0.1:6379> georadius china:city 115 39 1000 km withcoord #顯示范圍內(nèi)的城市信息
1) 1) "beijing"
   2) 1) "116.39999896287918091"
      2) "39.90000009167092543"
127.0.0.1:6379> georadius china:city 115 39 1000 km withcoord  count 1 #顯示范圍內(nèi)的城市信息限定數(shù)量1個
1) 1) "beijing"
   2) 1) "116.39999896287918091"
      2) "39.90000009167092543"

georadiusbymember 顯示以北京為中心10000 km內(nèi)的城市名字

127.0.0.1:6379> georadiusbymember china:city beijing 10000 km
1) "hangzhou"
2) "shanghai"
3) "beijing"

底層基于zset

127.0.0.1:6379> zrange china:city 0 -1
1) "hangzhou"
2) "shanghai"
3) "beijing"
127.0.0.1:6379> zrem china:city beijing #移除元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "hangzhou"
2) "shanghai"

Hyperloglog

簡介

Redis2.8.9更新的Hyperloglog數(shù)據(jù)結(jié)構
技術統(tǒng)計算法

優(yōu)點:占用內(nèi)存是固定的,2^64不同的元素卫枝,只需占12kb煎饼。比起用set存儲,大大節(jié)省內(nèi)存校赤。
不過有0.81% 的錯誤率

使用

127.0.0.1:6379> pfadd k1 9 8 4 9 7 3 3 5 4 #添加k1
(integer) 1
127.0.0.1:6379> pfadd k2 1 5 1 5 0 6 7 1 4 6 6 #添加k2
(integer) 1
127.0.0.1:6379> pfcount k1 #查詢k1吆玖,注意不可重復
(integer) 6
127.0.0.1:6379> pfcount k2 #查詢k2,注意不可重復
(integer) 6
127.0.0.1:6379> pfmerge k3 k1 k2 #k1和k2的并集马篮,存于k3
OK
127.0.0.1:6379> pfcount k3
(integer) 9

bitmaps

優(yōu)點:在儲存方面使用0或者1二進制位沾乘,可用于上班打卡這類只存在兩種結(jié)果的事情上

127.0.0.1:6379>  setbit daka 0 1 #設置打卡1代表打卡0代表沒打卡
(integer) 0
127.0.0.1:6379>  setbit daka 1 0 #bit位1的位置為0
(integer) 1
127.0.0.1:6379>  setbit daka 2 0 #bit位2的位置為0
(integer) 0
127.0.0.1:6379>  setbit daka 3 0 #...
(integer) 0
127.0.0.1:6379>  setbit daka 4 1
(integer) 0
127.0.0.1:6379>  setbit daka 5 1
(integer) 0
127.0.0.1:6379>  setbit daka 6 1
(integer) 0
127.0.0.1:6379> bitcount daka [start end]#統(tǒng)計打卡天數(shù),可加其實和結(jié)束
(integer) 4

redis的setbit設置或清除的是bit位置,而bitcount計算的是byte位置
start 和 end 參數(shù)的設置浑测,都可以使用負數(shù)值:比如 -1 表示最后一個位翅阵,而 -2 表示倒數(shù)第二個位。
https://www.cnblogs.com/song27/p/12329554.html

事務

redis的事務不保證原子性迁央,所謂原子性就是要成功都成功掷匠,一個失敗全部失敗。redis的事務類似于隊列漱贱,先進的先出槐雾,后進的后出!

redis事務流程

  • 開啟事務 multi
  • 命令入隊 .....
  • 執(zhí)行事務 exec

執(zhí)行事務

127.0.0.1:6379> multi #開啟事務
OK
#命令入隊
127.0.0.1:6379(TX)> set key1 value1 
QUEUED
127.0.0.1:6379(TX)> set key2 value2
QUEUED
127.0.0.1:6379(TX)> get key1
QUEUED
127.0.0.1:6379(TX)> get key2
QUEUED
127.0.0.1:6379(TX)> exec #執(zhí)行事務
1) OK #set key1 value1 
2) OK #set key2 value2
3) "value1" #get key1
4) "value2" #get key2

放棄事務

127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379(TX)> set key1 value1#設值
QUEUED
127.0.0.1:6379(TX)> discard #放棄事務
OK
127.0.0.1:6379> get key1 #無法查到值
(nil)

編譯時異常(錯誤命令)

127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379(TX)> set key1 value1 #設值
QUEUED
127.0.0.1:6379(TX)> getxxx hahaha #輸入錯誤命令幅狮,觸發(fā)編譯時異常
(error) ERR unknown command `getxxx`, with args beginning with: `hahaha`,
127.0.0.1:6379(TX)> exec #執(zhí)行事務
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get key1 #發(fā)現(xiàn)無法取到key1的值募强,說明事務內(nèi)發(fā)生編譯時異常株灸,則全部命令都不會執(zhí)行
(nil)

運行時異常

127.0.0.1:6379> set name "pxm" #設值
OK
127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379(TX)> set key1 value1 #設值key1
QUEUED
127.0.0.1:6379(TX)> incr name #制造運行時異常,因為字符串非數(shù)字不能自增
QUEUED
127.0.0.1:6379(TX)> set key2 value2 #設值key2
QUEUED
127.0.0.1:6379(TX)> exec #執(zhí)行事務
1) OK #set key1 value1執(zhí)行成功
2) (error) ERR value is not an integer or out of range #incr name執(zhí)行失敗
3) OK #set key2 value2執(zhí)行成功
127.0.0.1:6379> mget key1 key2 #獲取key1 key2成功擎值,事務內(nèi)說明運行時異常發(fā)生只會影響此異常命令
1) "value1"
2) "value2"

監(jiān)控

樂觀鎖:什么時候出現(xiàn)問題什么時候加鎖 攜帶版本號進行比較

悲觀鎖:無論什么時候都會加鎖慌烧,例如java里的sychoinized

使用watch進行監(jiān)控:

正常情況

127.0.0.1:6379> set inmoney 1000 #設置進賬1000
OK
127.0.0.1:6379> set outmoney 1000 #設置出賬1000
OK
127.0.0.1:6379> watch inmoney #監(jiān)控入賬
OK
127.0.0.1:6379> multi #開啟事務
OK
127.0.0.1:6379(TX)> incrby inmoney 200 #進賬增200
QUEUED
127.0.0.1:6379(TX)> decrby outmoney 200#出賬減200
QUEUED
127.0.0.1:6379(TX)> exec #執(zhí)行事務(成功)
1) (integer) 1200
2) (integer) 800

監(jiān)控中被他線程修改,使用watch當做樂觀鎖

127.0.0.1:6379> mget inmoney outmoney
1) "1200"
2) "800"
127.0.0.1:6379> watch inmoney #使用watch監(jiān)控鸠儿,當做樂觀鎖
OK
127.0.0.1:6379> multi 
OK
127.0.0.1:6379(TX)> incrby inmoney 200
QUEUED
127.0.0.1:6379(TX)> decrby outmoney 200
QUEUED
127.0.0.1:6379(TX)> exec #由于監(jiān)控期間他線程修改了inmoney的值屹蚊,導致觸發(fā)樂觀鎖,事務失敗
(nil)

解決方法

127.0.0.1:6379> unwatch #使用unwatch 解綁所有的監(jiān)控
OK
127.0.0.1:6379> watch inmoney #再次使用watch綁定进每,確保監(jiān)控的為最新的值
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby inmoney 200
QUEUED
127.0.0.1:6379(TX)> decrby outmoney 200
QUEUED
127.0.0.1:6379(TX)> exec #執(zhí)行事務時汹粤,先對比監(jiān)控的值是否發(fā)生改變,如果沒有則執(zhí)行成功田晚,改變了則失敗嘱兼,則再解綁重綁
1) (integer) 2600
2) (integer) 400

jedis

使用java操作redis的中間件

  1. 導入依賴

    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>3.2.0</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.51</version>
    </dependency>
    
  2. 使用

    Jedis jedis = new Jedis("47.99.171.23", 6379);//連接遠程需要打開安全組防火墻和修改配置文件
            jedis.flushDB();
            ....
    

    遠程redis連接:https://blog.csdn.net/weixin_44502804/article/details/90044682

Spring-boot整合

springboot操作數(shù)據(jù):spring-data jpa jdbc redis!

springdata也是和springboot其名的項目

為啥springboot2.x后使用lettuce而舍棄jedis

jedis:采用直連技術贤徒,多線程操作是不安全的芹壕,需要使用jedis pool褂删。更像BIO模式

lettuce:采用netty铺敌,實例可以多個線程中共享,不存在線程安全問題攘残,更像NIO模式

redis自動配置類源碼分析:

@Bean
    @ConditionalOnMissingBean(name = "redisTemplate")//如果沒有redisTemplate的類才執(zhí)行序宦,說明我們可以自定義
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();// 泛型為object使用的時候需要轉(zhuǎn)向
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnSingleCandidate(RedisConnectionFactory.class)
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

整合測試

1 導入依賴

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

2 配置連接測試

配置redis

image.png
@SpringBootTest
class SpringbootRedisApplicationTests {

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("myKey","myValue");
        System.out.println(redisTemplate.opsForValue().get("myKey"));
    }

}

重寫自動配置類

由于redis的自動配置類太low了睁壁,另外在傳json數(shù)據(jù)時需要序列化,所以我們自定義自動配置類

@Configuration
public class RedisConfig {

  @Bean
  @SuppressWarnings("all")
  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
      RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
      template.setConnectionFactory(factory);
      Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
      ObjectMapper om = new ObjectMapper();
      om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
      jackson2JsonRedisSerializer.setObjectMapper(om);
      StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

      // key采用String的序列化方式
      template.setKeySerializer(stringRedisSerializer);
      // hash的key也采用String的序列化方式
      template.setHashKeySerializer(stringRedisSerializer);
      // value序列化方式采用jackson
      template.setValueSerializer(jackson2JsonRedisSerializer);
      // hash的value序列化方式采用jackson
      template.setHashValueSerializer(jackson2JsonRedisSerializer);
      template.afterPropertiesSet();
      return template;
  }


}

重寫工具類

抽取常用方法

代碼參考「redis-study」

Redis.conf配置文件

INCLUDES 包含

# include /path/to/local.conf
# include /path/to/other.conf

可以導入其他配置文件

NETWORK 網(wǎng)絡

bind 127.0.0.1
protected-mode no
port 6379

GENERAL

daemonize yes #是否以守護進程的方式運行挨厚,默認no堡僻,我們要開啟yes,即后臺運行
pidfile /www/server/redis/redis.pid 
#如果指定了pid文件疫剃,Redis會在啟動時指定的地方寫入pid文件
#并在退出時刪除它钉疫。
#當服務器運行非守護時,如果沒有pid文件巢价,則不創(chuàng)建pid文件
#在配置中指定牲阁。當服務器被守護時,pid文件
#被使用壤躲,即使沒有指定城菊,默認為"/var/run/redis.pid"。
#創(chuàng)建一個pid文件是最好的努力:如果Redis不能創(chuàng)建它
#沒有壞的事情發(fā)生碉克,服務器將正常啟動和運行凌唬。
logfile "/www/server/redis/redis.log"
databases 16
always-show-logo yes #就是啟動時像漢堡一樣的東西哈哈

SNAPSHOTTING 快照

持久化,在規(guī)定的時間內(nèi)漏麦,執(zhí)行多少次操作的話客税,則會持久化到文件
沒有持久化的話况褪,數(shù)據(jù)斷點即失

save 900 1 #900s 至少一個key修改了則持久化操作
save 300 10 #...
save 60 10000 #...
stop-writes-on-bgsave-error yes #持久化出錯是否繼續(xù)工作
rdbcompression yes#是否壓縮rdb
rdbchecksum yes #是否檢查rdb
dbfilename dump.rdb #rdb文件名
dir /www/server/redis/ #儲存位置

REPLICATION 復制

replicaof <masterip> <masterport> #配置主機的地址和端口
masterauth <master-password> #主機若有密碼配置密碼

SECURITY 安全

設置密碼可以在配置文件里設置,也可以直接命令行設置

config get requirepass #查看密碼
config set requirepass#設置密碼
auth xxxxx #輸入密碼

CLIENTS 客戶端

# maxclients 10000  #默認最大連接1w臺

MEMORY MANAGEMENT 內(nèi)存管理

# MAXMEMORY POLICY 內(nèi)存達到上限的解決策略
noeviction #不刪除策略, 達到最大內(nèi)存限制時, 如果需要更多內(nèi)存, 直接返回錯誤信息更耻。(默認值)
allkeys-lru  #所有key通用; 優(yōu)先刪除最近最少使用(less recently used ,LRU) 的 key测垛。
volatile-lru  #只限于設置了 expire 的部分; 優(yōu)先刪除最近最少使用(less recently used ,LRU) 的 key。
allkeys-random #所有key通用; 隨機刪除一部分 key秧均。
volatile-random  #只限于設置了 expire 的部分; 隨機刪除一部分 key食侮。
volatile-ttl #只限于設置了 expire 的部分; 優(yōu)先刪除剩余時間(time to live,TTL) 短的key。

APPEND ONLY MODE aof配置

appendonly no #默認不開啟aof模式目胡,默認使用rdb方式持久化
appendfilename "appendonly.aof" #aof文件名

# appendfsync always #每次修改都會sync
appendfsync everysec #每秒都sync锯七,可能會丟失1s的數(shù)據(jù)
# appendfsync no #不執(zhí)行sync,這個時候操作系統(tǒng)自己同步讶隐,速度最快

redis持久化

RDB(Redis DataBase)

RDB其實就是把數(shù)據(jù)以快照的形式保存在磁盤上起胰。什么是快照呢久又,你可以理解成把當前時刻的數(shù)據(jù)拍成一張照片保存下來巫延。
RDB持久化是指在指定的時間間隔內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫入磁盤。也是默認的持久化方式地消,這種方式是就是將內(nèi)存中數(shù)據(jù)以快照的方式寫入到二進制文件中,默認的文件名為dump.rdb炉峰。

既然RDB機制是通過把某個時刻的所有數(shù)據(jù)生成一個快照來保存,那么就應該有一種觸發(fā)機制脉执,是實現(xiàn)這個過程疼阔。對于RDB來說,提供了2種機制:save半夷、bgsave(默認)我們分別來看一下

  • save
save流程圖

該命令會阻塞當前Redis服務器婆廊,執(zhí)行save命令期間,Redis不能處理其他命令巫橄,直到RDB過程完成為止淘邻,執(zhí)行完成時候如果存在老的RDB文件,就把新的替代掉舊的湘换。我們的客戶端可能都是幾萬或者是幾十萬宾舅,這種方式顯然不可取。

  • bgsave(默認)

執(zhí)行該命令時彩倚,Redis會在后臺異步進行快照操作筹我,快照同時還可以響應客戶端請求。具體流程如下帆离。具體操作是Redis進程執(zhí)行fork操作創(chuàng)建子進程蔬蕊,RDB持久化過程由子進程負責,完成后自動結(jié)束哥谷。阻塞只發(fā)生在fork階段岸夯,一般時間很短概而。基本上 Redis 內(nèi)部所有的RDB操作都是采用 bgsave 命令

bgsave流程圖

在配置文件可以修改save參數(shù)囱修,save 900 1 (900s 至少一個key修改了則持久化操作)赎瑰,則會生成dump.rdb文件用于持久化。

127.0.0.1:6379> config get dir  #rdb文件放在這就可以直接讀取恢復破镰,進行持久化
1) "dir"
2) "/www/server/redis"

rdb的優(yōu)缺點

  • 優(yōu)點
    1. 生成RDB文件的時候餐曼,redis主進程會fork()一個子進程來處理所有保存工作,主進程不需要進行任何磁盤IO操作
    2. RDB 在恢復大數(shù)據(jù)集時的速度比 AOF 的恢復速度要快
  • 缺點
    1. RDB快照是一次全量備份鲜漩,存儲的是內(nèi)存數(shù)據(jù)的二進制序列化形式源譬,存儲上非常緊湊。當進行快照持久化時孕似,會開啟一個子進程專門負責快照持久化踩娘,子進程會擁有父進程的內(nèi)存數(shù)據(jù),如果redis宕機了喉祭,最后一次的修改數(shù)據(jù)就沒了养渴。
    2. fork會消耗額外內(nèi)存

AOF(Append Only File)

全量備份總是耗時的,有時候我們提供一種更加高效的方式AOF泛烙,工作機制很簡單理卑,redis會將每一個收到的寫命令都通過write函數(shù)追加到文件中。通俗的理解就是日志記錄蔽氨。

appendonly no #默認不開啟aof模式藐唠,默認使用rdb方式持久化
appendfilename "appendonly.aof" #aof文件名

# appendfsync always #每次修改都會sync
appendfsync everysec #每秒都sync,可能會丟失1s的數(shù)據(jù)
# appendfsync no #不執(zhí)行sync鹉究,這個時候操作系統(tǒng)自己同步宇立,速度最快

AOP運行原理

通俗的說,就是每寫一條set命令自赔,就會追加到appendonly.aof文件中妈嘹,下次啟動時再次執(zhí)行只寫命令從而做到持久化操作。

數(shù)據(jù)修復

redis-check-aof --fix appendonly.aof

可以用于不小心輸入了flushall刪掉了所有緩存文件匿级,然后打開appendonly.aof刪掉保存的flushall命令后執(zhí)行恢復即可蟋滴。

AOP重寫

aof持久化策略是將Redis執(zhí)行的命令追加到一個文件之中,當Redis重啟時會加載這個文件依次重新執(zhí)行命令痘绎,以達到數(shù)據(jù)恢復的目的津函。但是隨著Redis的運行,aof文件之中會存在很多冗余的命令孤页,以及無效的命令(例如尔苦,先SET一個鍵,在將這個鍵刪除),這樣會導致aof文件過于龐大允坚,還原數(shù)據(jù)所需要的時間也會相應的增大魂那,因此在滿足一定條件的情況下,需要重寫aof文件稠项,將冗余的命令進行合并涯雅,同時將無效的命令進行刪除。

AOF的方式也同時帶來了另一個問題展运。持久化文件會變的越來越大活逆。為了壓縮aof的持久化文件。redis提供了bgrewriteaof命令拗胜。將內(nèi)存中的數(shù)據(jù)以命令的方式保存到臨時文件中蔗候,同時會fork出一條新進程來將文件重寫

AOF重寫

重寫aof文件的操作,并沒有讀取舊的aof文件埂软,而是將整個內(nèi)存中的數(shù)據(jù)庫內(nèi)容用命令的方式(因為可能會有很多無效命令例如锈遥,先SET一個鍵,在將這個鍵刪除)重寫了一個新的aof文件勘畔,這點和快照有點類似所灸。

重寫配置:

no-appendfsync-on-rewrite no #默認關閉

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb #舊文件達到64mb時重寫

AOF優(yōu)缺點

優(yōu)點

  1. AOF可以更好的保護數(shù)據(jù)不丟失,一般AOF會每隔1秒咖杂,最多丟失1秒鐘的數(shù)據(jù)庆寺。
  2. AOF日志文件即使過大的時候,出現(xiàn)后臺重寫操作诉字,也不會影響客戶端的讀寫

缺點:

  1. 對于同一份數(shù)據(jù)來說,AOF日志文件通常比RDB數(shù)據(jù)快照文件更大
  2. 進行數(shù)據(jù)恢復的時候知纷,沒有恢復一模一樣的數(shù)據(jù)出來壤圃。

AOF和RDB比較

AOF和RDB比較

[圖片上傳失敗...(image-4c3d8d-1630630196405)]

redis訂閱與發(fā)布

redis發(fā)布訂閱(pub/sub)是一種消息通信模式。

redis發(fā)布訂閱

測試

訂閱端:

127.0.0.1:6379> SUBSCRIBE channel1  #訂閱channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "hello world"
1) "message"
2) "channel1"
3) "hello redis"
^C
127.0.0.1:6379> UNSUBSCRIBE channel1 #退訂channel1
1) "unsubscribe"
2) "channel1"
3) (integer) 0

發(fā)送端:

127.0.0.1:6379> PUBLISH channel1 "hello world"  #在channel1發(fā)送消息
(integer) 1
127.0.0.1:6379> PUBLISH channel1 "hello redis"
(integer) 1

redis主從復制

未修改配置文件或者命令的機子會自動默認為master琅轧,修改文件的方法redis配置中已經(jīng)闡述伍绳,命令修改配置如下

注意:一臺linux上模擬1主2從復制時候需要修改配置文件的一下參數(shù):

  • port xxxx
  • pidfile /www/server/redis/redisxx.pid
  • logfile "/www/server/redis/redisxx.log"
  • dbfilename dumpxx.rdb

Slave0:

[root@pang ~]#  /www/server/redis/src/redis-server /root/myconfig/redis80.conf #指定配置文件啟動服務
[root@pang ~]# /www/server/redis/src/redis-cli -p 6380
127.0.0.1:6380> SLAVEOF 127.0.0.1 6379 #修改本機127.0.0.1的端口6379為次slave的master
OK
127.0.0.1:6380> info replication #查看復制的配置
# Replication
role:slave #此機為slave
master_host:127.0.0.1  #master主機為本機
master_port:6379 #主機端口為6379
...

Slave1

[root@pang ~]#  /www/server/redis/src/redis-server /root/myconfig/redis81.conf
[root@pang ~]# /www/server/redis/src/redis-cli -p 6381
127.0.0.1:6381> slaveof 127.0.0.1 6379
OK
127.0.0.1:6381> info replication #查看復制的配置
# Replication
role:slave #此機為slave
master_host:127.0.0.1  #master主機為本機
master_port:6379 #主機端口為6379
...

master:

[root@pang src]# /www/server/redis/src/redis-server /root/myconfig/redis79.conf
[root@pang src]# /www/server/redis/src/redis-cli -p 6379
127.0.0.1:6379> info replication #查看復制配置
# Replication
role:master #角色為master
connected_slaves:2 #賬下的叢集數(shù)2
slave0:ip=127.0.0.1,port=6381,state=wait_bgsave,offset=0,lag=0 #slave0信息
slave1:ip=127.0.0.1,port=6380,state=wait_bgsave,offset=0,lag=0 #slave1信息
master_failover_state:no-failover
...

細節(jié)

master可以寫,slave只能讀乍桂。

主機斷開連接冲杀,從機依舊在綁定著主機,主機重新連接再寫入操作睹酌,從機依舊可以獲取主機上的信息

命令綁定主機master是一次性的权谁,關閉連接了就復原了,如果每次開啟服務都綁定master則需要在配置文件里修改replication下的參數(shù)憋沿。

復制原理

slave啟動連接到master會發(fā)送一個sync的同步命令
master接到命令后旺芽,啟動后臺存盤進程,同時收集所有修改數(shù)據(jù)的命令,在后臺進程執(zhí)行之后采章,master將傳送整個數(shù)據(jù)文件到slave运嗜,并完成一次同步。

全量復制:slave服務器在接收到數(shù)據(jù)庫文件數(shù)據(jù)之后悯舟,將其存盤并加載到內(nèi)存中担租。

增量復制:master繼續(xù)將新的所有的收集到的修改數(shù)據(jù)命令依次傳給slave,完成同步抵怎。

但是 只要重新連接master翩活,一次完全同步(全量復制)將別自動執(zhí)行,數(shù)據(jù)肯定可以在slave中看到便贵。

毛毛蟲式主從復制

毛毛蟲式主從復制

如果master宕機菠镇,下面的slave遍可以謀朝篡位

12.0.0.1:6381> slaveof no one #此時6381端口的slave謀朝篡位編程master

即使79端口的master恢復連接也無法再次成為master

當然真正開發(fā)當中不使用普通的主從復制模式,而是使用以下的哨兵模式承璃。

redis哨兵模式(自動選舉master)

概述

當我們主服務器宕機后利耍,需要手動把一臺從服務器切換成中服務器,需要人工干預盔粹,費事費力隘梨,還會造成一段時間內(nèi)服務器不可用。所以說會優(yōu)先使用哨兵模式舷嗡,通過sentinel(哨兵)來解決問題轴猎。
謀朝篡位的自動版本,能夠根據(jù)后臺監(jiān)控主機故障进萄,如果主機故障了捻脖,會根據(jù)投票數(shù)自動將從機轉(zhuǎn)換為主機。
哨兵模式是一種特殊的模式中鼠,首先redis提供了哨兵的命令可婶,哨兵為一個獨立的進程,獨立運行援雇。原理是哨兵通過發(fā)生命令等待redis服務器響應矛渴,從而監(jiān)控運行的多個redis實力

redis哨兵模式

以防哨兵死亡惫搏,通常使用多個哨兵進行監(jiān)控具温。

redis哨兵模式

假設主服務器宕機,哨兵1會檢測這個結(jié)果筐赔,系統(tǒng)不會馬上進行failover(故障轉(zhuǎn)移)铣猩,僅僅是哨兵1主觀的認為服務器不可以,此現(xiàn)象稱為主觀下線川陆,當后面的服務器也檢測到主服務器不可用時剂习,并且數(shù)量達到一定值時蛮位,那么哨兵之間會進行一次投票,投票的結(jié)果由一個哨兵發(fā)起鳞绕,進行failover操作失仁。之后通過發(fā)布訂閱模式,讓各個哨兵切換監(jiān)控新的主機们何,稱為客觀下線萄焦。

測試

#配置端口 默認為26379
port 26379
#以守護進程模式啟動
daemonize yes
#日志文件名
logfile "sentinel_26379.log"
#存放備份文件以及日志等文件的目錄
dir "/opt/redis/data"
#監(jiān)控的IP 端口號 名稱 sentinel通過投票后認為mater宕機的數(shù)量,此處為至少2個,此配置最重要冤竹,其他可以沒有這個必須有
#mymaster為<master-name>隨便取
sentinel monitor mymaster 127.0.0.1 6379 2
#當在Redis實例中開啟了requirepass foobared授權密碼拂封,這樣所有連接Redis實例的客戶端都要提供密碼 
#設置哨兵sentinel連接主從的密碼,注意必須為主從設置一樣的驗證密碼
# sentinel auth-pass <master-name> <password>
#30秒ping不通主節(jié)點的信息鹦蠕,主觀認為master宕機
sentinel down-after-milliseconds mymaster 30000
#故障轉(zhuǎn)移后重新主從復制冒签,1表示串行,>1并行
sentinel parallel-syncs mymaster 1
#故障轉(zhuǎn)移開始钟病,三分鐘內(nèi)沒有完成萧恕,則認為轉(zhuǎn)移失敗
sentinel failover-timeout mymaster 180000
[root@pang ~]# redis-sentinel myconfig/sentinel.conf # 指定配置文件開啟哨兵

當監(jiān)視的master節(jié)點斷開,這時候會投票選舉一個slave成為新的master肠阱。當原先的master重新連接時票唆,會自動把它分配到新的master下當做slave。

哨兵模式的優(yōu)缺點

優(yōu)點:
1屹徘、哨兵集群走趋,基于主從復制模式,所有的主從配置優(yōu)點噪伊,它都有
2簿煌、主從可以切換,故障可以轉(zhuǎn)移酥宴,高可用性的系統(tǒng)
3啦吧、哨兵模式就是主從模式的升級,手動到自動拙寡,更加健壯
缺點:
1、Redis不好在線擴容的琳水,集群容量一旦到達上限肆糕,在線擴容就十分麻煩
2、哨兵模式的配置繁瑣

redis緩存穿透在孝、擊穿與雪崩

正常的緩存流程

正常的緩存流程

穿透

高并發(fā)訪問緩存和數(shù)據(jù)庫都沒有的數(shù)據(jù)诚啃,導致宕機。

穿透

解決方法:

  1. 布隆過濾器私沮。攔截不符合要求的請求
  2. 緩存空對象始赎,把空的對象寫進redis,避免直接訪問數(shù)據(jù)庫。

擊穿(高并發(fā)訪問單個key)

單個熱點key瞬間失效造垛,大量請求直接訪問數(shù)據(jù)庫魔招,雖數(shù)數(shù)據(jù)庫將此key寫回緩存時間很短,但時間再短五辽,還是有成千上百萬請求在這幾毫秒間直接訪問數(shù)據(jù)庫办斑,從而導致宕機。

擊穿

解決方法:

  1. 使用分布式鎖杆逗,在請求數(shù)據(jù)庫這一步上鎖乡翅,就只有一個線程可以搶到鎖訪問數(shù)據(jù)庫,同時讓其他線程睡幾毫秒罪郊,

    待數(shù)據(jù)庫寫回數(shù)據(jù)到redis蠕蚜,其他線程就可以直接從緩存里拿數(shù)據(jù)了。

雪崩

大量的redis緩存在同一時間全部失效(或redis宕機)悔橄,直接訪問數(shù)據(jù)庫導致宕機

例如雙11為了防止過多請求直接打到數(shù)據(jù)庫上靶累,提前將訪問量大的數(shù)據(jù)寫到redis緩存中,并設置3小時的失效時間橄维,當3小時過后的一瞬間尺铣,大量的數(shù)據(jù)(key)訪問數(shù)據(jù)庫,導致數(shù)據(jù)庫響應不及時宕機争舞。

雪崩

解決方法:

  1. 隨機設置緩存失效時間凛忿,不讓他們同一時間失效
  2. redis集群部署
  3. 用不讓key失效,或者通過定時任務在key失效前再次加載key進redis緩存

拓展

布隆過濾器

布隆過濾器會把一個數(shù)據(jù)通過hash算法竞川,把它所對應的bit數(shù)組下標存入1店溢。比如你好算出三個hash分別是357,則下標357則存入1委乌。查詢時通過下標357就可能知道此數(shù)據(jù)為你好床牧,為什么用可能,因為不同的數(shù)據(jù)完全可以擁有相同的hash值遭贸。所以布隆過濾器不便于刪除操作戈咳,因為可能會誤刪相同hash的其他數(shù)據(jù)。

布隆過濾器

這里為什么是通過3個hash不是5個不是10個以下慢慢做出解釋壕吹。
首先布隆過濾器存在一個很大的缺點就是會誤判著蛙!誤判的原因很簡單,因為不同的數(shù)據(jù)會算出不同的hash耳贬,對應下標也相同踏堡。比如你好和hello算出的hash都是2,在查詢hello是否存在的時候需查詢下標2咒劲,發(fā)現(xiàn)下標2有數(shù)據(jù)(因為為1不為0)顷蟆,則判斷hello是存在的诫隅。其實下標2存入的是你好不是hello,這時就發(fā)生了誤判帐偎。

布隆過濾器

源碼解析:

public void test2() {
        int size = 100000;//預計存入10w個數(shù)據(jù)
        double fpp = 0.03;//誤判率為3%
        int count = 0;
        BloomFilter<Integer> filter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);
        for (int i = 0; i < size; i++) {
            filter.put(i);
        }
        for (int i = 0; i < size + 10000; i++) {
            if (!filter.test(i)) {
                System.out.println(i + "==》不在filter里");
                count++;
            }
        }
        System.out.println("誤判個數(shù)=》" + (10000 - count));//誤判個數(shù)=》286
    }

那是不是誤判率越低越好呢逐纬?

誤判率0.01和0.03對比發(fā)現(xiàn):

誤判率越低,所需要的hash函數(shù)就越多肮街,帶來的性能消耗也會越大风题,所以并非誤判率越低越好。

image.png

redis如何使用布隆過濾器防止穿透:

Config config = new Config();//配置文件
config.useSingleServer().setAddress("127.0.0.1");//設置服務器地址
config.useSingleServer().setPassword("123455");//密碼
RedissonClient redissonClient = Redisson.create(config);//創(chuàng)建redission
//通過redission創(chuàng)建布隆過濾器嫉父,起名為myFilter
RBloomFilter<Object> myFilter = redissonClient.getBloomFilter("myFilter");
// 設置過濾樣本數(shù)量沛硅,以及誤判率
myFilter.tryInit(1000000L, 0.03);
//添加數(shù)據(jù)進過濾器
myFilter.add("10086");
//返回為true
System.out.println(myFilter.contains(10086));
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绕辖,隨后出現(xiàn)的幾起案子摇肌,更是在濱河造成了極大的恐慌,老刑警劉巖仪际,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件围小,死亡現(xiàn)場離奇詭異,居然都是意外死亡树碱,警方通過查閱死者的電腦和手機肯适,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來成榜,“玉大人框舔,你說我怎么就攤上這事∈昊椋” “怎么了刘绣?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長挣输。 經(jīng)常有香客問我纬凤,道長,這世上最難降的妖魔是什么撩嚼? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任停士,我火速辦了婚禮,結(jié)果婚禮上完丽,老公的妹妹穿的比我還像新娘向瓷。我一直安慰自己,他們只是感情好舰涌,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著你稚,像睡著了一般瓷耙。 火紅的嫁衣襯著肌膚如雪朱躺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天搁痛,我揣著相機與錄音长搀,去河邊找鬼。 笑死鸡典,一個胖子當著我的面吹牛源请,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播彻况,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼谁尸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了纽甘?” 一聲冷哼從身側(cè)響起良蛮,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悍赢,沒想到半個月后决瞳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡左权,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年皮胡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赏迟。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡屡贺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瀑梗,到底是詐尸還是另有隱情烹笔,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布抛丽,位于F島的核電站谤职,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏亿鲜。R本人自食惡果不足惜允蜈,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒿柳。 院中可真熱鬧饶套,春花似錦、人聲如沸垒探。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽圾叼。三九已至蛤克,卻和暖如春捺癞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背构挤。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工髓介, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人筋现。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓唐础,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矾飞。 傳聞我的和親對象是個殘疾皇子一膨,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內(nèi)容

  • [TOC] 一、Redis 基礎常問 1.1凰慈、Redis 有哪些數(shù)據(jù)結(jié)構 基礎:字符串String汞幢、字典Hash、...
    w1992wishes閱讀 637評論 0 1
  • Redis 為什么這么快微谓? 很多人只知道是 K/V NoSQl 內(nèi)存數(shù)據(jù)庫森篷,單線程……這都是沒有全面理解 Redi...
    大漠硝煙閱讀 235評論 0 0
  • Redis為什么速度快 1、完全基于內(nèi)存豺型,絕大部分請求是純粹的內(nèi)存操作仲智,非常快速姻氨。數(shù)據(jù)存在內(nèi)存中钓辆,類似于HashM...
    亖狼何需裝羴閱讀 726評論 0 0
  • 16宿命:用概率思維提高你的勝算 以前的我是風險厭惡者,不喜歡去冒險肴焊,但是人生放棄了冒險前联,也就放棄了無數(shù)的可能。 ...
    yichen大刀閱讀 6,054評論 0 4
  • 公元:2019年11月28日19時42分農(nóng)歷:二零一九年 十一月 初三日 戌時干支:己亥乙亥己巳甲戌當月節(jié)氣:立冬...
    石放閱讀 6,883評論 0 2