JavaEE進階之Redis

Redis是一個key-value的nosql數據庫.先存到內存中,會根據一定的策略持久化到磁盤,即使斷電也不會丟失數據。支持的數據類型比較多。

主要用來做緩存數據庫的數據和web集群時當做中央緩存存放seesion。

守護進程:在linux或者unix操作系統中在系統引導的時候會開啟很多服務,這些服務就叫做守護進程。為了增加靈活性,root可以選擇系統開啟的模式,這些模式叫做運行級別,每一種運行級別以一定的方式配置系統。 守護進程是脫離於終端並且在後臺運行的進程。守護進程脫離於終端是為了避免進程在執行過程中的信息在任何終端上顯示並且進程也不會被任何終端所產生的終端信息所打斷。

CAP定理

高性能,高可用性和可伸縮性

1)nosql數據庫分類

Redis和Memcache區別:

  • Redis和Memcache都是將數據存放在內存中,都是內存數據庫。不過memcache還可用於緩存其他東西,例如圖片、視頻等等。
  • Redis不僅僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲。
  • 虛擬內存--Redis當物理內存用完時,可以將一些很久沒用到的value 交換到磁盤

nosql數據庫分類:

JavaEE進階之Redis

2)Redis使用場景

緩存

把經常需要查詢的、很少修改數據,放到讀速度很快的空間(內存),以便下次訪問減少時間。減輕壓力,減少訪問時間。

計數器

  • Redis中的計數器是原子性的內存操作。
  • 可以解決庫存溢出問題.進銷存系統庫存溢出。

session緩存服務器

  • web集群時作為session緩存服務器
  • 緩存隊列等

3)Redis對象保存方式

Json字符串:

需要把對象轉換為json字符串,當做字符串處理。直接使用set get來設置或者或。

優點:設置和獲取比較簡單

缺點:沒有提供專門的方法,需要把把對象轉換為json。(jsonlib)

字節:需要做序列號,就是把對象序列化為字節保存。

如果是擔心JSON轉對象會消耗資源的情況,這個問題需要考量幾個地方:

第一點:就是使用的JSON轉換lib是否就會存在性能問題。

第二點:就是數據的數據量級別,如果是存儲百萬級的大數據對象,建議採用存儲序列化對象方式。如果是少量的數據級對象,或者是數據對象字段不多,還是建議採用JSON轉換成String方式。

畢竟redis對存儲字符類型這部分優化的非常好。具體採用的方式與方法,還要看你所使用的場景。

4)Redis數據淘汰機制

在 Redis 中,允許用戶設置最大使用內存大小 server.maxmemory,在內存限定的情況下是很有用的。譬如,在一臺 8G 機子上部署了 4 個 Redis 服務點,每一個服務點分配 1.5G 的內存大小,減少內存緊張的情況,由此獲取更為穩健的服務。

內存大小有限,需要保存有效的數據?

Redis 內存數據集大小上升到一定大小的時候,就會施行數據淘汰策略。

Redis 提供 6種數據淘汰策略:

volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰

volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰

volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰

allkeys-lru:從數據集(server.db[i].dict)中挑選最近最少使用的數據淘汰

allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰

no-enviction(驅逐):禁止驅逐數據

5)Java操作Redis方式

  • 使用jedis java客戶端來訪問redis服務器,有點類似通過jdbc訪問mysql一樣。
  • 當然如果是spring進行集成時,可以使用spring data來訪問redis,spring data只是對jedis的二次封裝。jdbcTemplate jdbc關係一樣。

6)Redis存儲的數據類型

1.String

要把一個String保存到redis中,用set(key,value),獲取值用get(key)。

2.Hash(一般用於保存對象)

要把一個Hash保存到redis中,遍歷Map<String,String>,逐個調用hset(key,hashKey,hashValue),獲取所有值有hgetAll(key)。

3.List

要把一個List保存到redis中,遍歷List<String>,逐個調用lpush(key,value),獲取值用lrange(key,start,end),start代表開始位置,end代表結束位置,如果為-1則代表到未尾。

這裡lpush的意思是從左邊保存,也就是後來居上。

4.Set

要把一個Set保存到redis中,遍歷Set<String>,逐個調用sadd(key,value),獲取值用smembers(key)。

5.SortedSet

SortedSet的意思是他的每一個元素是有順序的,順序根據其score來決定,如果socre一樣,則按value排序。保存到redis的方法是,對每一個要保存的元素,調用zadd(key,score,value),獲取值用zrange(key,satrt,end),start代表開始位置,end代表結束位置,如果為-1則代表到未尾。

7)Redis的主從複製

類似mysql的master-slave模式一樣,redis的master-slave可以提升系統的可用性,master節點寫入cache後,會自動同步到slave上。Master以寫為主,Slave以讀為主。

可以實現:讀寫分離和容災恢復

缺點:延時,由於所有的寫操作都是在Master上操作,然後同步更新到Slave上,所以從Master同步到Slave機器有一定的延遲,當系統很繁忙的時候,延遲問題會更加嚴重,Slave機器數量的增加也會使得這個問題更加嚴重。

配置過程:

主Redis:192.168.10.1 6379 從Redis:192.168.10.2 6380

  • 將主從redis配置文件redis.conf中的aemonize no 改為 yes
  • 修改從redis配置文件redis.conf中的port 6379 改為 6380,添加slaveof 192.168.10.1 6379
  • 啟動主從服務

主Redis:

[root@localhost redis-2.8.3]# src/redis-server /soft/redis-2.8.3-master/redis-2.8.3/redis.conf

從Redis:

[root@localhost redis-2.8.3]# src/redis-server /soft/redis-2.8.3-slave/redis-2.8.3/redis.conf

測試數據同步

主Redis:

[root@localhost redis-2.8.3]# src/redis-cli -p 6379 ​ 127.0.0.1:6379> set name abc ​ OK ​ 127.0.0.1:6379> get name ​ "abc" ​ 127.0.0.1:6379>

從Redis:

[root@localhost redis-2.8.3]# src/redis-cli -p 6380 ​ 127.0.0.1:6380> get name ​ "abc" ​ 127.0.0.1:6380>

默認是讀寫分離的

在從Redis:

[root@localhost redis-2.8.3]# src/redis-cli -p 6380 ​ 127.0.0.1:6380> set name 123 ​ (error) READONLY You can't write against a read only slave.

主從切換

1、停止主Redis

[root@localhost redis-2.8.3]# src/redis-cli -n 6379 shutdown ​ [root@localhost redis-2.8.3]# src/redis-cli -p 6379 ​ Could not connect to Redis at 127.0.0.1:6379: Connection refused ​ not connected>

2、將從Redis設成主Redis ​

[root@localhost redis-2.8.3]# src/redis-cli -p 6380 slaveof NO ONE ​ OK

3、測試從Redis是否切換從主redis

[root@localhost redis-2.8.3]# src/redis-cli -p 6380 ​ 127.0.0.1:6380> set name 123 ​ OK ​ 127.0.0.1:6380> get name ​ "123" ​ 127.0.0.1:6380>

4、原來的主Redis恢復正常了,要重新切換回去

1)將現在的主redis的數據進行保存

[root@localhost redis-2.8.3]# src/redis-cli -p 6380 ​ 127.0.0.1:6380> get name ​ "abc" ​ 127.0.0.1:6380> set name 123 ​ OK ​ 127.0.0.1:6380> get name ​ "123" ​ 127.0.0.1:6380> save ​ OK ​ 127.0.0.1:6380> get name ​ "123" ​ 127.0.0.1:6380>

2)將現在的主redis根目錄下dump.rdb文件拷貝覆蓋到原來主redis的根目錄

3)啟動原來的主redis

[root@localhost redis-2.8.3]# src/redis-server /soft/redis-2.8.3-master/redis-2.8.3/redis.conf ​

4)在現在的主redis中切換

[root@localhost redis-2.8.3]# src/redis-cli -p 6380 slaveof 192.168.10.1 6379 ​ OK

常用的設計方案:

一主二僕:一個Master,兩個Slave,Slave只能讀不能寫;當Slave與Master斷開後需要重新slave of連接才可建立之前的主從關係;Master掛掉後,Master關係依然存在,Master重啟即可恢復。

薪火相傳:上一個Slave可以是下一個Slave的Master,Slave同樣可以接收其他slaves的連接和同步請求,那麼該slave作為了 鏈條中下一個slave的Master,如此可以有效減輕Master的寫壓力。如果slave中途變更轉向,會清除之前的數據,重新建立最新的。

反客為主: 當Master掛掉後,Slave可鍵入命令 slaveof no one使當前Redis停止與其他Master redis數據同步,轉成Master redis。

複製原理:

  1. Slave啟動成功連接到master後會發送一個sync命令;
  2. Master接到命令啟動後的存盤進程,同時收集所有接收到的用於修改數據集命令,在後臺進程執行完畢之後,master將傳送整個數據文件到slave,以完成一次完全同步;
  3. 全量複製:而slave服務在數據庫文件數據後,將其存盤並加載到內存中;
  4. 增量複製:Master繼續將新的所有收集到的修改命令依次傳給slave,完成同步;
  5. 但是隻要是重新連接master,一次完全同步(全量複製)將被自動執行。

哨兵模式:

反客為主的自動版,能夠後臺監控Master庫是否故障,如果故障了根據投票數自動將slave庫轉換為主庫。一組sentinel能同時監控多個Master。

使用步驟:

  • 1、在Master對應redis.conf同目錄下新建sentinel.conf文件,名字絕對不能錯;
  • 2、配置哨兵,在sentinel.conf文件中填入內容:
sentinel monitor 被監控數據庫名字(自己起名字) ip port 1

說明:上面最後一個數字1,表示主機掛掉後slave投票看讓誰接替成為主機,得票數多少後成為主機。

  • 3、啟動哨兵模式:
  • 命令鍵入:redis-sentinel /myredis/sentinel.conf
  • 注:上述sentinel.conf路徑按各自實際情況配置

8)Redis序列化器

普通的連接使用沒有辦法把Java對象直接存入Redis,而需要我們自己提供方案-對象序列化,然後存入redis,取回序列化內容後,轉換為java對象。Spring模板中提供了封裝的方案,在它內部提供了RedisSerializer接口(org.springframework.data.redis.serializer.RedisSerializer)和一些實現類。也可以自定義序列化器,實現RedisSerializer接口。常用的有:StringRedisSerializer,JdkSerializationRedisSerializer<T>,GenericToStringSerializer

RedisTemplate默認的系列化類是JdkSerializationRedisSerializer,用JdkSerializationRedisSerializer序列化的話,被序列化的對象必須實現Serializable接口。在存儲內容時,除了屬性的內容外還存了其它內容在裡面,總長度長,且不容易閱讀。 我們要求是存儲的數據可以方便查看,也方便反系列化,方便讀取數據。

Jackson2JsonRedisSerializer和GenericJackson2JsonRedisSerializer,兩者都能序列化成json,但是後者會在json中加入@class屬性,類的全路徑包名,方便反系列化。前者如果存放了List則在反系列化的時候如果沒指定TypeReference則會報錯:java.util.LinkedHashMap cannot be cast to

9)websocket

WebSocket 是 HTML5 開始提供的一種在單個 TCP 連接上進行全雙工通訊的協議。

WebSocket 使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在 WebSocket API 中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。

在 WebSocket API 中,瀏覽器和服務器只需要做一個握手的動作,然後,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。

現在,很多網站為了實現推送技術,所用的技術都是 Ajax 輪詢。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP請求,然後由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源。

WebSocket 協議本質上是一個基於 TCP 的協議。

為了建立一個 WebSocket 連接,客戶端瀏覽器首先要向服務器發起一個 HTTP 請求,這個請求和通常的 HTTP 請求不同,包含了一些附加頭信息,其中附加頭信息"Upgrade: WebSocket"表明這是一個申請協議升級的 HTTP 請求,服務器端解析這些附加的頭信息然後產生應答信息返回給客戶端,客戶端和服務器端的 WebSocket 連接就建立起來了,雙方就可以通過這個連接通道自由的傳遞信息,並且這個連接會持續存在直到客戶端或者服務器端的某一方主動的關閉連接。

websocket事件觸發機制:

open

一旦服務器響應了WebSocket連接請求,open事件觸發並建立一個連接。open事件對應的回調函數稱作onopen。

到open事件觸發時,協議握手已經完成,WebSocket已經準備好發送和接收數據。如果應用程序接收到一個open事件,那麼 可以確定WebSocket服務器成功地處理了連接請求,並且同意與應用程序通信。

message

WebSocket消息包含來自服務器的數據。你也可能聽說過組成WebSocket消息的WebSocket幀(Frame)。第3章將詳細討論消息和幀的概念。為了理解消息使用API的方式,WebSocket API只輸出完整的消息,而不是WebSocket幀。message事件在接收到消息時觸發,對應於該事件的回調函數是onmessage。

除了文本,WebSocket消息還可以處理二進制數據,這種數據作為Blob消息或者ArrayBuffer消息處理。因為設置WebSocket消息二進制數據類型的應用程序會影響二進制消息,所以必須在讀取數據之前決定用於客戶端二進制輸入數據的類型。

error

error事件在響應意外故障的時候觸發。與該事件對應的回調函數為onerror。錯誤還會導致WebSocket連接關閉。如果你接收一個error事件,可以預期很快就會觸發close事件。close事件中的代碼和原因有時候能告訴你錯誤的根源。error事件處理程序是調用服務器重連邏輯以及處理來自WebSocket對象的異常的最佳場所。

close

close事件在WebSocket連接關閉時觸發。對應於close事件的回調函數是onclose。一旦連接關閉,客戶端和服務器不再能接收或者發送消息。

說明:WebSocket規範還定義了ping和pong幀,可以用於持續連接(keep-alive)、心跳、網絡狀態檢測、延遲測量等,但是WebSocket API目前沒有輸出這些特性。儘管瀏覽器接受ping幀,但是不會觸發對應WebSocket上的ping事件。相反,瀏覽器將自動響應pong幀。然而,瀏覽器實例化的ping如果在一段時間內沒有得到pong應答,可能會觸發連接的close事件。

當調用close()方法終止與服務器的連接時,也會觸發onclose事件處理程序;WebSocket close事件在連接關閉時觸發,這可能有多種原因,比如連接失敗或者成功的WebSocket關閉握手。WebSocket對象特性readyState反映了連接的狀態(2為正在關閉,3為已關閉)。

close事件有3個有用的屬性(property),可以用於錯誤處理和恢復:wasClean、code和error。wasClean屬性是一個布爾屬性,表示連接是否順利關閉。如果WebSocket的關閉是對來自服務器的一個close幀的響應,則該屬性為true。如果連接是因為其他原因(例如,因為底層TCP連接關閉)關閉,則該屬性為false。code和reason屬性表示服務器發送的關閉握手狀態。這些屬性和WebSocket.close()方法中的code和reason參數一致。

最後,想學習JAVA的小夥伴們!

請關注+私信回覆:“學習”就可以拿到一份我為大家準備的學習資料!

JavaEE進階之Redis

java學習資料

JavaEE進階之Redis

相關推薦

推薦中...