1.redis常用指令
第一個是key的常用指令,第二個是數據庫的常用指令
前面的那些指令都是針對某一個數據類型操作的,現在的都是對所有的操作的
1.key常用指令
key應該設計哪些操作
key是一個字符串,通過key獲取redis中保存的數據
對于key自身狀態的相關操作,例如:刪除,判定存在,獲取類型等
對于key有效性控制相關操作,例如:有效期設定,判定是否有效,有效狀態的切換等
對于key快速查詢操作,例如:按指定策略查詢key
key 基本操作
刪除指定key
del key
獲取key是否存在
exists key
獲取key的類型
type key
排序
sort
改名
rename key newkey
renamenx key newkey
?
key 擴展操作(時效性控制)
為指定key設置有效期
expire key seconds
pexpire key milliseconds
expireat key timestamp
pexpireat key milliseconds-timestamp
獲取key的有效時間
ttl key # ttl:time to live:存活時間(過期時間)
pttl key
獲取key的有效時間
ttl key # ttl:time to live:存活時間(過期時間)
pttl key
key 擴展操作(查詢模式)
查詢key
keys pattern
查詢模式規則
*? 匹配任意數量的任意符號? ??? ?配合一個任意符號? ?[]? ?匹配一個指定符號
keys * keys 查詢所有
it* keys 查詢所有以it開頭
*heima 查詢所有以heima結尾
keys ??heima 查詢所有前面兩個字符任意,后面以heima結尾 查詢所有以
keys user:? user:開頭,最后一個字符任意
keys u[st]er:1 查詢所有以u開頭,以er:1結尾,中間包含一個字母,s或t
2.數據庫指令?
key 的重復問題
假如說十個人同時操作redis,會不會出現key名字命名沖突的問題
一定會,為什么?因為你的key是由程序而定義的。你想寫什么寫什么,那在使用的過程中大家都在不停的加,早晚有一天會沖突
redis在使用過程中,伴隨著操作數據量的增加,會出現大量的數據以及對應的key
我們最好把數據進行一個分類,除了命名規范我們做統一以外,如果還能把它分開,這樣是不是沖突的機率就會小一些了
解決方案
redis為每個服務提供有16個數據庫,編號從0到15
每個數據庫之間的數據相互獨立
在對應的數據庫中劃出一塊區域,說他就是幾,你就用幾那塊,同時,其他的這些都可以進行定義,一共是16個,這里邊需要注意一點,他們這16個共用redis的內存。沒有說誰大誰小,也就是說數字只是代表了一塊兒區域,區域具體多大未知。這是數據庫的一個分區的一個策略
數據庫的基本操作
切換數據庫
select index
其他操作
ping
數據移動
move key db
數據總量
dbsize
數據清除
flushdb # 清除當前庫的數據
flushall # 清除所有庫的數據
#flush:沖洗,沖掉
2.jedis
1.jedis概述
對于我們現在的數據來說,它是在我們的redis中,而最終我們是要做程序。那么程序就要和redis進行連接
程序中有數據的時候,我們要把這些數據全部交給redis管理。同時,redis中的數據還能取出來,回到我們的應用程序中
那在這個過程中,在Java與redis之間打交道的這個東西就叫做Jedis
Jedis就是提供了Java與redis的連接服務的,里邊有各種各樣的API接口,你可以去調用它
Java語言連接redis服務 Jedis(SpringData、Redis 、 Lettuce)
2.操作實現
準備工作
1.導入jar包
下載地址:https://mvnrepository.com/artifact/redis.clients/jedis
2.客戶端連接redis
連接redis
Jedis jedis = new Jedis("localhost", 6379);
操作redis
jedis.set("name", "ljb"); jedis.get("name");
關閉redis連接
jedis.close();
代碼實現?
import redis.clients.jedis.Jedis;import java.util.List;public class JedisTest {public static void main(String[] args) {//1.獲取連接對象Jedis jedis = new Jedis("192.168.235.129",6379);//2.執行操作jedis.set("age","39"); // jedis提供的方法與redis命令基本一致String hello = jedis.get("hello");System.out.println(hello);jedis.lpush("list1","a","b","c","d");List<String> list1 = jedis.lrange("list1", 0, -1);for (String s:list1 ) {System.out.println(s);}jedis.sadd("set1","abc","abc","def","poi","cba");Long len = jedis.scard("set1");System.out.println(len);//3.關閉連接jedis.close();}
}
3.Jedis簡易工具類開發
前面做的程序還是有點兒小問題,就是我們的Jedis對象的管理是我們自己創建的,真實企業開發中是不可能讓你去new一個的,那接下來咱們就要做一個工具類,簡單來說,就是做一個創建Jedis的這樣的一個工具
JedisPool:Jedis提供的連接池技術
poolConfig:連接池配置對象
host:redis服務地址
port:redis服務端口號
JedisPool的構造器:(源碼)
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) {this(poolConfig, host, port, 2000, (String)null, 0, (String)null);
}
創建jedis的配置文件:jedis.properties
jedis.host=192.168.235.129
jedis.port=6379
jedis.maxTotal=50 #控制一個pool可分配多少個jedis實例
jedis.maxIdle=10 #控制一個pool最多有多少個狀態為idle(空閑的)的jedis實例
# 就是說如果沒人用jedis,那么這個池子里就只有10個jedis實例
# 如果用的人非常多,但是不會超過50個
創建JedisUtils:使用靜態代碼塊初始化資源?
public class JedisUtils {private static int maxTotal;private static int maxIdel;private static String host;private static int port;private static JedisPoolConfig jpc;private static JedisPool jp;static {ResourceBundle bundle = ResourceBundle.getBundle("redis");maxTotal = Integer.parseInt(bundle.getString("redis.maxTotal"));maxIdel = Integer.parseInt(bundle.getString("redis.maxIdel"));host = bundle.getString("redis.host");port = Integer.parseInt(bundle.getString("redis.port"));//Jedis連接池配置jpc = new JedisPoolConfig();jpc.setMaxTotal(maxTotal);jpc.setMaxIdle(maxIdel);jp = new JedisPool(jpc,host,port);}
}
3.持久化
1.持久化概述
自動恢復,其實基于的一個前提就是他提前把你的數據給存起來了。你平常操作的所有信息都是在內存中的,而我們真正的信息是保存在硬盤中的,內存中的信息斷電以后就消失了,硬盤中的信息斷電以后還可以保留下來
? 我們將文件由內存中保存到硬盤中的這個過程,我們叫做數據保存,也就叫做持久化
但是把它保存下來不是你的目的,最終你還要把它再讀取出來,它加載到內存中這個過程,我們叫做數據恢復
就是我們所說的word為什么斷電以后還能夠給你保留文件,因為它執行了一個自動備份的過程,也就是通過自動的形式,把你的數據存儲起來,那么有了這種形式以后,我們的數據就可以由內存到硬盤上實現保存
什么是持久化
?利用永久性存儲介質將數據進行保存,在特定的時間將保存的數據進行恢復的工作機制稱為持久化?
?持久化用于防止數據的意外丟失,確保數據安全性
持久化過程保存什么
第一種:將當前數據狀態進行保存,快照形式,存儲數據結果,存儲格式簡單,關注點在數據。
第二種:將數據的操作過程進行保存,日志形式,存儲操作過程,存儲格式復雜,關注點在數據的操作過程
2.RDB?
1.save指令
手動執行一次保存操作
save
save指令相關配置
設置本地數據庫文件名,默認值為 dump.rdb,通常設置為dump-端口號.rdb
dbfilename filename
設置存儲.rdb文件的路徑,通常設置成存儲空間較大的目錄中,目錄名稱data
dir path
設置存儲至本地數據庫時是否壓縮數據,默認yes,設置為no,節省 CPU 運行時間,但存儲文件變大
rdbcompression yes|no
設置讀寫文件過程是否進行RDB格式校驗,默認yes,設置為no,節約讀寫10%時間消耗,單存在數據損壞的風險
rdbchecksum yes|no
2.?bgsave指令
當save指令的數據量過大時,單線程執行方式造成效率過低,那應該如何處理
此時我們可以使用:bgsave指令,bg其實是background的意思,后臺執行的意思
手動啟動后臺保存操作,但不是立即執行
bgsave
bgsave指令相關配置
后臺存儲過程中如果出現錯誤現象,是否停止保存操作,默認yes
stop-writes-on-bgsave-error yes|no
bgsave指令工作原理?
當執行bgsave的時候,客戶端發出bgsave指令給到redis服務器。
注意,這個時候服務器馬上回一個結果告訴客戶端后臺已經開始了,與此同時它會創建一個子進程,使用Linux的fork(分叉)函數創建一個子進程,讓這個子進程去執行save相關的操作
此時我們可以想一下,我們主進程一直在處理指令,而子進程在執行后臺的保存,它會不會干擾到主進程的執行嗎
答案是不會,所以說他才是主流方案。
子進程開始執行之后,它就會創建啊RDB文件把它存起來,操作完以后他會把這個結果返回,也就是說bgsave的過程分成兩個過程,
第一個是服務端拿到指令直接告訴客戶端開始執行了;
另外一個過程是一個子進程在完成后臺的保存操作,操作完以后回一個消息
注意:bgsave命令是針對save阻塞問題的優化。redis內部所有涉及到RDB操作都采用bgsave的方式,save命令可以放棄使用
3.save配置自動執行
設置自動持久化的條件,滿足限定時間范圍內key的變化數量達到指定數量即進行持久化
save second changes
參數
second:監控時間范圍
changes:監控key的變化量
范例:
save 900 1 #900s之內只有有1個key發生改變,就會保存
save 300 10
save 60 10000
RDB三種啟動方式對比
方式 | save指令 | bgsave指令 |
---|---|---|
讀寫 | 同步 | 異步 |
阻塞客戶端指令 | 是 | 否 |
額外內存消耗 | 否 | 是 |
啟動新進程 | 否 | 是 |
RDB優點:
RDB是一個緊湊壓縮的二進制文件,存儲效率較高
RDB內部存儲的是redis在某個時間點的數據快照,非常適合用于數據備份,全量復制等場景
RDB恢復數據的速度要比AOF快很多
應用:服務器中每X小時執行bgsave備份,并將RDB文件拷貝到遠程機器中,用于災難恢復
RDB缺點
RDB方式無論是執行指令還是利用配置,無法做到實時持久化,具有較大的可能性丟失數據
bgsave指令每次運行要執行fork操作創建子進程,要犧牲掉一些性能
Redis的眾多版本中未進行RDB文件格式的版本統一,有可能出現各版本服務之間數據格式無法兼容現象
3.AOF
為什么要有AOF,這是因為RDB的存儲的弊端
存儲數據量較大,效率較低,基于快照思想,每次讀寫都是全部數據,當數據量巨大時,效率非常低
大數據量下的IO性能較低
基于fork創建子進程,內存產生額外消耗
宕機帶來的數據丟失風險
解決思路
不寫全數據,僅記錄部分數據
降低區分數據是否改變的難度,改記錄數據為記錄操作過程
對所有操作均進行記錄,排除丟失數據的風險
1.AOF概念
AOF(append only file)持久化:以獨立日志的方式記錄每次寫命令,重啟時再重新執行AOF文件中命令 達到恢復數據的目的。與RDB相比可以簡單理解為由記錄數據改為記錄數據產生的變化
AOF的主要作用是解決了數據持久化的實時性,目前已經是Redis持久化的主流方式
2.啟動AOF相關配置
開啟AOF持久化功能,默認no,即不開啟狀態
appendonly yes|no
AOF持久化文件名,默認文件名為appendonly.aof,建議配置為appendonly-端口號.aof
appendfilename filename
AOF持久化文件保存路徑,與RDB持久化文件保持一致即可
dir
AOF寫數據策略,默認為everysec
appendfsync always|everysec|no
3.AOF執行策略
AOF寫數據三種策略(appendfsync)
always(每次):每次寫入操作均同步到AOF文件中數據零誤差,性能較低,不建議使用。
everysec(每秒):每秒將緩沖區中的指令同步到AOF文件中,在系統突然宕機的情況下丟失1秒內的數據 數據準確性較高,性能較高,建議使用,也是默認配置
no(系統控制):由操作系統控制每次同步到AOF文件的周期,整體過程不可控
4.AOF重寫
場景:AOF寫數據遇到的問題,如果連續執行如下指令該如何處理
AOF概述
隨著命令不斷寫入AOF,文件會越來越大,為了解決這個問題,Redis引入了AOF重寫機制壓縮文件體積
AOF文件重寫是將Redis進程內的數據轉化為寫命令同步到新AOF文件的過程
簡單說就是將對同一個數據的若干個條命令執行結果?轉化成?最終結果數據對應的指令進行記錄
AOF重寫作用
降低磁盤占用量,提高磁盤利用率
提高持久化效率,降低持久化寫時間,提高IO性能
降低數據恢復用時,提高數據恢復效率
AOF重寫規則
進程內具有時效性的數據,并且數據已超時將不再寫入文件
非寫入類的無效指令將被忽略,只保留最終數據的寫入命令
(如del key1、 hdel key2、srem key3、set key4 111、set key4 222等
如select指令雖然不更改數據,但是更改了數據的存儲位置,此類命令同樣需要記錄)
對同一數據的多條寫命令合并為一條命令
如lpushlist1 a、lpush list1 b、lpush list1 c可以轉化為:lpush list1 a b c。
為防止數據量過大造成客戶端緩沖區溢出,對list、set、hash、zset等類型,每條指令最多寫入64個元素
AOF重寫方式
手動重寫
bgrewriteaof # 這是一個redis指令,不是配置
自動重寫
自動重寫觸發條件設置
auto-aof-rewrite-min-size size # 達到指定大小就自動重寫,size可以指定多少兆:2MB 、 4MB
auto-aof-rewrite-percentage percent #按照存儲占用整體的百分比自動重寫,percent指定10%,達到10%就可以自動重寫
自動重寫觸發比對參數( 運行指令info Persistence獲取具體信息 )
aof_current_size
aof_base_size
?
5.RDB與AOF區別
持久化方式 | RDB | AOF |
---|---|---|
占用存儲空間 | 小(數據級:壓縮) | 大(指令級:重寫) |
存儲速度 | 慢 | 快 |
恢復速度 | 快 | 慢 |
數據安全性 | 會丟失數據 | 依據策略決定 |
資源消耗 | 高/重量級 | 低/輕量級 |
啟動優先級 | 低 | 高 |
RDB與AOF應用場景?
對數據非常敏感,建議使用默認的AOF持久化方案
AOF持久化策略使用everysecond,每秒鐘fsync一次。該策略redis仍可以保持很好的處理性能,當出 現問題時,最多丟失0-1秒內的數據。
注意:由于AOF文件存儲體積較大,且恢復速度較慢
數據呈現階段有效性,建議使用RDB持久化方案
數據可以良好的做到階段內無丟失(該階段是開發者或運維人員手工維護的),且恢復速度較快,階段 點數據恢復通常采用RDB方案
注意:利用RDB實現緊湊的數據持久化會使Redis降的很低,慎重總結
綜合比對
RDB與AOF的選擇實際上是在做一種權衡,每種都有利有弊
如不能承受數分鐘以內的數據丟失,對業務數據非常敏感,選用AOF
如能承受數分鐘以內的數據丟失,且追求大數據集的恢復速度,選用RDB
災難恢復選用RDB
雙保險策略,同時開啟 RDB和 AOF,重啟后,Redis優先使用 AOF 來恢復數據,降低丟失數據的量