學習方式:html
爲何要用Nosqljava
如今都是大數據時代node
大數據通常的數據庫沒法進行分析處理了mysql
至少要會Springboot+SpringCloudlinux
壓力必定會愈來愈大,適者生存android
1.單機MySQL的年代程序員
90年代,一個基本的網站訪問量通常不會太大,單個數據庫徹底足夠,那個時候,更多的去使用靜態網頁,HTML,服務器根本沒有太大的壓力思考一下,這種狀況下:整個網站的瓶頸是什麼?web
1.數據量若是太大,一個機器放不下了面試
2.數據的索引 300萬就必定要創建索引(B+Tree),一個機器內存也放不下redis
3.訪問量(讀寫混合),一個服務器承受不了
只要你出現以上的三種狀況之一,那麼你就必需要晉級
2.Memcached(緩存)+MYSQL+垂直拆分
網站80%的狀況都是在讀,每次都要去查詢數據庫的話就十分的麻煩!因此說咱們但願減輕數據的壓力,咱們可使用緩存來保證效率!發展過程:優化數據結構和索引->文件緩存(IO)->Memcachaed(當時最熱門的技術!)
3.分庫分表+水平分表+MYSQL集羣
技術和業務在發展的同時,對人的要求也愈來愈高!==本質:數據庫(讀,寫)==
早些年MYISAM:表鎖,十分影響效率!高併發下就會出現嚴重的鎖問題
轉戰INNODB:行鎖
慢慢的就開始使用分庫分表來解決寫的壓力!Mysql在那個年代推出了表分區!這個並無多少公司使用!
Mysql的集羣,很好的解決了那個年代的全部需求
4.現在最近的年代
技術爆炸
2010(按鍵手機 android1.0HTC)--2020
十年之間,世界已經發生了翻天覆地的變化(定位,也是一種數據,音樂,熱榜!)
MySQL等關係型數據庫就不夠用了,數據量不少,變化很快!
圖形數據庫 JSON數據庫
MYSQL有的時候使用它來存儲一些比較大的文件,博客,圖片!數據庫表很大,效率就低了!若是有一種數據庫來專門處理這種數據,mysql的壓力就會變得十分小(研究如何處理這些問題!)大數據的io壓力下,表幾乎無法更大
目前一個基本的互聯網項目
爲何要用NoSQL
用戶的我的信息,社交網絡,==地理位置==。用戶本身產生的數據,用戶日誌等等爆發式增加!
這時候咱們就須要使用NoSQL數據庫的,NoSQL能夠很好的處理以上的狀況!
NoSQL=Not Only SQL(不只僅是SQL)
泛指非關係型數據庫,隨着web2.0互聯網的誕生!傳統的關係型數據庫很難對付web2.0時代!尤爲是超大規模的高併發的社區!站長!暴露出來不少難以克服的問題,NOSQL在當今大數據環境下發展的十分迅速,Redis是發展最快的,並且是咱們當下必須掌握的技術!
不少的數據類型用戶的我的信息,社交網絡,地理位置。這些數據類型的存儲不須要一個固定的格式(行和列),不須要有多餘的操做就能夠橫向擴展了!Map<String,Object>使用鍵值對來控制
NoSql特色
1.方便擴展(數據之間沒有關係,很好擴展!)
2.大數據量高性能(Redis一秒能夠寫8萬次,讀取11萬次,nosql的緩存記錄級,是一種細粒度的緩存,性能比較高)
3.數據類型是多樣型的!(不須要事先設計數據庫!隨取隨用!若是是數據量十分大的表,不少人就沒法設計了!)
4.傳統RDBMS和NOSQL
傳統的RDBMS
- 結構化組織
- SQL
- 數據和關係都存在單獨的表中
- 操做操做,數據定義語言
- 嚴格的一致性
- 基礎的事務
- ……
NOSQL
- 不只僅是數據
- 沒有固定的查詢語言
- 鍵值對存儲,列存儲,文檔存儲,圖形數據庫(社交關係)
- 最終一致性
- CAP定理 和 BASE理論(異地多活!)初級架構師
- 高性能,高可用,高可擴
- ……
瞭解:3V+3高
大數據時代的3v:主要是描述問題的
1.海量Volume
2.多樣Variety
3.實時Velocity
大數據時代的3高:主要是對程序的要求
1.高併發
2.高可拓(隨時水平拆分,機器不夠了,能夠擴展機器)
3.高性能(保證用戶體驗和性能!)
真正在公司中的實踐:NOsql+RDBMS一塊兒使用纔是最強的,阿里巴巴的架構演進!
技術沒有高低之分,看你如何使用!(提高內功,思惟的提升!)
技術急不得,越是慢慢學,才能越紮實
敏捷開發,極限編程
任何一家互聯網的公司,都不可能只是簡簡單單讓用戶能用就行了
大量公司作的都是相同的業務(競品協議)
隨着這樣的競爭,業務是愈來愈完善,而後對於開發者的要求也是愈來愈高!
若是你將來想當一個架構師:沒有什麼是加一層解決不了的
1.商品的基本信息
名稱,價格,商家信息
關係型數據庫就能夠解決了(王堅:阿里雲的這羣瘋子)
淘寶內部的mysql 不是你們用的mysql
2.商品的描述,評論(文字比較多)
文檔型數據庫中,mongodb
3.圖片
分佈式文件系統 FastDFS
- 淘寶本身的TFS
- Google的 GFS
- Hadoop HDFS
- 阿里雲的 oss
4.商品的關鍵字(搜索)
- 搜索引擎 solr elasticsearch
- Isearch: 多隆
全部牛逼的人都有一段苦逼的歲月,可是你只要像sb同樣的去堅持,終將牛逼!
5.商品熱門的波段信息
- 內存數據庫
- redis tair memache
6.商品的交易,外部的支付接口
- 三方應用
要知道,一個簡單的網頁背後的技術不必定是你們所想的那麼簡單!
大型互聯網應用問題
解決問題:
![\[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-544IbeI2-1605684515441)(C:\Users\12168\AppData\Roaming\Typora\typora-user-images\image-20200811155340164.png)\]](https://img-blog.csdnimg.cn/2...
關係型數據庫:表格,行,列(POI)
kv鍵值對:
文檔型數據庫(bson格式和json同樣)
mongodb(通常必需要掌握)
列存儲數據庫
圖關係型數據庫
Redis(Remote Dictionary Server ),即遠程字典服務
是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。
區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操做寫入追加的記錄文件,而且在此基礎上實現了master-slave(主從)同步
免費和開源,是當下最熱門的nosql技術之一,也被人們稱之爲結構化數據庫
1.內存存儲,持久化,內存中是斷電即失,因此說持久化很重要(rdb,aof)2.效率高,能夠用於高速緩存
3.發佈訂閱系統
4.地圖信息分析
5.計時器,計數器(瀏覽量)
6.……
1.多樣的數據類型
2.持久化
3.集羣
4.事務
……
==Window在Github上下載(停更好久了)==
Redis推薦都是在Linux服務器上搭建的,咱們是基於Linux學習
默認端口是6379
window下使用確實簡單,可是redis推薦咱們使用linux去開發使用
「redis-benchmark」 是一個壓力測試工具!
官方自帶的性能測試工具
redis-benchmark
測試:100個併發鏈接 100000請求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
redis默認有16個數據庫
默認使用的是第0個數據庫
可使用select進行切換數據庫
select 3 //切換到第三個數據庫
dbsize //查看當前的大小
set k v //插入數據
get k //查詢數據
keys * //查詢全部的k
flushdb //清空當前庫
flushall //清空所有的數據庫
exists name //判斷name是否存在
move name 1 //移除在第一個數據庫中的name
expire name 10 //該參數10秒後過時
ttl name //查詢剩餘的過時時間 -2表示沒了
type name //查詢當前的key的類型
append key1 「hello」 //在key後面追加字符串,若是當前key不存在,就至關於setkey
strlen key1 //獲取字符串長度
incr views //數據加1
decr views //數據減1
incrby views 10 //數據加10
decrby views 10 //數據減10
getrange key 0 3 //取0-3中間的字符串
getrange key 0 -1 //取所有符串和get key是同樣的
setrange key 1 xx //替換指定位置的字符串
setex (set with expire) //設置過時時間
setnx (set if not expire) //不存在設置 (在分佈式鎖中會經常使用)若是存在就建立成功,若是不存在就建立失敗
mset //批量插入
mget //批量獲取
msetnx //批量不存在設置(原子性:一個錯誤所有錯誤)
對象
set user:1 {name:zhangsan,age:3} //設置一個user:1 對象 值爲json字符串來保存一個對象
mset user:1:name zhangsan user:2:name lisi
這裏的key是一個巧妙的設計: user:{id}:{filed} ,如此設計在redis中是徹底ok了
getset //先get而後再set 若是不存在值,則返回nil 若是存在值,獲取原來的值,並設置新的值
數據結構是相同的,jedis
string類型的使用場景:value除了是咱們的字符串還能夠是咱們的數字
粉絲效應
Redis是單線程的
明白Redis是很快的,官方表示,Redis是基於內存操做,CPU不是redis性能瓶頸,redis的瓶頸是根據機器的內存和網絡帶寬,既然可使用單線程來實現,就使用單線程了
Reids是c語言寫的,官方提供的數據爲10W+的QPS,徹底不比一樣是使用k-v的Memcache差
1.誤區1:高性能的服務器必定是多線程的
2.誤區2:多線程(cpu上下文會切換!)必定比單線程效率高!
cpu>內存>硬盤的速度要有所瞭解!
核心:redis是全部的數據所有放在內存中的,因此說使用單線程去操做效率就是最高的,多線程(cpu上下文會切換:耗時的操做),對於內存系統來講,若是沒有上下文切換效率就是最高的,屢次讀寫都是在一個cpu上的,在內存狀況下,這個就是最佳的方案!
Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它能夠用做==數據庫==、==緩存==和==消息中間件==。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內置了 複製(replication), LUA腳本(Lua scripting), LRU驅動事件(LRU eviction), 事務(transactions) 和不一樣級別的 磁盤持久化(persistence), 並經過 Redis哨兵(Sentinel)和自動 分區(Cluster)提供高可用性(high availability)
大基本數據類型
90%的java程序員使用redis只會使用一個String類型
List
基本的數據類型,列表
在redis裏面,咱們能夠把list玩成,棧,隊列,阻塞隊列
全部的list命令都是l開頭的
############################################# > lpush list one #將一個值或者多個值,插入到列表頭部(左) 1 > lpush list two 2 > lpush list three 3 > lrange list 0 -1 three two one > lrange list 0 1 three two > rpush list right #將一個值或者多個值,插入到列表頭部(右) 4 > lrange list 0 -1 three two one right ############################################# lpop rpop > lrange list 0 -1 three two one right > lpop list #移除列表的第一個元素 three > rpop list #移除列表的最後一個元素 right > lrange list 0 -1 two one ############################################# lindex > lindex list 1 #經過下標得到list中的某一個值 one > lindex list 0 two ############################################# llen > lpush list one 1 > lpush list two 2 > lpush list three 3 > (error) ERR unknown command > llen list #返回列表長度 3 ############################################# 移除指定的值! > lrange list 0 -1 three three two > lrem list 1 three #移除list集合中指定個數的value,精確匹配 1 > lrange list 0 -1 three two > lpush list three 3 > lrem list 2 three 2 > lrange list 0 -1 two ############################################# trim 修剪 > rpush mylist "hello" 1 > rpush mylist "hello1" 2 > rpush mylist "hello2" 3 > rpush mylist "hello3" 4 > ltrim mylist 1 2 #經過下標截取指定的長度,這個list已經被改變了,只剩下截取的元素 OK > lrange mylist 0 -1 hello1 hello2 ############################################# rpoplpush #移除列表最後一個元素而且移動到新的列表中 > rpush mylist "hello" 1 > rpush mylist "hello1" 2 > rpush mylist "hello2" 3 > rpoplpush mylist myotherlist #移除列表最後一個元素而且移動到新的列表中 hello2 > lrange mylist 0 -1 #查看原來的列表 hello hello1 > lrange myotherlist 0 -1 #查看目標列表中,確實存在該值 hello2 ############################################# lset 將列表中指定下標的值替換爲另一個值,更新操做 > exists list #判斷這個列表是否存在 0 > lset list 0 item #若是不存在列表咱們去更新就會報錯 ERR no such key > lpush list value1 1 > lrange list 0 0 value1 > lset list 0 item #若是存在,更新當前下標的值 OK > lrange list 0 0 item > lset list 1 other #若是不存在,則會報錯 ERR index out of range ############################################# linsert #將某個具體的value插入到列表中某個元素的前面或者後面 > rpush mylist hello 3 > rpush mylist hello1 4 > linsert mylist before hello1 other 5 > lrange mylist 0 -1 hello other hello1 hello hello1 > linsert mylist after other enw 6 > lrange mylist 0 -1 hello other enw hello1 hello hello1
小結
消息隊列(Lpush Rpop) 棧 (Lpush Lpop)
Set(集合)
set中的值是不能重複的
############################################# > sadd myset hello #set集合中添加元素 1 > sadd myset kuangshen 1 > sadd myset lovekuangshen 1 > smembers ERR wrong number of arguments for 'smembers' command > smembers myset #查看指定set的全部值 lovekuangshen kuangshen hello > sismember myset hello #判斷某一個值是否是在set集合中 1 > sismember myset world 0 ############################################# > scard myset #獲取set集合中的內容元素個數 3 > sadd myset lovekuangshen #已經存在的添加失敗 0 ############################################# > srem myset hello #移除set集合中的指定元素 1 > scard myset 2 > smembers myset lovekuangshen kuangshen ############################################# set是無序不重複集合,抽隨機 > srandmember myset #隨機抽選出一個元素 kuangshen > srandmember myset lovekuangshen > srandmember myset 2 #隨機抽取指定個數的元素 kuangshen lovekuangshen ############################################# 刪除指定的key,隨機刪除key > smembers myset lovekuangshen kuangshen > spop myset #隨機刪除一些set集合中的元素 lovekuangshen > spop myset kuangshen ############################################# 將一個指定的值,移動到另一個set集合中 > sadd myset hello 1 > sadd myset hello 0 > sadd myset world 1 > sadd myset kuangshen 1 > sadd myset2 set2 1 > smove myset myset2 kuangshen #將一個指定的值,移動到另一個set集合 1 > smembers myset world hello > smembers myset2 set2 kuangshen ############################################# > sadd key1 a 1 > sadd key1 b 1 > sadd key1 c 1 > sadd key2 c 1 > sadd key2 d 1 > sadd key2 e 1 > sadd key2 e 0 > sadd key2 key 1 > sdiff key1 key2 #差集 a b > sinter key1 key2 #交集(共同好友就能夠這樣實現) c > sunion key1 key2 #並集 c e key d b a
微博,a用戶將全部關注的人放在一個set集合中,將它的粉絲也放在一個集合中
共同關注,共同愛好,二度好友,推薦好友!(六度分割理論)
Hash(哈希)
Map集合,key-Map集合,本質和String類型沒有太大區別,仍是一個簡單的kv
set myhash field kuangshen
> hset myhash field1 kuangshen #set一個具體key-value 1 > hget myhash field1 #獲取一個字段值 kuangshen > hmset myhash field1 hello field2 world #set多個key-value OK > hmget myhash field1 field2 #獲取多個字段值 hello world > hgetall myhash #獲取所有的數據 field1 hello field2 world ############################################# > hdel myhash field1 #刪除hash指定key字段,對應的value值也就消失了 1 > hgetall myhash field2 world ############################################# hlen > hmset myhash field1 hello field2 world OK > hgetall myhash field2 world field1 hello > hlen myhash #獲取hash表的字段數量 2 ############################################# > hexists myhash field #判斷hash中指定字段是否存在 0 > hexists myhash field1 1 ############################################# #只得到全部field #只得到全部value > hkeys myhash#只得到全部field field2 field1 > hvals myhash#只得到全部value world hello ############################################# incr decr > hset myhash field3 5 #指定增量 1 > hincrby myhash field3 1 6 > hincrby myhash field3 -1 5 > hsetnx myhash field4 hello #若是不存在則能夠設置 1 > hsetnx myhash field4 world #若是存在則不能設置 0 ############################################# > hset user:1 name qinjiang 1 > hget user:1 name qinjiang
hash變動的數據user name age 尤爲是用戶信息之類的,常常變更的信息!hash更適合於對象的存儲,String更加適合字符串存儲
Zset(有序集合)
在set的基礎上,增長了一個值,set k1 v1 zset k1 score1 v1
> zadd myset 1 one #添加一個值 1 > zadd myset 2 two 3 three #添加多個值 1 > zrange myset 0 -1 one two three ############################################# 排序如何實現 > zadd salary 2500 xiaohogn #添加三個用戶 1 > zadd salary 5000 zhangsan 1 > zadd salary 500 kuangshen 1 > zrangebyscore salary -inf +inf #顯示所有的用戶,從小到大排序 kuangshen xiaohogn zhangsan > zrange salary 0 -1 kuangshen xiaohogn zhangsan > zrangebyscore salary 0 -1 #顯示所有的用戶並附帶成績 kuangshen 500 xiaohogn 2500 zhangsan 5000 > zrangebyscore salary -inf 2500 withscores #顯示工資小於2500員工的降序排列 kuangshen 500 xiaohogn 2500 > zrevrange salary 0 -1 #從大到小排序 zhangsan kuangshen ############################################# 移除rem中的元素 > zrange salary 0 -1 kuangshen xiaohogn zhangsan > zrem salary xiaohogn #移除有序集合中的指定元素 1 > zrange salary 0 -1 kuangshen zhangsan > zcard salary # 獲取有序集合中的個數 2 ############################################# > zadd myset 1 hello 1 > zadd myset 2 world 3 kuangshen 2 > zcount myset 1 3 #獲取指定區間的成員數量 3 > zcount myset 1 2 2
案例思路:set排序 存儲班級成績表,工資排序
普通消息1 重要消息2 帶權重進行判斷
排行榜應用實現
三種特殊數據類型
朋友的定位,附近的人,打車距離計算
redis的geo在redis3.2版本就推出了!這個功能能夠推算地理位置的信息,兩地之間的距離,方圓幾裏的人
getadd http://www.jsons.cn/lngcode/
#geoadd 地理位置 #規則:兩極沒法直接添加,咱們通常會直接下載城市數據,直接經過java程序一次性導入 #參數key 值(緯度經度名稱) > geoadd china:city 116.40 39.90 beijing 1 > geoadd china:city 121.47 31.23 shanghai 1 > geoadd china:city 106.50 29.53 chongqin 1 > geoadd china:city 114.08 22.54 shenzhen 1 > geoadd china:city 120.16 30.24 hangzhou 1 > geoadd china:city 108.96 34.26 xian 1 #有效的經度-180度到180度 #有效的緯度-85.05112878度到85.05112878度 #當座標位置超出上述指定範圍時,該命令將會返回一個錯誤
geopos
> geopos china:city beijing #獲取指定的城市的經度和緯度 116.39999896287918 39.900000091670925 > geopos china:city beijing shanghai 116.39999896287918 39.900000091670925 121.47000163793564 31.229999039757836
geodist
兩人之間的距離
單位以下
m表示單位爲米
km表示單位爲公里
mi表示單位爲英里
ft表示單位爲英尺
> geodist china:city beijing shanghai #查看上海到北京的直線距離 1067378.7564 > geodist china:city beijing shanghai km 1067.3788 > geodist china:city beijing chongqin km 1464.0708
georedius 以給定的經緯度爲中心
我附近的人?(得到全部附近的人的地址,定位)經過半徑來查詢
得到指定數量的人,200
全部的數據都應該錄入:china:city纔會讓結果更清晰
> georadius china:city 110 30 1000 km #以110 30這個經緯度爲中心,尋找方圓1000km內的城市 chongqin xian shenzhen hangzhou > georadius china:city 110 30 500 km chongqin xian > georadius china:city 110 30 500 km withdist #顯示到中間距離的位置 chongqin 341.9374 xian 483.8340 > georadius china:city 110 30 500 km withcoord #顯示他人的定位信息 chongqin 106.49999767541885 29.529999579006592 xian 108.96000176668167 34.2599996441893 > georadius china:city 110 30 500 km withdist withcoord count 1 #篩選出指定的用戶 chongqin 341.9374 106.49999767541885 29.529999579006592 > georadius china:city 110 30 500 km withdist withcoord count 2 chongqin 341.9374 106.49999767541885 29.529999579006592 xian 483.8340 108.96000176668167 34.2599996441893
georadiusbymember
#找出位於指定元素周圍的其餘元素 > georadiusbymember china:city beijing 1000 km beijing xian > georadiusbymember china:city shanghai 400 km hangzhou shanghai
gethash 命令-返回一個或多個位置元素的geohash表示
該命令將返回11個字符的geohash字符串
#將二維的經緯度轉換爲一維的字符串,若是兩個字符串越接近,那麼則距離越近 > geohash china:city beijing chongqin wx4fbxxfke0 wm5xzrybty0
geo 底層的實現原理其實就是Zset!咱們可使用Zset命令來操做geo
> zrange china:city 0 -1 #查看地圖中所有的元素 chongqin xian shenzhen hangzhou shanghai beijing > zrem china:city beijing #移除指定元素 1
hyperloglog
什麼是基數
A{1.3.5.7.8.9.7}
B{1,3,5,7,8}
基數(不重複的元素) =5 ,能夠接受偏差!
簡介
reids2.8.9版本就更新了Hyperloglog 數據結構
reids hyperloglog 基數統計的算法
網頁的uv(一我的訪問一個網站屢次,可是仍是算做一我的)
傳統的方式,set保存用戶的id,而後就能夠統計set中的元素數量做爲標準判斷
這個方式若是保存大量的用戶id,就會比較麻煩!咱們的目的是爲了計數,而不是保存用戶id
優勢:佔用的內存是固定的,2^64不一樣的元素的技術,只須要廢12kb內存,若是要從內存角度來比較的話,hyperloglog是首選
0.81%錯誤率,統計uv任務,能夠忽略不計的
> pfadd mykey a b c d e f g h i j #建立第一組元素 1 > pfcount mykey #統計mykey元素的基數數量 10 > pfadd mykey2 i j z x c v b n m #建立第二組元素 1 > pfcount mykey2 9 > pfmerge mykey3 mykey mykey2 #合併兩組 mykey mykey2 => mykey3 (並集) OK > pfcount mykey3 #查看並集的數量 15
若是容許容錯,那麼必定可使用hyperloglog
若是不容許容錯,就使用set或者本身的數據類型便可
bitmap
位存儲
統計疫情感染人數:010101
統計用戶信息,活躍,不活躍!登陸,未登陸!打卡,365打卡!兩個狀態的,均可以使用bitmaps
Bitmaps 位圖,數據結構!都是操做二進制位來進行記錄,就只有0和1兩個狀態!
365天=365bit 1字節 = 8bit 46個字節左右
測試
使用bitmap來記錄 週一到週日的打卡
setbit sign 0 1
0
setbit sign 1 0
0
setbit sign 3 0
0
setbit sign 4 0
0
setbit sign 5 1
0
setbit sign 6 1
0
查看某一天是否有打卡
############################################# > getbit sign 4 0 > getbit sign 6 1
統計打卡天數
> bitcount sign #統計這周的打卡記錄,就能夠看到是否有全勤 3
Redis配置詳解
Redis持久化
redis單條命令是保證原子性的,可是事務不保證原子性的,要麼同時成功,要麼同時失敗,原子性!
redis事務的本質:一組命令的集合!一個事務中的全部命令都會被序列化,在事務執行的過程當中,會按照順序執行
一次性,順序性,排他性!執行一些列的命令
-----隊列 set set set 執行 ----
redis事務沒有隔離級別的概念!
全部的命令在事務中,並無直接被執行!只有發起執行命令的時候纔會執行!exec
redis的事務
鎖:redis能夠實現樂觀鎖
正常執行事務!
> multi #開啓事務 OK #命令入隊 > set k1 v1 QUEUED > set k2 v2 QUEUED > get k2 QUEUED > set k3 v3 QUEUED > exec #執行事務 OK OK v2 OK
放棄事務
multi #開啓事務 OK > set k1 v1 QUEUED > set k2 v3 QUEUED > set k4 b5 QUEUED > discard #取消事務 QUEUED > get k4 #事務隊列中命令都不會被執行 QUEUED > (error) ERR unknown command > DISCARD QUEUED
編譯型異常(代碼有問題!命令有錯!),事務中全部的命令都不會被執行
> multi OK > set k1 v1 QUEUED > set k2 v2 QUEUED > set k3 v3 QUEUED > getset k3 #錯誤命令 QUEUED > set k4 v4 QUEUED > set k5 v5 QUEUED > exec #執行事務報錯 EXECABORT Transaction discarded because of previous errors. > get k5 #全部的命令都不會被執行 null
運行時異常(1/0),若是隊列中存在一些語法型錯誤,那麼執行命令的時候,其餘命令式能夠正常執行的,錯誤命令會拋出異常
> set k1 v1 OK > multi OK > incr k1 #會執行的時候失敗 QUEUED > set k2 v2 QUEUED > set k3 v3 QUEUED > get k3 QUEUED > exec OK OK v3 > get k2 v2 > get k3 v3 > get k1 v1 > incr k1 ERR value is not an integer or out of range #雖然第一條命令報錯了,可是依舊正常執行成功了
監控!watch(面試常問)
悲觀鎖
樂觀鎖
redis測監視測試
正常執行成功 > set money 100 OK > set out 0 OK > watch money #監視money對象 OK > multi #事務正常結束,數據期間沒有發生變更,這個時候就正常執行成功 OK > decrby money 20 QUEUED > incrby out 20 QUEUED > exec 80 20
測試多線程修改值,使用watch能夠當作redis的樂觀鎖操做!
> set money 100 OK > set out 0 OK > watch money #監視money OK > multi OK > decrby money 20 QUEUED > incrby out 20 QUEUED > exec #執行以前,另一個線程,修改了咱們的值,這個時候,就會致使事務執行失敗 null
若是修改失敗,獲取最新的值就好
咱們要使用java來操做redis
什麼是jedis是redis官方推薦的java鏈接開發工具!使用java操做redis,若是你要使用java操做redis,那麼必定要對jedis十分的熟悉測試
1.導入對應的依賴
<!--導入jedis的包--> <dependencies> <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.3.0</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.73</version> </dependency> </dependencies>
2.編碼測試:
package com.kuang; import redis.clients.jedis.Jedis; public class testPing { public static void main(String[] args) { //1.new jedis對象便可 Jedis jedis = new Jedis("127.0.0.1",6379); //jedis全部的命令就是咱們以前學習的全部指令~!因此以前的指令學習很重要 System.out.println(jedis.ping()); } }
輸出
#### 經常使用的api
String
List
Set
Hash
Zset
全部的api命令,就是咱們對應的上面的指令!因此以前的指令學習很重要
SpringBoot操做數據:spring-data jpa jdbc mongodb redis
SpringData也是和Springboot齊名的項目
說明:在springboot2.x後,原來使用的jedis被替換成爲了lettuce
jedis:採用的是直連,多個線程操做的話是不安全的,若是想要避免不安全的,使用jedis pool鏈接池!BIO阻塞
lettuce:採用netty,實例能夠在多個線程中進行共享,不存在線程不安全的狀況!能夠減小線程數量,更像Nio模式
Springboot 全部的配置類,都有一個自動配置類
自動配置類都會綁定一個properties 配置文件
源碼分析
整合測試一下
1.導入依賴
2.配置鏈接
3.測試
Redis實現訂閱發佈(消息隊列)
主從複製,是指將一臺redis服務器的數據,複製到其餘redis服務器。前者稱爲主節點(master/leader),後者稱爲從節點(slave/follower);數據的複製都是單向的,只能由主節點到從節點。master以寫爲主,slave以讀爲主。
==默認狀況下,每臺redis服務器都是主節點==;且一個主節點能夠有多個從節點(或沒有從節點),但一個從節點只能有一個主節點。
主從複製的做用主要包括:
1.數據冗餘:主從複製實現了數據的熱備份,是持久化以外的一種數據冗餘方式
2.故障恢復:當主節點出現問題時,能夠由從節點提供服務,實現快速的故障恢復,其實是一種服務的冗餘
3.負載均衡:在主從複製的基礎上,配合讀寫分離,能夠由主節點提供寫服務,由從節點提供讀服務(即寫redis服務時應用讀取主節點,讀redis服務時應用鏈接從節點),分擔服務器負載;尤爲是在寫少讀多的場景下,經過多個從節點分擔讀負載,能夠大大提升redis服務器的併發量
4.高可用基石(集羣):除了上述做用之外,主從複製仍是哨兵和集羣可以實施的基礎,所以說主從複製是redis高可用的基礎
通常來講,==要將redis應用於項目工程中,只使用的一臺redis服務器是萬萬不能的==,緣由以下:
1.從結構上,單個redis服務器會發生單點故障,而且一臺服務器須要處理全部的請求負載,壓力較大;
2.從容量上,單個redis服務器內存容量有限,就算一臺redis服務器容量爲256g,也不能將全部內存用做於redis存儲內存,通常來講,==單臺redis最大使用內存不該該超過20g==
電商網站上的商品,通常都是一次上傳,無數次瀏覽的,說專業點也就是「多讀少寫」
主從複製,讀寫分離!80%的狀況下都是在進行讀操做!減緩服務器的壓力!架構中常用!一主二從!
只要在公司中,主從複製就是必需要使用的
,由於在真實的項目中不可能單機使用redis
只配置從庫,不配置主庫
> info replication #查看當前庫的信息 # Replication role:master #角色 master connected_slaves:0 #沒有從機 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
複製3個配置文件,而後修改對應的信息
1.端口
2.pid名字
3.log文件名字
4.dump.rdb名字
咱們通常狀況下只用配置從機就行了
一個主機兩個從機
slaveof 127.0.0.1 6379
真實得從主配置應該在配置文件中配置,這樣的話是永久的,咱們這裏使用的是命令,暫時的!
細節
主機能夠寫,從機不能寫只能讀!主機中全部的信息和數據,都會自動被從機保存
主機寫:
從機只能讀取內容:
測試:主機斷開鏈接,從機依舊鏈接到主機的,可是沒有寫操做,這個時候,主機若是回來了,從機依舊能夠直接獲取到主機寫的信息!
若是是使用命令行來配置的主從,這個時候若是重啓了,就會自動變回主機!只要變爲從機,立馬就會從主機中獲取值!
複製原理
slave啓動成功鏈接到master後會發送一個sync同步命令
Master接到命令,啓動後臺的存盤進程,同時收集全部接收到的用於修改數據集命令,在後臺進程執行完畢以後,==master將傳送整個數據文件到slave,並完成一次徹底同步==
==全量複製==:而salve服務在接收到數據庫文件數據後,將其存盤並加載到內存中
==增量複製==:master繼續將新的全部收集到的修改命令依次傳給slave,完成同步
可是隻要是從新鏈接master,一次徹底同步(全量複製)將被自動執行
咱們的數據必定能夠在從機中看到!
層層鏈路
上一個M鏈接下一個S!
這個時候也能夠完成咱們的主從複製!
若是沒有老大了,這個時候能不能選擇一個老大出來呢?手動!
謀權篡位
若是主機斷開了鏈接,咱們可使用SLAVEOF no one
讓本身變成主機!其餘的節點就能夠手動鏈接到最新的這個主節點(手動)!若是這個時候老大修復了,那就從新鏈接
自動選舉老大的模式
概述:
主從切換技術的方法是:當主服務器宕機後,須要手動把一臺服務器切換爲主服務器,這就須要人工干預,費時費力,還會形成一段時間內服務不可用。這不是一種推薦的方式,更多時候,咱們優先考慮哨兵模式。redis從2.8開始正式提供了Sentinel(哨兵模式)架構來解決這個問題
謀權篡位的自動版,可以後臺監控主機是否故障,若是故障了根據投票數自動將從庫轉換爲主庫
哨兵模式是一種特殊的模式,首先redis提供了哨兵的命令,哨兵是一個獨立的進程,做爲進程,它會獨立運行,其原理是哨兵經過發送命令,等待redis服務器響應,從而監控運行的多個redis實例
這裏哨兵有兩個做用
然而一個哨兵進程對redis服務器進行監控,可能會出現問題,爲此,咱們可使用多個哨兵進行監控,各個哨兵之間還會進行監控,這樣酒就造成了多哨兵模式
假設主服務器宕機,哨兵1先檢測到這個結果,系統並不會立刻進行failover過程,僅僅是哨兵1主觀的認爲主服務器不可用,這個現象成爲主觀下線。當後面的哨兵也檢測到主服務器不可用,而且數量達到必定值時,那麼哨兵之間就會進行一次投票,投票結果由一個哨兵發起,進行failover[故障轉移]操做。切換成功後,就會經過發佈訂閱模式,讓各個哨兵把本身監控的從服務器實現切換主機,這個過程稱爲客觀下線
測試
咱們目前的狀態是一主二從
1.配置哨兵配置文件
# sentinel monitor 被監控的名稱 host port 1 sentinel monitor myredis 127.0.0.1 6379 1
後面的數字1,表明主機掛了,slave投票看讓誰接替成爲主機,票數最多的,就會成爲主機!
2.啓動哨兵
若是Master節點斷開了,這個時候就會從從機中隨機選擇一個服務器(這裏面有一個投票算法)
哨兵日誌
若是主機此時回來了,只能歸併到新的主機下,當作從機,這就是哨兵模式的規則!
哨兵模式
優勢:
1.哨兵集羣,基於主從複製模式,全部的主從配置的優勢它全有
2.主從能夠切換,故障能夠轉移,系統的可用性就會更好
3.哨兵模式就是主從模式的升級,手動到自動,更加健壯!
缺點:
1.redis很差啊在線擴容的,集羣容量一旦到達上限,在線擴容就十分麻煩
2.實現哨兵模式的配置實際上是很麻煩的,裏面有不少選擇
哨兵模式的所有配置
# Example sentinel.conf # port <sentinel-port> port 8001 # 守護進程模式 daemonize yes # 指明日誌文件名 logfile "./sentinel1.log" # 工做路徑,sentinel通常指定/tmp比較簡單 dir ./ # 哨兵監控這個master,在至少quorum個哨兵實例都認爲master down後把master標記爲odown # (objective down客觀down;相對應的存在sdown,subjective down,主觀down)狀態。 # slaves是自動發現,因此你不必明確指定slaves。 sentinel monitor MyMaster 127.0.0.1 7001 1 # master或slave多長時間(默認30秒)不能使用後標記爲s_down狀態。 sentinel down-after-milliseconds MyMaster 1500 # 若sentinel在該配置值內未能完成failover操做(即故障時master/slave自動切換),則認爲本次failover失敗。 sentinel failover-timeout TestMaster 10000 # 設置master和slaves驗證密碼 sentinel auth-pass TestMaster testmaster123 sentinel config-epoch TestMaster 15 #除了當前哨兵, 還有哪些在監控這個master的哨兵 sentinel known-sentinel TestMaster 127.0.0.1 8002 0aca3a57038e2907c8a07be2b3c0d15171e44da5 sentinel known-sentinel TestMaster 127.0.0.1 8003 ac1ef015411583d4b9f3d81cee830060b2f29862
Redis緩存的使用,極大的提高了應用程序的性能和效率,特別是數據查詢方面。但同時,它也帶來了一些問題。其中,最要害的問題,就是數據的一致性問題,從嚴格意義上講,這個問題無解。若是對數據的一致性要求很高,那麼就不能使用緩存。
另外的一些典型問題就是,緩存穿透,緩存雪崩和緩存擊穿。目前,業界也都有比較流行的解決方案
概覽
緩存穿透的概念很簡單,用戶想要查詢一個數據,發現redis內存數據庫沒有,也就是緩存沒有命中,因而向持久層數據庫查詢。發現也沒有,因而本次查詢失敗。當用戶不少的時候,緩存都沒有命中,因而都去請求了持久層數據庫。這會給持久層數據庫形成很大的壓力,這個時候就至關於出現了緩存穿透。
解決方案
布隆過濾器
布隆過濾器是一種數據結構,對全部可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄,從而避免了對底層存儲系統的查詢壓力
緩存空對象
當存儲層不命中後,即便返回的空對象也將其緩存起來,同時會設置一個過時時間,以後再訪問這個數據將會直接從緩存中獲取,保護了後端數據源;
可是這種方法會存在兩個問題:
1.若是空值可以被緩存起來,這就意味着緩存須要更多的空間存儲更多的鍵,由於這當中可能會有不少的空值的鍵
2.即便對空值設置了過時時間,仍是會存在緩存層的數據會有一段時間窗口的不一致,這對於須要保持一致性的業務會有影響。
概述
微博服務器宕機
這裏須要注意和緩存擊穿的區別,緩存擊穿,是指一個key很是熱點,在不停的扛着大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。
當某個key在過時的瞬間,有大量的請求併發訪問,這類數據通常是熱點數據,因爲緩存過時,會同時訪問數據庫來查詢最新數據,而且回寫緩存,會致使數據庫瞬間壓力過大 。
解決方案
設置熱點數據永不過時
從緩存層面來看,沒有設置過時時間,因此不會出現熱點key過時後產生的問題
加互斥鎖
分佈式鎖:使用分佈式鎖,保證對於每一個key同時只有一個線程去查詢後端服務,其餘線程沒有得到分佈式鎖的權限,所以只須要等待便可。這種方式將高併發的壓力轉移到了分佈式鎖,所以對分佈式鎖的考驗很大
服務器的高可用問題
概念
緩存雪崩,是指在某一個時間段,緩存集中過時失效,redis宕機!
產生雪崩的緣由之一,好比在寫文本的時候,立刻就要雙十二零點,很快就會迎來一波搶購,這波商品時間比較集中的放入了緩存,假設緩存一個小時,那麼到了凌晨一點鐘的時候,這批商品的緩存就都過時了。而對這批商品訪問查詢,都落到了數據庫上,對於數據庫而言,就會產生週期性的壓力波峯。因而全部的請求都會達到存儲層,存儲層的調用量會暴增,形成存儲層也會掛掉的狀況
其實集中過時,倒不是很是致命,比較致命的緩存雪崩,是緩存服務器某個節點宕機或斷網。由於天然造成的緩存雪崩,必定是在某個時間段集中建立緩存,這個時候,數據庫也是考研頂住壓力的。無非就是對數據庫產生週期性的壓力而已。而緩存服務節點的宕機,對數據庫服務器形成的壓力是不可預知的,頗有可能瞬間就把數據庫壓垮。
雙十一:停掉一些服務,(保證主要的服務可用!)==服務降級==
解決方案
redis高可用
這個思想的含義是,既然redis有可能掛掉,那我多增設幾臺redis,這樣一臺掛掉以後其餘的還能夠繼續工做,其實就是搭建的集羣(異地多活)
限流降級(在springCloud講解過!)
這個解決方案的思想是,在緩存失效後,經過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。好比對某個key只容許一個線程查詢數據和寫緩存,其餘線程等待。
數據預熱
數據加熱的含義就是在正式部署以前,我線把可能的數據先預先訪問一遍,這樣部分可能大量訪問的數據就會加載到緩存中。在即將發生大併發訪問前手動觸發加載緩存不一樣的key,設置不一樣的過時時間,讓緩存失效的時間點儘可能均勻