1. 程式人生 > 實用技巧 >非關係資料庫之redis入門到實戰(5)Redis企業運用

非關係資料庫之redis入門到實戰(5)Redis企業運用

第一章 NoSQL 入門概述

1.1 入門概述

1.1.1 單機 MySQL 的美好年代

  在90年代,一個網站的訪問量一般都不大,用單個數據庫完全可以輕鬆應付。
  在那個時候,更多的都是靜態網頁,動態互動型別的網站不多。


  上述架構下,我們來看看資料儲存的瓶頸是什麼?
  1、資料量的總大小:一個機器放不下時
  2、資料的索引(B+ Tree):一個機器的記憶體放不下時
  3、訪問量(讀寫混合):一個例項不能承受
  如果滿足了上述 1 or 3 個,進化……

1.1.2 Memcached(快取) + MySQL + 垂直拆分

  後來,隨著訪問量的上升,幾乎大部分使用 MySQL 架構的網站在資料庫上都開始出現了效能問題,web 程式不再僅僅專注在功能上,同時也在追求效能。程式設計師們開始大量的使用快取技術來緩解資料庫的壓力,優化資料庫的結構和索引。開始比較流行的是通過檔案快取來緩解資料庫壓力,但是當訪問量繼續增大的時候,多臺 web 機器通過檔案快取不能共享,大量的小檔案快取也帶了了比較高的 IO 壓力。在這個時候,Memcached 就自然的成為一個非常時尚的技術產品。
  


  Memcached 作為一個獨立的分散式的快取伺服器,為多個 web 伺服器提供了一個共享的高效能快取服務,在 Memcached 伺服器上,又發展了根據 hash 演算法來進行多臺 Memcached 快取服務的擴充套件,然後又出現了一致性 hash 來解決增加或減少快取伺服器導致重新 hash 帶來的大量快取失效的弊端。

1.1.3 MySQL 主從複製--讀寫分離

  由於資料庫的寫入壓力增加,Memcached 只能緩解資料庫的讀取壓力。讀寫集中在一個數據庫上讓資料庫不堪重負,大部分網站開始使用主從複製技術來達到讀寫分離,以提高讀寫效能和讀庫的可擴充套件性。Mysql 的 master-slave 模式成為這個時候的網站標配了。
  

1.1.4 分表分庫 + 水平拆分 + MySQL 叢集

  在 Memcached 的快取記憶體,MySQL 的主從複製,讀寫分離的基礎之上,這時 MySQL 主庫的寫壓力開始出現瓶頸,而資料量的持續猛增,由於 MyISAM 使用表鎖,在高併發下會出現嚴重的鎖問題,大量的高併發 MySQL 應用開始使用 InnoDB 引擎代替 MyISAM。
  同時,開始流行使用分表分庫來緩解寫壓力和資料增長的擴充套件問題。這個時候,分表分庫成了一個熱門技術,是面試的熱門問題也是業界討論的熱門技術問題。也就在這個時候,MySQL 推出了還不太穩定的表分割槽,這也給技術實力一般的公司帶來了希望。雖然 MySQL 推出了 MySQL Cluster 叢集,但效能也不能很好滿足網際網路的要求,只是在高可靠性上提供了非常大的保證。
  

1.1.5 MySQL 的擴充套件性瓶頸

  MySQL 資料庫也經常儲存一些大文字欄位,導致資料庫表非常的大,在做資料庫恢復的時候就導致非常的慢,不容易快速恢復資料庫。比如 1000 萬 4KB 大小的文字就接近 40GB 的大小,如果能把這些資料從 MySQL 省去,MySQL 將變得非常的小。關係資料庫很強大,但是它並不能很好的應付所有的應用場景。MySQL 的擴充套件性差(需要複雜的技術來實現),大資料下 IO 壓力大,表結構更改困難,正是當前使用 MySQL 的開發人員面臨的問題。

1.1.6 今天是什麼樣子?

1.1.7 為什麼用 NoSQL?

  為什麼使用 NoSQL ?
  今天我們可以通過第三方平臺(如:Google、Facebook等)可以很容易的訪問和抓取資料。使用者的個人資訊、社交網路、地理位置、使用者生成的資料和使用者操作日誌已經成倍的增加。我們如果要對這些使用者資料進行挖掘,那 SQL 資料庫已經不適合這些應用了,NoSQL 資料庫的發展也卻能很好的處理這些大的資料。
  

1.2 NoSQL 是什麼?

  NoSQL(NoSQL = Not Only SQL ),意即“不僅僅是 SQL”,泛指非關係型的資料庫。隨著網際網路 web2.0 網站的興起,傳統的關係資料庫在應付 web2.0 網站,特別是超大規模和高併發的 SNS 型別的 web2.0 純動態網站已經顯得力不從心,暴露了很多難以克服的問題,而非關係型的資料庫則由於其本身的特點得到了非常迅速的發展。NoSQL 資料庫的產生就是為了解決大規模資料集合多重資料種類帶來的挑戰,尤其是大資料應用難題,包括超大規模資料的儲存。
  例如谷歌或 Facebook 每天為他們的使用者收集萬億位元的資料。這些型別的資料儲存不需要固定的模式,無需多餘操作就可以橫向擴充套件

1.3 NoSQL 能幹啥?

KV -- 鍵值對
Cache -- 快取
Persistence -- 持久化

1.4 NoSQL 有哪些?

Redis
Memcache
MongoDB

1.5 NoSQL 怎麼玩?

Hello World
類比
遞推
各大網站、部落格、論壇、微信公眾號

1.2 4V + 3高

4V:
  海量(大量) Volume
  多樣 Variety
  實時(高速) Velocity
  低價值密度 Value

參考連結:https://www.cnblogs.com/chenmingjun/p/10335265.html#_label0_1

3高:
  高併發
  高可擴
  高效能

1.3 雲端計算--網際網路雲架構

1.3.1 當前的網際網路江湖

雲端計算大資料工程師 = 雲大。

人算不如天算,天算就是雲端計算。

架構即技術,技術即人生。

雲端計算 和 大資料 是不分家的。就相當於語文和歷史的關係。

買書容易看書難,搬家還麻煩!

天上飛的理論是相通的,落地的產品各不相同。


我們身處“爭雄圖霸”的 IT 亂世

滴滴 + 快的 合併
美團 + 大眾點評 合併
攜程 + 去哪網兒 合併
海底撈

支付寶會記錄你的消費軌跡 => 螞蟻金服 -> 花唄+借唄+芝麻信用 => 廣告的分類推送 + 精確營銷


百度 -- 熊廠、狼廠、藍廠
  百度的 Logo 是一個藍色的熊爪子,百度CEO李彥巨集給百度員工的一封公開信:《鼓勵狼性淘汰小資》。
騰訊 -- 鵝廠
  騰訊的 Logo 是一隻企鵝,企鵝也是鵝。
迅雷 -- 鳥廠
360 -- 綠廠、數字公司
阿里巴巴 -- 貓廠、東廠、西廠
  阿里巴巴是因為旗下天貓的 Logo。
新浪 -- 渣浪
  起因是 up 主使用外鏈投稿曾多次被新浪稽核但又無故刪除,使得UP主們抓狂,從此就有了“戰渣浪”的定義。
網易 -- 豬廠
  網易 CEO 丁磊在之前養過一段時間的豬。
搜狐 -- 狐廠
  搜狐的吉祥物是一隻紅色大尾巴的小狐狸。
京東 -- 狗廠
小米 -- 糧廠、雜糧、粗糧
盛大 -- 無花名
  據說在盛大工作過1-2年叫盛鬥士;3-5年叫必盛客;6-9年叫鬥戰盛佛;10年以上叫齊天大盛。

1.3.2 傳統行業 Java 工程師

01 圖


02 圖

03 圖

問題:
  使用者端:公司發展,使用者過萬,線上使用者上千,應用伺服器和資料庫都成為瓶頸。
  開發組:團隊變大,所有開發人員集中針對同一個系統,衝突嚴重。

業務模式決定架構:
  • 面向網際網路海量使用者提供服務
  • 面向商家提供網路銷售平臺
  • 商品種類繁多,需及時更新資料
  • 全天24小時運營,快速處理客戶訂單
  • 交易量大且不斷增長,促銷活動期間業務量突增
  • 支援多種營銷模式,邏輯複雜
  • 業務模式包括自營B2C、商家B2C、廣告、代發物流等
  • 經營實物商品和數字商品,交付方式不同
  • 支援多種安全的登入方式和支付方式

1.3.1 大型網際網路架構架構

1、噹噹網


噹噹網技術架構

2、美團網

3、宜人貸

4、淘寶網

1.3.2 雲大具體應用

1.3.3 需要掌握的技術


把傳統的 JavaEE + 雲平臺整合構建?

1.3.4 軟體架構設計

  • 子系統的設計以及介面的定義
  • 基於 Linux 下的伺服器叢集配置
  • 負載均衡與效能提升

阿里巴巴大規模網際網路實踐的頂層架構圖

企業級網際網路架構平臺的事實標準

企業資訊系統演進的歷程

芒果TV合作案例

1.4 當下的 NoSQL 經典應用

阿里巴巴中文站架構發展歷程

阿里巴巴中文站第五代網站架構

阿里巴巴中文站第五代網站架構的使命

和我們相關的,多資料來源多資料型別的儲存問題

為什麼要去IOE?

  2008年,王堅加盟阿里巴巴成為集團首席架構師,即現在的首席技術官。這位前微軟亞洲研究院常務副院長被馬雲定位為:將幫助阿里巴巴集團建立世界級的技術團隊,並負責集團技術架構以及基礎技術平臺搭建。
  在加入阿里後,帶著技術基因和學者風範的王堅就在阿里巴巴集團提出了被稱為 “去IOE”(在 IT 建設過程中,去除 IBM 小型機、Oracle 資料庫及 EMC 儲存裝置)的想法,並開始把雲端計算的本質,植入阿里 IT 基因。
  王堅這樣概括 “去IOE” 運動和阿里雲之間的關係:“去IOE” 徹底改變了阿里集團 IT 架構的基礎,是阿里擁抱雲端計算,產出計算服務的基礎。“去IOE” 的本質是分佈化,讓隨處可以買到的 Commodity PC 架構成為可能,使雲端計算能夠落地的首要條件。

UDSL 是什麼?

1.5 在分散式資料庫中 CAP 原理(CAP + BASE)

  最多隻能同時較好的滿足兩個。
  CAP 理論的核心是:一個分散式系統不可能同時很好的滿足一致性,可用性和分割槽容錯性這三個需求。
  因此,根據 CAP 原理將 NoSQL 資料庫分成了滿足 CA 原則、滿足 CP 原則和滿足 AP 原則三大類:
  • CA - 單點叢集,滿足一致性,可用性的系統,通常在可擴充套件性上不太強大。
  • CP - 滿足一致性,分割槽容忍性的系統,通常效能不是特別高。
  • AP - 滿足可用性,分割槽容忍性的系統,通常可能對一致性要求低一些。

CAP 的 3 進 2

  CAP 理論就是說在分散式儲存系統中,最多隻能實現上面的兩點。
  而由於當前的網路硬體肯定會出現延遲丟包等問題,所以分割槽容忍性是我們必須需要實現的。所以我們只能在一致性和可用性之間進行權衡,沒有 NoSQL 系統能同時保證這三點。
  C:強一致性 A:高可用性 P:分散式容忍性
  CA -- 傳統 Oracle 資料庫
  AP -- 大多數網站架構的選擇
  CP -- Redis、Mongodb
  注意:分散式架構的時候必須做出取捨。
  一致性和可用性之間取一個平衡。多餘大多數 web 應用,其實並不需要強一致性。
  因此犧牲 C 換取 P,這是目前分散式資料庫產品的方向。
一致性與可用性的決擇
  對於 web2.0 網站來說,關係資料庫的很多主要特性卻往往無用武之地
資料庫事務一致性需求
  很多web實時系統並不要求嚴格的資料庫事務,對讀一致性的要求很低,有些場合對寫一致性要求並不高。允許實現最終一致性。
資料庫的寫實時性和讀實時性需求
  對關係資料庫來說,插入一條資料之後立刻查詢,是肯定可以讀出來這條資料的,但是對於很多web應用來說,並不要求這麼高的實時性,比方說發一條訊息之 後,過幾秒乃至十幾秒之後,我的訂閱者才看到這條動態是完全可以接受的。
對複雜的SQL查詢,特別是多表關聯查詢的需求
  任何大資料量的 web 系統,都非常忌諱多個大表的關聯查詢,以及複雜的資料分析型別的報表查詢,特別是 SNS 型別的網站,從需求以及產品設計角度,就避免了這種情況的產生。往往更多的只是單表的主鍵查詢,以及單表的簡單條件分頁查詢,SQL 的功能被極大的弱化了。

BASE 是什麼?

  BASE 就是為了解決關係資料庫強一致性引起的問題而引起的可用性降低而提出的解決方案。
  BASE 其實是下面三個術語的縮寫:
  基本可用(Basically Available)
  軟狀態(Soft state)
  最終一致(Eventually consistent)
  它的思想是通過讓系統放鬆對某一時刻資料一致性的要求來換取系統整體伸縮性和效能上改觀。為什麼這麼說呢?緣由就在於大型系統往往由於地域分佈和極高效能的要求,不可能採用分散式事務來完成這些指標,要想獲得這些指標,我們必須採用另外一種方式來完成,這裡 BASE 就是解決這個問題的辦法。

分散式系統

  分散式系統(distributed system)由多臺計算機和通訊的軟體元件通過計算機網路連線(本地網路或廣域網)組成。分散式系統是建立在網路之上的軟體系統。正是因為軟體的特性,所以分散式系統具有高度的內聚性和透明性。因此,網路和分散式系統之間的區別更多的在於高層軟體(特別是作業系統),而不是硬體。分散式系統可以應用在在不同的平臺上如:Pc、工作站、區域網和廣域網上等。
  簡單來講:
  1、分散式:不同的多臺伺服器上面部署不同的服務模組(工程),他們之間通過 RPC/RMI 之間通訊和呼叫,對外提供服務和組內協作。
  2、叢集:不同的多臺伺服器上面部署相同的服務模組,通過分散式排程軟體進行統一的排程,對外提供服務和訪問。

回到頂部

第二章 Redis 入門介紹

2.1 入門概述

2.2 Redis 的安裝


檢視埠命令複習

2.3 Redis 啟動後雜項基礎知識講解

回到頂部

第三章 Redis 資料型別

第四章 解析 Redis 配置檔案 redis.conf

4.1 Units 單位


1、配置大小單位,開頭定義了一些基本的度量單位,只支援 bytes(位元組),不支援 bit(位數)。
2、對大小寫不敏感。

4.2 INCLUDES 包含


指定包含其它的配置檔案,可以在同一主機上多個 Redis 例項之間使用同一份配置檔案,而同時各個例項又擁有自己的特定配置檔案。
include /path/to/local.conf

4.3 GENERAL 通用

daemonize
pidfile
port


bind
timeout

loglevel
logfile
databases

4.4 SNAPSHOTTING 快照

sava

RDB是整個記憶體的壓縮過的Snapshot,RDB的資料結構,可以配置複合的快照觸發條件。
預設
save9001
save30010
save6010000

15分鐘內改了1次,就儲存一次快照
或5分鐘內改了10次,就儲存一次快照
或1分鐘內改了1萬次,就儲存一次快照

注意:實際開發中30分鐘儲存一次快照。

如果想禁用RDB持久化的策略,只要不設定任何save指令,或者給save傳入一個空字串引數也可以。
sava""

stop-writes-on-bgsave-error 預設配置是yes,表示在使用bgsave命令備份的時候出現錯誤則停止外界寫入操作,
如果配置成no,表示你不在乎資料不一致或者有其他的手段發現和控制。
dbfilename
dir dump.rdb儲存的目錄,即啟動redis時的目錄

4.5 SECURITY 安全


具體操作如下:

4.6 LIMITS 限制

maxclients

  設定 redis 同時可以與多少個客戶端進行連線。預設情況下為 10000 個客戶端。當你無法設定程序檔案控制代碼限制時,redis 會設定為當前的檔案控制代碼限制值減去 32,因為 redis 會為自身內部處理邏輯留一些控制代碼出來。如果達到了此限制,redis 則會拒絕新的連線請求,並且向這些連線請求方發出 “max number of clients reached” 以作迴應。
maxmemory
  設定 redis 可以使用的記憶體量。一旦到達記憶體使用上限,redis 將會試圖移除內部資料,移除規則可以通過 maxmemory-policy 來指定。如果 redis 無法根據移除規則來移除記憶體中的資料,或者設定了“不允許移除”,那麼 redis 則會針對那些需要申請記憶體的指令返回錯誤資訊,比如 SET、LPUSH 等。
  但是對於無記憶體申請的指令,仍然會正常響應,比如 GET 等。如果你的 redis 是主 redis(說明你的 redis 有從 redis),那麼在設定記憶體使用上限時,需要在系統中留出一些記憶體空間給同步佇列快取,只有在你設定的是“不移除”的情況下,才不用考慮這個因素。
maxmemory-policy
  •(1)volatile-lru:使用 LRU 演算法移除 key,只對設定了過期時間的鍵
  •(2)allkeys-lru:使用 LRU 演算法移除 key
  •(3)volatile-random:在過期集合中移除隨機的 key,只對設定了過期時間的鍵
  •(4)allkeys-random:移除隨機的 key
  •(5)volatile-ttl:移除那些 TTL 值最小的 key,即那些最近要過期的 key
  •(6)noeviction:不進行移除。針對寫操作,只是返回錯誤資訊,實際開發中不使用這個配置。

4.7 APPEND ONLY MODE 追加

appendonly
appendfilename
appendfsync
  always:同步持久化,每次發生資料變更會被立即記錄到磁碟,效能較差但資料完整性比較好。
  everysec:出廠預設推薦,非同步操作,每秒記錄,如果一秒內宕機,有資料丟失,實際開發中推薦
  no

4.8 常見配置 redis.conf 介紹

引數說明:

redis.conf配置項說明如下:
1.Redis預設不是以守護程序的方式執行,可以通過該配置項修改,使用yes啟用守護程序
daemonizeno
2.當Redis以守護程序方式執行時,Redis預設會把pid寫入/var/run/redis.pid檔案,可以通過pidfile指定
pidfile/var/run/redis.pid
3.指定Redis監聽埠,預設埠為6379,作者在自己的一篇博文中解釋了為什麼選用6379作為預設埠,因為6379在手機按鍵上是MERZ對應的號碼,而MERZ取自義大利歌女AlessiaMerz的名字
port6379
4.繫結的主機地址
bind127.0.0.1
5.當客戶端閒置多長時間後關閉連線,如果指定為0,表示關閉該功能
timeout300
6.指定日誌記錄級別,Redis總共支援四個級別:debug、verbose、notice、warning,預設為verbose
loglevelverbose
7.日誌記錄方式,預設為標準輸出,如果配置Redis為守護程序方式執行,而這裡又配置為日誌記錄方式為標準輸出,則日誌將會發送給/dev/null
logfilestdout
8.設定資料庫的數量,預設資料庫為0,可以使用SELECT<dbid>命令在連線上指定資料庫id
databases16
9.指定在多長時間內,有多少次更新操作,就將資料同步到資料檔案,可以多個條件配合
save<seconds><changes>
Redis預設配置檔案中提供了三個條件:
save9001
save30010
save6010000
分別表示900秒(15分鐘)內有1個更改,300秒(5分鐘)內有10個更改以及60秒內有10000個更改。
10.指定儲存至本地資料庫時是否壓縮資料,預設為yes,Redis採用LZF壓縮,如果為了節省CPU時間,可以關閉該選項,但會導致資料庫檔案變的巨大
rdbcompressionyes
11.指定本地資料庫檔名,預設值為dump.rdb
dbfilenamedump.rdb
12.指定本地資料庫存放目錄
dir./
13.設定當本機為slave服務時,設定master服務的IP地址及埠,在Redis啟動時,它會自動從master進行資料同步
slaveof<masterip><masterport>
14.當master服務設定了密碼保護時,slave服務連線master的密碼
masterauth<master-password>
15.設定Redis連線密碼,如果配置了連線密碼,客戶端在連線Redis時需要通過AUTH<password>命令提供密碼,預設關閉
requirepassfoobared
16.設定同一時間最大客戶端連線數,預設無限制,Redis可以同時開啟的客戶端連線數為Redis程序可以開啟的最大檔案描述符數,如果設定maxclients0,表示不作限制。當客戶端連線數到達限制時,Redis會關閉新的連線並向客戶端返回maxnumberofclientsreached錯誤資訊
maxclients128
17.指定Redis最大記憶體限制,Redis在啟動時會把資料載入到記憶體中,達到最大記憶體後,Redis會先嚐試清除已到期或即將到期的key,當此方法處理後,仍然到達最大記憶體設定,將無法再進行寫入操作,但仍然可以進行讀取操作。Redis新的vm機制,會把key存放記憶體,value會存放在swap區
maxmemory<bytes>
18.指定是否在每次更新操作後進行日誌記錄,Redis在預設情況下是非同步的把資料寫入磁碟,如果不開啟,可能會在斷電時導致一段時間內的資料丟失。因為redis本身同步資料檔案是按上面save條件來同步的,所以有的資料會在一段時間內只存在於記憶體中。預設為no
appendonlyno
19.指定更新日誌檔名,預設為appendonly.aof
appendfilenameappendonly.aof
20.指定更新日誌條件,共有3個可選值:
no:表示等作業系統進行資料快取同步到磁碟(快)
always:表示每次更新操作後手動呼叫fsync()將資料寫到磁碟(慢,安全)
everysec:表示每秒同步一次(折衷,預設值)
appendfsynceverysec
21.指定是否啟用虛擬記憶體機制,預設值為no,簡單的介紹一下,VM機制將資料分頁存放,由Redis將訪問量較少的頁即冷資料swap到磁碟上,訪問多的頁面由磁碟自動換出到記憶體中(在後面的文章會仔細分析Redis的VM機制)
vm-enabledno
22.虛擬記憶體檔案路徑,預設值為/tmp/redis.swap,不可多個Redis例項共享
vm-swap-file/tmp/redis.swap
23.將所有大於vm-max-memory的資料存入虛擬記憶體,無論vm-max-memory設定多小,所有索引資料都是記憶體儲存的(Redis的索引資料就是keys),也就是說,當vm-max-memory設定為0的時候,其實是所有value都存在於磁碟。預設值為0
vm-max-memory0
24.Redisswap檔案分成了很多的page,一個物件可以儲存在多個page上面,但一個page上不能被多個物件共享,vm-page-size是要根據儲存的資料大小來設定的,作者建議如果儲存很多小物件,page大小最好設定為32或者64bytes;如果儲存很大大物件,則可以使用更大的page,如果不確定,就使用預設值
vm-page-size32
25.設定swap檔案中的page數量,由於頁表(一種表示頁面空閒或使用的bitmap)是在放在記憶體中的,,在磁碟上每8個pages將消耗1byte的記憶體。
vm-pages134217728
26.設定訪問swap檔案的執行緒數,最好不要超過機器的核數,如果設定為0,那麼所有對swap檔案的操作都是序列的,可能會造成比較長時間的延遲。預設值為4
vm-max-threads4
27.設定在向客戶端應答時,是否把較小的包合併為一個包傳送,預設為開啟
glueoutputbufyes
28.指定在超過一定的數量或者最大的元素超過某一臨界值時,採用一種特殊的雜湊演算法
hash-max-zipmap-entries64
hash-max-zipmap-value512
29.指定是否啟用重置雜湊,預設為開啟(後面在介紹Redis的雜湊演算法時具體介紹)
activerehashingyes
30.指定包含其它的配置檔案,可以在同一主機上多個Redis例項之間使用同一份配置檔案,而同時各個例項又擁有自己的特定配置檔案
include/path/to/local.conf

第五章 Redis 的持久化


RBD小結

AOF小結

第六章 Redis 的事務

Redis 事務常用命令:


Redis 的事務腦圖

第七章 Redis 的複製(Master/Slave)

第八章 Redis 的 Java 客戶端 Jedis


測試連通性
packagecom.atguigu.test;

importredis.clients.jedis.Jedis;

publicclassHelloRedis{

publicstaticvoidmain(String[]args){
Jedisjedis=newJedis("192.168.25.102",6379);

Stringresult=jedis.ping();

System.out.println("**********"+result);

//Connection
}
}

五大資料型別 + 1個 key

packagecom.atguigu.test;

importjava.util.Set;

importredis.clients.jedis.Jedis;

publicclassAPIRedis{

publicstaticvoidmain(String[]args){
Jedisjedis=newJedis("192.168.22.167",6379);

Set<String>set=jedis.keys("*");
System.out.println(set.size());

jedis.set("k3","v3");

System.out.println(jedis.get("k3"));
}
}

事務提交

packagecom.atguigu.test;

importredis.clients.jedis.Jedis;
importredis.clients.jedis.Transaction;

publicclassTXRedis{

publicbooleantransMethod()throwsInterruptedException{
Jedisjedis=newJedis("192.168.25.102",6379);

intbalance;//可用餘額
intdebt;//欠額
intamtToSubtract=10;//實刷額度

jedis.watch("balance");
Thread.sleep(8000);//停止程式一小段時間,外面先修改balance資料後看效果
balance=Integer.parseInt(jedis.get("balance"));

if(balance<amtToSubtract){
jedis.unwatch();
System.out.println("TheDatahasbeenupdatedbeforeyoucommitorbalance<amtToSubtract");
returnfalse;
}else{
System.out.println("***********transaction");

Transactiontransaction=jedis.multi();
transaction.decrBy("balance",amtToSubtract);
transaction.incrBy("debt",amtToSubtract);
transaction.exec();

balance=Integer.parseInt(jedis.get("balance"));
debt=Integer.parseInt(jedis.get("debt"));

System.out.println("*******"+balance);
System.out.println("*******"+debt);
returntrue;
}
}

/**
*虛擬碼如下:通俗點講,watch命令就是標記一個鍵,如果標記了一個鍵:
*
*在提交事務前如果該鍵被別人修改過,那事務就會失敗,這種情況通常可以在程式中重新再嘗試一次。
*首先標記了鍵balance,然後檢查餘額是否足夠,不足就取消標記,並不做扣減;足夠的話,就啟動事務進行更新操作,
*如果在此期間鍵balance被其它人修改,那在提交事務(執行exec)時就會報錯,程式中通常可以捕獲這類錯誤再重新執行一次,直到成功。
*
*@throwsInterruptedException
*/
publicstaticvoidmain(String[]args)throwsInterruptedException{
TXRedistest=newTXRedis();
booleanretValue=test.transMethod();
System.out.println("mainretValue-------:"+retValue);
}
}

主從複製

packagecom.atguigu.test;

importredis.clients.jedis.Jedis;

publicclassReplicationRedis{

publicstaticvoidmain(String[]args){
JedisjedisM=newJedis("192.168.25.102",6379);
JedisjedisS=newJedis("192.168.25.102",6380);

jedisS.slaveof("192.168.25.102",6379);

jedisM.set("k3","v3");

Stringresult=jedisS.get("k3");

System.out.println("#############result:"+result);
}
}

JedisPoolUtils.java

packagecom.atguigu.test;

importredis.clients.jedis.Jedis;
importredis.clients.jedis.JedisPool;
importredis.clients.jedis.JedisPoolConfig;

publicclassJedisPoolUtils{
privatestaticvolatileJedisPooljedisPool=null;

privateJedisPoolUtils(){
}

//DCL(doublechecklock)
publicstaticJedisPoolgetInstance(){
if(null==jedisPool){
synchronized(JedisPoolUtils.class){
if(null==jedisPool){
JedisPoolConfigpoolConfig=newJedisPoolConfig();
poolConfig.setMaxActive(100);
poolConfig.setMaxIdle(32);
poolConfig.setMaxWait(100*1000);
poolConfig.setTestOnBorrow(true);

jedisPool=newJedisPool(poolConfig,"192.168.25.102",6379);
}
}
}
returnjedisPool;
}

publicstaticvoidclose(JedisPooljedisPool,Jedisjedis){
if(null!=jedis){
jedisPool.returnResourceObject(jedis);
}
}
}

JedisPoolRedis.java

packagecom.atguigu.test;

importredis.clients.jedis.Jedis;
importredis.clients.jedis.JedisPool;

publicclassJedisPoolRedis{

publicstaticvoidmain(String[]args){
JedisPooljedisPool=JedisPoolUtils.getInstance();
Jedisjedis=null;
try{
jedis=jedisPool.getResource();
jedis.set("k5","0508good");
}catch(Exceptione){
e.printStackTrace();
}finally{
JedisPoolUtils.close(jedisPool,jedis);
}
}
}

配置總結

JedisPool的配置引數大部分是由JedisPoolConfig的對應項來賦值的。

maxActive:控制一個pool可分配多少個jedis例項,通過pool.getResource()來獲取;如果賦值為-1,則表示不限制;如果pool已經分配了maxActive個jedis例項,則此時pool的狀態為exhausted。

maxIdle:控制一個pool最多有多少個狀態為idle(空閒)的jedis例項。

whenExhaustedAction:表示當pool中的jedis例項都被allocated完時,pool要採取的操作,預設有三種:
WHEN_EXHAUSTED_FAIL-->表示無jedis例項時,直接丟擲NoSuchElementException
WHEN_EXHAUSTED_BLOCK-->則表示阻塞住,或者達到maxWait時丟擲JedisConnectionException
WHEN_EXHAUSTED_GROW-->則表示新建一個jedis例項,也就說設定的maxActive無用

maxWait:表示當borrow一個jedis例項時,最大的等待時間,如果超過等待時間,則直接拋JedisConnectionException;

testOnBorrow:在borrow一個jedis例項時,是否提前進行validate操作;如果為true,則得到的jedis例項均是可用的;

testOnReturn:在return給pool時,是否提前進行validate操作;

testWhileIdle:如果為true,表示有一個idleobjectevitor執行緒對idleobject進行掃描,如果validate失敗,此object會被從pool中drop掉;這一項只有在timeBetweenEvictionRunsMillis大於0時才有意義;

timeBetweenEvictionRunsMillis:表示idleobjectevitor兩次掃描之間要sleep的毫秒數;

numTestsPerEvictionRun:表示idleobjectevitor每次掃描的最多的物件數;

minEvictableIdleTimeMillis:表示一個物件至少停留在idle狀態的最短時間,然後才能被idleobjectevitor掃描並驅逐;這一項只有在timeBetweenEvictionRunsMillis大於0時才有意義;

softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基礎上,加入了至少minIdle個物件已經在pool裡面了。如果為-1,evicted不會根據idletime驅逐任何物件。如果minEvictableIdleTimeMillis>0,則此項設定無意義,且只有在timeBetweenEvictionRunsMillis>0時才有意義;

lifo:borrowObject返回物件時,是採用DEFAULT_LIFO(lastinfirstout,即類似cache的最頻繁使用佇列),如果為False,則表示FIFO佇列;

=================================================
其中JedisPoolConfig對一些引數的預設設定如下:

testWhileIdle=true
minEvictableIdleTimeMills=60000
timeBetweenEvictionRunsMillis=30000
numTestsPerEvictionRun=-1