進(jìn)程、線程萤皂、協(xié)程
進(jìn)程
進(jìn)程是系統(tǒng)分配資源的最小單位敛苇,一個(gè)應(yīng)用程序就是一個(gè)進(jìn)程,每個(gè)進(jìn)程都是相互獨(dú)立的
線程
線程是程序運(yùn)行的不同路徑恋沃,每個(gè)進(jìn)程至少有一個(gè)線程,可以有多個(gè)線程必搞。線程有自己獨(dú)立的堆棧、寄存器和共享進(jìn)程資源囊咏。線程的多并發(fā)是系統(tǒng)對(duì)線程調(diào)度的上下文切換恕洲,CPU在不同時(shí)間片段執(zhí)行不同的線程,每一次上下文切換都會(huì)中斷當(dāng)前線程梅割,保留當(dāng)前線程狀態(tài)霜第,切換到其它線程執(zhí)行,過(guò)程是由用戶態(tài)-> 內(nèi)核態(tài)->用戶態(tài)户辞。相對(duì)協(xié)程而言會(huì)耗費(fèi)更多內(nèi)存和時(shí)間
協(xié)程
協(xié)程是一個(gè)輕量級(jí)的線程泌类,它是一個(gè)特殊的函數(shù),函數(shù)可以被掛起后執(zhí)行底燎。在Go中刃榨,由關(guān)鍵字go定義的函數(shù)就是一個(gè)協(xié)程,可以實(shí)現(xiàn)高并發(fā)弹砚,由系統(tǒng)調(diào)度切換,但不需要由用戶態(tài)到內(nèi)核態(tài)枢希,協(xié)程的通訊不是共享內(nèi)存桌吃,而是消息傳遞,在Go中協(xié)程的通訊是通過(guò)channel管道實(shí)現(xiàn)的苞轿。進(jìn)程和線程上下文切換過(guò)程中茅诱,切換內(nèi)容保存在內(nèi)核棧中,協(xié)程則保存在自己的變量中(用戶椗皇海或者堆)
用戶態(tài)和內(nèi)核態(tài)
用戶態(tài)到內(nèi)核態(tài)怎樣切換让簿?
Go的協(xié)程
Go的channel
Go的select
Go的切片
- new(T) 為每個(gè)新的類(lèi)型T分配一片內(nèi)存,初始化為 0 并且返回類(lèi)型為*T的內(nèi)存地址:這種方法 返回一個(gè)指向類(lèi)型為 T秀睛,值為 0 的地址的指針尔当,它適用于值類(lèi)型如數(shù)組和結(jié)構(gòu)體;它相當(dāng)于 &T{}蹂安;
- make(T) 返回一個(gè)類(lèi)型為 T 的初始值椭迎,它只適用于3種內(nèi)建的引用類(lèi)型:slice、map 和 channel田盈;
數(shù)組:arr := [...]int{1,2,3}
切片:slice := []int{1,2,3}
slice := make([]int,5,10)
len(slice)長(zhǎng)度 cap(slice)容量
nil切片 var silce[]int
空切片 slice := []{}
對(duì)于底層數(shù)組容量是k的切片slice[i:j]來(lái)說(shuō)
長(zhǎng)度:j-i
容量:k-j
slice[1:3],長(zhǎng)度就是3-1=2畜号,容量是5-1=4
slice := []int{1, 2, 3, 4, 5}
newSlice := slice[1:3]
fmt.Printf("newSlice長(zhǎng)度:%d,容量:%d",len(newSlice),cap(newSlice))
Redis
遠(yuǎn)程字典服務(wù)(Remote Dictionary Server),C語(yǔ)言寫(xiě)的,支持網(wǎng)絡(luò)允瞧,可基于內(nèi)存亦可持久化的日志型简软、Key-Value數(shù)據(jù)庫(kù)。
5種數(shù)據(jù)類(lèi)型:String述暂、Lists痹升、hashes、Set畦韭、Zset
還有范圍查詢:bitmaps疼蛾、hyperloglogs和地理空間(geospatial)索引半徑查詢
KV鍵值對(duì),每秒10萬(wàn)+查詢
作用場(chǎng)景:內(nèi)容緩存艺配,主要用于處理大量數(shù)據(jù)的高訪問(wèn)負(fù)載察郁,也用于一些日志系統(tǒng)。
優(yōu)點(diǎn):查找速度快
缺點(diǎn):數(shù)據(jù)無(wú)結(jié)構(gòu)化转唉,通常只被當(dāng)作字符串或者二進(jìn)制數(shù)據(jù)
特性:
1皮钠、多樣的數(shù)據(jù)類(lèi)型
2、 持久化赠法,定期把內(nèi)存中的數(shù)據(jù)同步到磁盤(pán)中
3鳞芙、 集群
4、 事物
redis是單線程的,redis的瓶頸是機(jī)器內(nèi)存和網(wǎng)絡(luò)帶寬原朝。
作用:
- 數(shù)據(jù)庫(kù)
- 緩存
- 消息中間件MQ
字符串
微信公眾號(hào)文章瀏覽量應(yīng)用
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> decr views
(integer) 1
127.0.0.1:6379> incrby views 10
(integer) 11
127.0.0.1:6379>
#GETRANGE
127.0.0.1:6379> keys *
1) "views"
127.0.0.1:6379> set key1 "hello,123"
OK
127.0.0.1:6379> get key1
"hello,123"
127.0.0.1:6379> get range key 0 3
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> getrange key 0 3
""
127.0.0.1:6379> getrange key1 0 3
"hell"
127.0.0.1:6379> getrange key1 0 -1
"hello,123"
127.0.0.1:6379> getrange key1 0 3
#setex (set with expire) #設(shè)置過(guò)期時(shí)間
127.0.0.1:6379> setex key3 30 'hello'
OK
127.0.0.1:6379> ttl key3
(integer) 22
127.0.0.1:6379> ttl key3
(integer) 19
127.0.0.1:6379>
#setnx (set if not exist) #如果key不存在 在分布式鎖中會(huì)常常使用
127.0.0.1:6379> setnx mykey 'redis'
(integer) 1
127.0.0.1:6379> setnx mykey 'mongodb'
(integer) 0
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379>
#########################
#批量設(shè)置驯嘱,批量獲取 mset mget
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "mykey"
4) "k1"
5) "views"
6) "key1"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4
(integer) 0 #原子性操作,失敗一個(gè)都會(huì)失敗
127.0.0.1:6379>
##########################
#對(duì)象
127.0.0.1:6379> set user:1 {name:zhangsan,age:lisi} #設(shè)置一個(gè)user:1對(duì)象 值為json字符串來(lái)保存對(duì)象
OK
127.0.0.1:6379> get user:1
"{name:zhangsan,age:lisi}"
127.0.0.1:6379>
##########################
#getset
127.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb
"redis"
127.0.0.1:6379> get db
"mongodb"
127.0.0.1:6379>
List
棧喳坠、隊(duì)列鞠评、阻塞
127.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1
1) "three"
2) "two"
127.0.0.1:6379> rpush list 1
(integer) 4
127.0.0.1:6379> rpush list 0 -1
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "1"
5) "0"
6) "-1"
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpop list
"-1"
127.0.0.1:6379>
127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379>
127.0.0.1:6379> llen list
(integer) 4
127.0.0.1:6379>
#移除指定數(shù)量的值
127.0.0.1:6379> lrem list 1 one
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "1"
3) "0"
127.0.0.1:6379>
#trim 修剪
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "0"
127.0.0.1:6379>
#####################
#rpoplpush 移除列表最后一個(gè)元素并添加新的元素
127.0.0.1:6379> lset list 0 'ww'
OK
127.0.0.1:6379> lrange list 0 -1
1) "ww"
2) "0"
127.0.0.1:6379>
127.0.0.1:6379> linsert list before "ww" "nn"
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "nn"
2) "ww"
3) "0"
127.0.0.1:6379>
- List實(shí)際上是鏈表結(jié)構(gòu),before Note after ,left, right都可以插入
- 如果key不存在壕鹉,創(chuàng)建新的鏈表
- 如果key存在剃幌,創(chuàng)建新的內(nèi)容
Set
set中的值不能重復(fù)
kuangdeMacBook-Pro:~ kuang$ redis-cli
127.0.0.1:6379> sadd myset "kaung"
(integer) 1
127.0.0.1:6379> sadd myset 'xiao'
(integer) 1
127.0.0.1:6379> smembers myset
1) "xiao"
2) "kaung"
127.0.0.1:6379> ismember myset xiao
(error) ERR unknown command 'ismember'
127.0.0.1:6379> sismember myset 'xiao'
(integer) 1
127.0.0.1:6379>
#獲取集合中值的數(shù)量
127.0.0.1:6379> scard myset
(integer) 2
127.0.0.1:6379>
#移除
127.0.0.1:6379> srem myset 'xiao'
(integer) 1
127.0.0.1:6379>
#隨機(jī)抽選出一個(gè)元素
127.0.0.1:6379> srandmember myset
"kaung"
127.0.0.1:6379>
#隨機(jī)移除集合中的元素
127.0.0.1:6379> sadd myset 'k1'
(integer) 1
127.0.0.1:6379> sadd myset 'k2'
(integer) 1
127.0.0.1:6379> smembers myset
1) "k2"
2) "k1"
3) "kaung"
127.0.0.1:6379> spop myset
"kaung"
127.0.0.1:6379> spop myset
"k1"
127.0.0.1:6379> smembers myset
1) "k2"
127.0.0.1:6379>
#將指定的值移動(dòng)到另外一個(gè)集合中
127.0.0.1:6379> sadd myset 2
(integer) 1
127.0.0.1:6379> sadd myset2 'v1'
(integer) 1
127.0.0.1:6379> smove v1 myset
(error) ERR wrong number of arguments for 'smove' command
127.0.0.1:6379> smove myset2 'v1' myset
(integer) 0
127.0.0.1:6379> smove myset2 myset 'v1'
(integer) 1
127.0.0.1:6379> smembers myset2
(empty list or set)
127.0.0.1:6379> smove myset myset2 'v1'
(integer) 1
127.0.0.1:6379> smembers myset2
1) "v1"
127.0.0.1:6379>
# 差集、交集晾浴、并集 如微博共同關(guān)注
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2
1) "b"
2) "a"
127.0.0.1:6379> SDIFF key2 key1
1) "e"
2) "d"
127.0.0.1:6379> SINTER key1 key2
1) "c"
127.0.0.1:6379> SUNION key1 key2
1) "e"
2) "a"
3) "c"
4) "b"
5) "d"
127.0.0.1:6379>
Hash(哈希)
Map集合负乡,key-map,值是map集合 key field->value;
hash變更的數(shù)據(jù)user name age脊凰,尤其是用戶信息之類(lèi)的抖棘,經(jīng)常變動(dòng)的信息!hash更適合于對(duì)象的存儲(chǔ)狸涌,String更加適合于字符串存儲(chǔ)切省;
127.0.0.1:6379> hset myhash field1 kuang
(integer) 1
127.0.0.1:6379> hget myhash field1
"kuang"
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
#長(zhǎng)度
127.0.0.1:6379> hlen myhash
(integer) 1
#是否存在
127.0.0.1:6379> hexists myhash field1
(integer) 0
127.0.0.1:6379> hexists myhash field2
(integer) 1
#獲取所有的keys
127.0.0.1:6379> hkeys myhash
1) "field2"
#獲取所有的值
127.0.0.1:6379> hvals myhash
1) "world"
#自增
127.0.0.1:6379> hset myhash field3 5
(integer) 1
127.0.0.1:6379> hincrby myhash field3 1
(integer) 6
#如果不存在添加
127.0.0.1:6379> hsetnx myhash field4 hello
(integer) 1
127.0.0.1:6379> hsetnx myhash field4 world
(integer) 0
127.0.0.1:6379>
Zset(有序集合)
在set的基礎(chǔ)上加了值
127.0.0.1:6379> zadd myzset 1 one
(integer) 1
127.0.0.1:6379> zadd myzset 2 two 3 three
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379>
# 實(shí)現(xiàn)排序
127.0.0.1:6379> zadd salary 100 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 200 lisi
(integer) 1
127.0.0.1:6379> zadd salary 300 wangwu
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "zhangsan"
2) "100"
3) "lisi"
4) "200"
5) "wangwu"
6) "300"
127.0.0.1:6379>
127.0.0.1:6379> zrangebyscore salary -inf 250 withscores
1) "zhangsan"
2) "100"
3) "lisi"
4) "200"
127.0.0.1:6379>
#移除 zrem
127.0.0.1:6379> zrem salary lisi
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> zcard salary
(integer) 2
127.0.0.1:6379>
#從大到小排序 反轉(zhuǎn)
127.0.0.1:6379> zrevrange salary 0 -1
1) "wangwu"
2) "zhangsan"
127.0.0.1:6379>
#獲取指定區(qū)間的成員數(shù)量
127.0.0.1:6379> zcount salary 100 200
(integer) 2
127.0.0.1:6379>
Geosptial地理位置
3.2版本以后,可以推算地理位置的信息帕胆,兩地之間的距離朝捆,方圓幾里的人
#添加地理位置
#規(guī)則:兩級(jí)無(wú)法直接添加,我們一般會(huì)下載城市數(shù)據(jù)懒豹,直接通過(guò)程序一次性寫(xiě)入
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> geopos china:city beijing
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> geodist china:city beijing shanghai
"1067378.7564"
127.0.0.1:6379> georadius china:city 110 30
(error) ERR wrong number of arguments for 'georadius' command
127.0.0.1:6379> georadius china:city 110 30 1000 km
(empty list or set)
127.0.0.1:6379> georadius china:city 110 39 1000 km
1) "beijing"
127.0.0.1:6379>
#將二位的經(jīng)緯度轉(zhuǎn)為一維的字符串
127.0.0.1:6379> geohash china:city beijing
1) "wx4fbxxfke0"
#移除
127.0.0.1:6379> zrem china:city beijing
(integer) 1
127.0.0.1:6379>
hyperloglog基數(shù)統(tǒng)計(jì)的算法
優(yōu)點(diǎn):占用的內(nèi)存固定芙盘,2^64不同元素的技術(shù),只需要128KB內(nèi)存
應(yīng)用:網(wǎng)頁(yè)的UV(一個(gè)人訪問(wèn)一個(gè)網(wǎng)站多次脸秽,但算作一個(gè)人)
傳統(tǒng)方式:set保存用戶id,然后統(tǒng)計(jì)set中元素的數(shù)量作為判斷標(biāo)準(zhǔn)
127.0.0.1:6379> PFadd mykey a b c d e f g h i j
(integer) 1
127.0.0.1:6379> PFcount mykey
(integer) 10
127.0.0.1:6379> PFadd mykey2 i j z x c v b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 15
127.0.0.1:6379>
Bitmaps
位存儲(chǔ)
統(tǒng)計(jì)用戶信息何陆,活躍,不活躍豹储,登錄,未登錄淘这,打卡剥扣,365打卡。兩個(gè)狀態(tài)的都可以使用Bitmaps
Bitmaps位圖铝穷,數(shù)據(jù)結(jié)構(gòu)钠怯,都是操作二進(jìn)制位來(lái)進(jìn)行記錄,就只有0和1兩個(gè)狀態(tài)
365天=365bit 1字節(jié)=8bit 46個(gè)字節(jié)左右
使用bitmap來(lái)記錄周一到周日到打卡
周一:1 周二:0周三:0 周四:1 ...
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
127.0.0.1:6379>
#查看某一天是否打卡
127.0.0.1:6379> getbit sign 3
(integer) 1
#統(tǒng)計(jì)打卡的天數(shù)
27.0.0.1:6379> bitcount sign
(integer) 3
127.0.0.1:6379>
Hyperloglog基數(shù)統(tǒng)計(jì)算法
特點(diǎn):占用內(nèi)存固定曙聂,2^64個(gè)不同元素的技術(shù)晦炊,只需要12KB內(nèi)存。
什么是基數(shù)
A{1,3,5,7,9} B{1,3,,7,8}
基數(shù):不重復(fù)的元素 = 5
2.8.9就更新了Hyperlogolog數(shù)據(jù)結(jié)構(gòu)
網(wǎng)頁(yè)的UV(一個(gè)人訪問(wèn)一個(gè)網(wǎng)站多次,但是還是算作一個(gè)人)
傳統(tǒng)方式:set保存用戶的id,然后統(tǒng)計(jì)set中元素的數(shù)量作為標(biāo)準(zhǔn)断国。這種方式需要保存大量的用戶ID贤姆。我們的目的是為了計(jì)數(shù)而不是保存用戶ID。
有0.81%的錯(cuò)誤率稳衬!統(tǒng)計(jì)UV霞捡,可以忽略不計(jì)。
127.0.0.1:6379> PFadd mykey a b c d e f g h i j
(integer) 1
127.0.0.1:6379> PFcount mykey
(integer) 10
127.0.0.1:6379> PFadd mykey2 i j z x c v b n m
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 15
127.0.0.1:6379>
統(tǒng)計(jì)時(shí)薄疚,只統(tǒng)計(jì)不重復(fù)的數(shù)據(jù),適合用作UV統(tǒng)計(jì)
127.0.0.1:6379> pfadd key a b c a d
(integer) 1
127.0.0.1:6379> pfcount key
(integer) 4
127.0.0.1:6379> pfadd a a a a a f g d
(integer) 1
127.0.0.1:6379> pf count
(error) ERR unknown command 'pf'
127.0.0.1:6379> pfcount count
(integer) 0
127.0.0.1:6379> pfcount key
(integer) 4
127.0.0.1:6379>
事務(wù)
Redis事務(wù)本質(zhì):一組命令的集合碧信!一個(gè)事務(wù)中的所有命令都會(huì)被序列化,在事務(wù)執(zhí)行過(guò)程中街夭,會(huì)按照順序執(zhí)行砰碴!
一次性、順序性板丽、排他性呈枉!
Redis事物沒(méi)有隔離級(jí)別的概念
所有的命令在事務(wù)中,并沒(méi)有直接被執(zhí)行檐什,只有發(fā)起執(zhí)行命令的時(shí)候才會(huì)執(zhí)行
- Redis單條命令是原子性的碴卧,但事務(wù)不保證原子性
redis事務(wù) - 開(kāi)啟事務(wù)(multi)
- 命令入隊(duì)
- 執(zhí)行事務(wù) (exce)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v2"
4) OK
127.0.0.1:6379>
#放棄事務(wù)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k2
(nil)
127.0.0.1:6379> get k2
#異常
- 運(yùn)行時(shí)異常,如果事務(wù)隊(duì)列中存在語(yǔ)法性乃正,那么執(zhí)行命令的時(shí)候住册,其它命令是可以正常執(zhí)行的,錯(cuò)誤命令拋出異常瓮具!
- 編譯型異常(代碼有問(wèn)題荧飞!命令有錯(cuò)!)名党,事務(wù)中的所有命令都不會(huì)被執(zhí)行
悲觀鎖
- 很悲觀叹阔,認(rèn)為什么時(shí)候都會(huì)出現(xiàn)問(wèn)題,無(wú)論做什么都會(huì)加鎖传睹,效率低
樂(lè)觀鎖 - 很樂(lè)觀耳幢,認(rèn)為什么時(shí)候都不會(huì)出現(xiàn)問(wèn)題,所有不會(huì)上鎖欧啤!更新數(shù)據(jù)的時(shí)候去判斷一下睛藻,在此期間是否有人修改過(guò)數(shù)據(jù)。Watch監(jiān)控.
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY out 20
QUEUED
127.0.0.1:6379> exec #事務(wù)正常結(jié)束邢隧,數(shù)據(jù)期間沒(méi)有發(fā)生變動(dòng)店印,這個(gè)時(shí)候就正常執(zhí)行
1) (integer) 80
2) (integer) 20
127.0.0.1:6379>
#測(cè)試多線程修改值,使用watch監(jiān)視money倒慧,可以當(dāng)作redis的樂(lè)觀鎖
如第一條線程還未執(zhí)行exec時(shí)按摘,又開(kāi)啟一個(gè)線程包券,直接修改money的值,再次執(zhí)行exec就會(huì)失敗
使用watch可以當(dāng)作redis的樂(lè)觀鎖(面試常問(wèn))
redis內(nèi)存滿了的策略
配置環(huán)境中設(shè)置
LRU是Least Recently Used的縮寫(xiě)炫贤,即最近最少使用;
- volatile-lru:只對(duì)設(shè)置了過(guò)期時(shí)間的key進(jìn)行LRU
- alleys-lru:刪除lru算法的key
- volatile-random: 隨機(jī)刪除即將過(guò)期的key
- allkeys-random:隨機(jī)刪除
- volatile-ttl:刪除即將過(guò)期的
- noeviction: 永不過(guò)期溅固,返回錯(cuò)誤
持久化
快照配置:
如果900s內(nèi),如果至少有一個(gè)key進(jìn)行了修改照激,我們及時(shí)進(jìn)行持久化
save 900 1
默認(rèn)使用RDB发魄,可以在配置文件中開(kāi)啟AOF(appendonly)
APPEND ONLY 模式 aof配置
appendonly no #默認(rèn)不是開(kāi)啟aof模式的,默認(rèn)是使用rdb方式持久化俩垃,在大部分情況下励幼,rdb完全夠用。
appendfilename 'appendonly.aof' #持久化的文件名字
appendsysnc always #每次修改都會(huì)sync 消耗性能
appendfsync everysec #每秒執(zhí)行一次sync口柳,可能會(huì)丟失這1s的數(shù)據(jù)
appendfsync no #不執(zhí)行sync,這個(gè)時(shí)候系統(tǒng)會(huì)自己同步數(shù)據(jù)苹粟,速度最快
RDB(Redis DataBase)
優(yōu)點(diǎn):
- 適合大規(guī)模數(shù)據(jù)的恢復(fù)!
- 對(duì)數(shù)據(jù)完整性的要求不高跃闹!
缺點(diǎn): - 需要一定的時(shí)間間隔進(jìn)行操作嵌削,如果意外宕機(jī)了,這個(gè)最后一次修改的數(shù)據(jù)就沒(méi)有了望艺。
- fork進(jìn)程的時(shí)候苛秕,會(huì)占用一定的空間。
有時(shí)候在生產(chǎn)環(huán)境會(huì)對(duì)rdb數(shù)據(jù)進(jìn)行備份
配置:save 900 1 默認(rèn)配置不要隨便修改
在指定的時(shí)間內(nèi)將內(nèi)存中的數(shù)據(jù)集快照寫(xiě)入硬盤(pán)找默,也就是行話講的S napshot快照艇劫,它恢復(fù)時(shí)將快照文件直接讀到內(nèi)存。
Redis會(huì)單獨(dú)創(chuàng)建(fork)一個(gè)子進(jìn)程來(lái)進(jìn)行持久化惩激,會(huì)先將數(shù)據(jù)寫(xiě)入一個(gè)臨時(shí)文件中店煞,待持久化過(guò)程都結(jié)束了,再用這個(gè)臨時(shí)文件替換上次持久化好的文件风钻,整個(gè)過(guò)程中顷蟀,主進(jìn)程是不進(jìn)行任何IO操作的。這就確保了極高的性能骡技。如果需要進(jìn)行大規(guī)模數(shù)據(jù)的恢復(fù)鸣个,且對(duì)數(shù)據(jù)恢復(fù)的完整性不是非常敏感,那RDB方式比AOF方式更加高效布朦,RDB的缺點(diǎn)時(shí)最好一次持久化后的數(shù)據(jù)可能丟失囤萤。
rdb保存的文件是dump.rdb ;
如何恢復(fù)rdb文件
- 只需要將rdb文件放在我們r(jià)edis啟動(dòng)目錄就可以喝滞,redis啟動(dòng)的時(shí)候會(huì)自動(dòng)檢查dump.rdb恢復(fù)其中的數(shù)據(jù)
- 查看需要存在的位置
127.0.0.1:6379> config get dir
1) "dir"
2) "/Users/kuang/lnmp1"
127.0.0.1:6379>
AOF(Append Only File)
優(yōu)點(diǎn):
- 每一次修改都會(huì)同步;
- 每秒同步一次膏秫,可能會(huì)丟失一秒的數(shù)據(jù)
- 從不同步右遭,效率最高
缺點(diǎn): - 相對(duì)于數(shù)據(jù)文件來(lái)說(shuō)做盅,aof遠(yuǎn)遠(yuǎn)大于rdb,恢復(fù)的速度比rdb慢
- aof運(yùn)行的效率也比rdb慢,所以我們r(jià)edis默認(rèn)的配置就是rdb持久化窘哈!
將我們的所有命令都記錄下來(lái)吹榴。
以日志的形式來(lái)記錄每一個(gè)寫(xiě)操作,將redis執(zhí)行過(guò)的所有指令記錄下來(lái)(讀操作不記錄)滚婉,只允許追加文件但不可以改寫(xiě)文件图筹,redis啟動(dòng)之初會(huì)讀取該文件重新構(gòu)建數(shù)據(jù),換言之让腹,redis重啟的話就會(huì)根據(jù)日志文件的內(nèi)容將寫(xiě)指令從前到后執(zhí)行一次以完成數(shù)據(jù)的恢復(fù)工作远剩。
AOF保存的是appendonly.aof文件;
如果aof文件有錯(cuò)誤骇窍,這個(gè)時(shí)候redis是啟動(dòng)不起來(lái)的瓜晤。redis提供了一個(gè)修復(fù)工具redis-check-aof
kuangdeMacBook-Pro:~ kuang$ redis-check-aof --fix appendonly.aof
#線程一
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set money 100
QUEUED
127.0.0.1:6379> set out 0
QUEUED
127.0.0.1:6379> exec #線程二執(zhí)行之后執(zhí)行
(nil) #沒(méi)有成功
127.0.0.1:6379>
#線程二
kuangdeMacBook-Pro:~ kuang$ redis-cli
127.0.0.1:6379> set money 10
OK
127.0.0.1:6379>
#解除觀察
127.0.0.1:6379> unwatch
OK
127.0.0.1:6379> watch money
如果事務(wù)修改失敗,解鎖腹纳,獲取最新的值痢掠,再次觀察,然后執(zhí)行新的事務(wù)
拓展
- RDB 持久化方式能夠在指定的時(shí)間間隔內(nèi)對(duì)你的數(shù)據(jù)進(jìn)行快照存儲(chǔ)
- AOF持久化方式記錄每次對(duì)服務(wù)器的寫(xiě)操作嘲恍,當(dāng)服務(wù)器重啟的時(shí)候會(huì)重新執(zhí)行這些命令來(lái)恢復(fù)原始數(shù)據(jù)足画,AOF命令以Redis協(xié)議追加保存每次寫(xiě)的操作到文件的末尾,Redis還能對(duì)AOF文件進(jìn)行后臺(tái)重寫(xiě)佃牛,使得AOF文件的提及不至于太大
- 只做緩存淹辞,如果你只希望你的數(shù)據(jù)在服務(wù)器運(yùn)行的時(shí)候存在,你可以不使用任何持久化
- 同時(shí)開(kāi)啟兩種持久化方式
- 在這種情況下吁脱,當(dāng)redis重啟的時(shí)候會(huì)優(yōu)先載入AOF文件來(lái)恢復(fù)原始的數(shù)據(jù)桑涎,因?yàn)樵谕ǔG闆r下AOF文件保存的數(shù)據(jù)集要比RDB文件保存的數(shù)據(jù)集完整
- RDB的數(shù)據(jù)不實(shí)時(shí),同時(shí)使用兩者服務(wù)器重啟也只會(huì)找到AOF文件兼贡,那要不要只使用AOF文件呢攻冷?不建議,因?yàn)镽DB更適合用于備份數(shù)據(jù)庫(kù)(AOF在不斷變化不好備份)遍希,快速重啟等曼,而且不會(huì)有AOF可能潛在的Bug,留作一個(gè)萬(wàn)一的手段
- 性能建議
- 因?yàn)镽DB文件只用作后備用途,建議在Slave上持久化RDB文件凿蒜,而且只要15分鐘備份一次就夠了禁谦,只保留save 900 1這條規(guī)則。
- 如果Enable AOF废封,好處是在最?lèi)毫拥那闆r下也只會(huì)丟失不超過(guò)2秒的數(shù)據(jù)州泊,啟動(dòng)腳本簡(jiǎn)單只load自己的AOF文件就可以了,代價(jià)一是帶來(lái)了持續(xù)的IO漂洋,二是AOF rewrite 過(guò)程中產(chǎn)生的新數(shù)據(jù)寫(xiě)到新文件造成的阻塞幾乎是不可避免的遥皂,要是硬盤(pán)許可力喷,盡可能減少rewrite頻率。AOF重寫(xiě)基礎(chǔ)文件大小默認(rèn)64M太小演训,可以設(shè)置到5G弟孟。
- 如果不Enable AOF,僅靠Master-Slave Replication實(shí)現(xiàn)高可用性也可以样悟,代價(jià)是如果Master/Slave同時(shí)倒掉拂募,會(huì)丟失幾十分鐘的數(shù)據(jù),啟動(dòng)腳本也要比較兩個(gè)Master/Slave中的RDB文件窟她,載入教新的那個(gè)陈症。微博就是這種架構(gòu)。
發(fā)布訂閱
Redis發(fā)布訂閱(pub/sub)是一種消息通訊模式:發(fā)送者發(fā)生消息礁苗,訂閱者接收消息爬凑。微博的關(guān)注系統(tǒng)。
Redis客戶端可以訂閱任何數(shù)量的頻道试伙。
第一個(gè):消息發(fā)送者 第二個(gè):頻道 第三個(gè):消息訂閱在
場(chǎng)景:
- 實(shí)時(shí)消息系統(tǒng)嘁信!
- 實(shí)時(shí)聊天(頻道當(dāng)作聊天室,將信息回顯給所有人即可)
-
訂閱疏叨,關(guān)注系統(tǒng)
稍微復(fù)雜的場(chǎng)景就會(huì)用消息中間件MQ()
測(cè)試
#訂閱頻道 訂閱端
127.0.0.1:6379> subscribe kuang
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "kuang"
3) (integer) 1
#等待讀取推送信息
1) "message"
2) "kuang"
3) "hello"
1) "message" # 消息
2) "kuang" # 哪個(gè)頻道的消息
3) "redis" # 消息內(nèi)容
#向頻道發(fā)送消息 發(fā)送端
kuangdeMacBook-Pro:~ kuang$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> publish kuang "hello"
(integer) 1
127.0.0.1:6379> publish kuang "redis"
(integer) 1
127.0.0.1:6379>
主從復(fù)制
概念:主從復(fù)制潘靖,是指將一臺(tái)Redis服務(wù)的數(shù)據(jù),復(fù)制到其他的Redis服務(wù)器中蚤蔓,前者稱(chēng)為主節(jié)點(diǎn)Master以寫(xiě)為主,后者稱(chēng)為從節(jié)點(diǎn)Slave以讀為主卦溢。數(shù)據(jù)復(fù)制是單向的,只能從主到從秀又。
主從復(fù)制的主要作用包括:
1单寂、數(shù)據(jù)冗余:主從復(fù)制實(shí)現(xiàn)了數(shù)據(jù)的熱備份
2、故障恢復(fù):主節(jié)點(diǎn)出現(xiàn)問(wèn)題時(shí)吐辙,可以由從節(jié)點(diǎn)提供服務(wù)宣决,實(shí)現(xiàn)快速的故障恢復(fù)
3、 負(fù)責(zé)均衡:主負(fù)責(zé)寫(xiě)昏苏,從負(fù)責(zé)讀
4尊沸、高可用的基石:主從復(fù)制是哨兵和集群的基礎(chǔ)。
單臺(tái)redis最大使用內(nèi)存不應(yīng)該超過(guò)20G贤惯。
默認(rèn)情況下洼专,每臺(tái)redis服務(wù)器都是主節(jié)點(diǎn);且一個(gè)主節(jié)點(diǎn)可以有多個(gè)從節(jié)點(diǎn)孵构,但一個(gè)從節(jié)點(diǎn)只能有一個(gè)主節(jié)點(diǎn)屁商。
配置:
#info 查看信息
127.0.0.1:6379> info
# Server
redis_version:4.0.9
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:7b8134d888556d22
redis_mode:standalone
os:Darwin 20.4.0 x86_64
arch_bits:64
multiplexing_api:kqueue
atomicvar_api:atomic-builtin
gcc_version:4.2.1
process_id:31972
run_id:64c18b1f659df291d920871f2dcf598f1523378d
tcp_port:6379
uptime_in_seconds:3649
uptime_in_days:0
hz:10
lru_clock:14057410
executable:/Users/kuang/redis-server
config_file:
# Clients
connected_clients:2
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
# Memory
used_memory:1470864
used_memory_human:1.40M
used_memory_rss:1245184
used_memory_rss_human:1.19M
used_memory_peak:1470864
used_memory_peak_human:1.40M
used_memory_peak_perc:100.06%
used_memory_overhead:1048576
used_memory_startup:981040
used_memory_dataset:422288
used_memory_dataset_perc:86.21%
total_system_memory:8589934592
total_system_memory_human:8.00G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:0.85
mem_allocator:libc
active_defrag_running:0
lazyfree_pending_objects:0
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1624670098
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
# Stats
total_connections_received:2
total_commands_processed:11
instantaneous_ops_per_sec:0
total_net_input_bytes:403
total_net_output_bytes:20500
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:1
pubsub_patterns:0
latest_fork_usec:1188
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
# Replication
role:master
connected_slaves:0
master_replid:ea9f90513a821a4d5997e2b28a531e158a0b8da7
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:2.29
used_cpu_user:0.78
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
# Cluster
cluster_enabled:0
# Keyspace
db0:keys=19,expires=0,avg_ttl=0
127.0.0.1:6379>
復(fù)制3個(gè)配置文件,然后修改對(duì)應(yīng)的信息
1颈墅、 端口
2蜡镶、 pid名字
3溯职、 log文件名字
4、 dump.rdb名字
啟動(dòng)
配置從機(jī):
臨時(shí)配置:
127.0.0.1:6379> slaveof 127.0.0.1 6379 #找誰(shuí)當(dāng)作自己的主機(jī)
![image.png](https://upload-images.jianshu.io/upload_images/10144198-9cfb97e35e6b541a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
永久配置:
在config中修改主機(jī)ip和端口
>細(xì)節(jié)
- 主機(jī)可寫(xiě)帽哑,從機(jī)不可寫(xiě),寫(xiě)報(bào)錯(cuò)
- 主機(jī)斷開(kāi)連接叹俏,從機(jī)依舊連接到主機(jī)妻枕,但是沒(méi)有寫(xiě)操作。如果主機(jī)恢復(fù)正常后粘驰,依舊可以讀取主機(jī)信息屡谐。
>復(fù)制原理
- slave啟動(dòng)成功連接到master后會(huì)發(fā)送一個(gè)sync同步命令
- Master接到命令,啟動(dòng)后臺(tái)的存盤(pán)進(jìn)程蝌数,同時(shí)收集所有接收到的用于修改數(shù)據(jù)的命令愕掏,在后臺(tái)進(jìn)程執(zhí)行完畢后,master將傳送整個(gè)數(shù)據(jù)文件到slave顶伞,并完成一次完全同步
- 全量復(fù)制:slave服務(wù)在收到數(shù)據(jù)庫(kù)文件后饵撑,將其存盤(pán)并加載到內(nèi)存中
- 增量復(fù)制: Master繼續(xù)將新的所有收集到的修改命令依次傳給slave,完成同步
- 但是只要是重新連接master,一次完全同步(全量復(fù)制)將被自動(dòng)執(zhí)行
>如果主機(jī)斷開(kāi)了,可以使用SLAVEOF on one 使從節(jié)點(diǎn)變成主節(jié)點(diǎn)
哨兵模式
哨兵模式能夠后臺(tái)監(jiān)控主機(jī)是否故障唆貌,如果故障了根據(jù) 投票計(jì)數(shù)自動(dòng)將從苦轉(zhuǎn)化為主庫(kù)滑潘,當(dāng)主庫(kù)恢復(fù)時(shí),主庫(kù)自動(dòng)變?yōu)閺膸?kù)锨咙。
哨兵模式是一種特殊的模式,首先Redis提供了哨兵的命令,哨兵是一個(gè)獨(dú)立的進(jìn)程泣栈,作為進(jìn)程册烈,它會(huì)獨(dú)立運(yùn)行,其原理是哨兵通過(guò)發(fā)送命令骂倘,等待Redis服務(wù)器響應(yīng)眼滤,從而監(jiān)控運(yùn)行多個(gè)redis實(shí)例。
哨兵的作用:
- 通過(guò)發(fā)送命令稠茂,讓redis服務(wù)器返回監(jiān)控其運(yùn)行狀態(tài)柠偶,包括主機(jī)和從服務(wù)器
- 當(dāng)哨兵監(jiān)測(cè)到master宕機(jī),會(huì)自動(dòng)將slave切換成master,然后通過(guò)發(fā)布訂閱模式通知其他的從服務(wù)器睬关,修改配置文件诱担,讓它們切換主機(jī)
然爾一個(gè)哨兵進(jìn)程對(duì)redis服務(wù)器進(jìn)行監(jiān)控,可能出現(xiàn)問(wèn)題电爹,為此蔫仙,我們可以使用多個(gè)哨兵進(jìn)行監(jiān)控,各個(gè)哨兵之間還會(huì)進(jìn)行監(jiān)控丐箩,這就形成了多哨兵模式摇邦。
假設(shè)主服務(wù)器宕機(jī)恤煞,哨兵1先檢測(cè)到這個(gè)結(jié)果,系統(tǒng)并不會(huì)馬上進(jìn)行failover過(guò)程施籍,僅僅是哨兵1主觀的認(rèn)為主服務(wù)器不可用居扒,這個(gè)現(xiàn)象稱(chēng)為主觀下線。當(dāng)后面的哨兵也檢測(cè)到主服務(wù)器不可用丑慎,并且數(shù)量達(dá)到一定值時(shí)喜喂,那么哨兵之間就會(huì)進(jìn)行一次投票,投票的結(jié)果由一個(gè)哨兵發(fā)起竿裂,進(jìn)行failover故障轉(zhuǎn)移操作玉吁,切換成功后,就會(huì)通過(guò)發(fā)布訂閱模式腻异,讓各個(gè)哨兵把自己監(jiān)控的從服務(wù)器實(shí)現(xiàn)切換主機(jī)进副,這個(gè)過(guò)程稱(chēng)為客觀下線。
配置哨兵
目前狀態(tài)是一主二從
1悔常、 配置哨兵配置文件sentinel.conf
#被監(jiān)控的名稱(chēng) host port 1 后面的這個(gè)數(shù)字1影斑,代表主機(jī)掛了,slave投票看讓誰(shuí)來(lái)接替主機(jī)机打,票數(shù)最多的鸥昏,就會(huì)成為主機(jī)
kuangdeMacBook-Pro:~ kuang$ sentinel monitor myredis 127.0.0.1 6379 1
2、 啟動(dòng)哨兵
redis-sentinel monitor kconfig/sentinel.conf
如果過(guò)Master節(jié)點(diǎn)斷開(kāi)姐帚,會(huì)自動(dòng)選擇以一個(gè)從機(jī)作為主機(jī)(有自己的算法)
優(yōu)點(diǎn):
- 哨兵集群吏垮,基于主從復(fù)制,所有主從配置的優(yōu)點(diǎn)罐旗,它全有
- 主從可以切換膳汪,故障可以轉(zhuǎn)移,系統(tǒng)的可用性會(huì)更好
- 哨兵模式就是主從模式的升級(jí)九秀,手動(dòng)到自動(dòng)遗嗽,更加健壯
缺點(diǎn): - redis不好在線擴(kuò)容,集群容量一旦到達(dá)上限鼓蜒,在線擴(kuò)容就十分麻煩
- 實(shí)現(xiàn)哨兵模式的配置其實(shí)是很麻煩的痹换,里面有很多選擇
全部配置
1、端口 2都弹、工作目錄 3娇豫、主機(jī)節(jié)點(diǎn) 4、主機(jī)密碼 5畅厢、故障轉(zhuǎn)移時(shí)間 6冯痢、通知腳本(如主機(jī)宕機(jī)了,發(fā)送郵件通知)
緩存穿透和雪崩
[圖片上傳中...(image.png-bbefaf-1624679561120-0)]
緩存穿透:用戶查詢數(shù)據(jù)浦楣,緩存和數(shù)據(jù)庫(kù)中都沒(méi)能命中袖肥,查詢失敗,下次查詢依舊需要訪問(wèn)數(shù)據(jù)庫(kù)振劳,導(dǎo)致數(shù)據(jù)庫(kù)壓力變大
解決方案:
-
布隆過(guò)濾器--布隆過(guò)濾器是一種數(shù)據(jù)結(jié)構(gòu)椎组,對(duì)所有可能查詢的參數(shù)以hash形式存儲(chǔ),在控制層先進(jìn)行校驗(yàn)历恐,不符合則丟棄庐杨,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力;
- 緩存空對(duì)象--如果空值能夠被緩存起來(lái)夹供,這就意味著緩存需要更多的空間存儲(chǔ)更多的鍵,因?yàn)檫@當(dāng)中可能會(huì)有很多的空鍵仁堪; 即使對(duì)空值設(shè)置過(guò)了過(guò)期時(shí)間哮洽,還是會(huì)存在緩存層和存儲(chǔ)空間層會(huì)有一段時(shí)間窗口額度不一致,這對(duì)于需要保持一致性的業(yè)務(wù)會(huì)有影響弦聂。
緩存擊穿
這里需要注意和緩存擊穿的區(qū)別鸟辅,緩存擊穿,是指一個(gè)key非常熱點(diǎn)莺葫,在不停的扛著大并發(fā)匪凉,大并發(fā)集中對(duì)著個(gè)點(diǎn)進(jìn)行訪問(wèn),當(dāng)這個(gè)key在失效瞬間捺檬,持續(xù)的大并發(fā)就穿破緩存再层,直接請(qǐng)求數(shù)據(jù)庫(kù)。
解決方案:
- 設(shè)置熱點(diǎn)永不過(guò)期堡纬;
- 加互斥鎖:使用分布式鎖(setnx)聂受,保證對(duì)于每一個(gè)key同時(shí)只有一個(gè)線程去查詢后端服務(wù),其他線程沒(méi)有獲得分布式鎖的權(quán)限烤镐,因此只需要等待即可蛋济,這種方式將高并發(fā)的壓力轉(zhuǎn)移到了分布式鎖,因此對(duì)分布式鎖的考驗(yàn)較大炮叶。
緩存雪崩
在某個(gè)時(shí)間段 碗旅,緩存集中過(guò)期失效 或者是緩存服務(wù)器某個(gè)節(jié)點(diǎn)出現(xiàn)宕機(jī)或者斷網(wǎng)。因?yàn)樽匀恍纬傻木彺嫜┍谰迪ぃ欢ㄊ窃谀硞€(gè)時(shí)間段集中創(chuàng)建緩存祟辟,這個(gè)時(shí)候,數(shù)據(jù)庫(kù)也是可以頂住壓力的侣肄,無(wú)非就是對(duì)數(shù)據(jù)庫(kù)產(chǎn)生周期性的壓力而已川尖。而緩存服務(wù)節(jié)點(diǎn)的宕機(jī),對(duì)數(shù)據(jù)庫(kù)服務(wù)器造成的壓力是不可預(yù)知的,很可能瞬間就把數(shù)據(jù)庫(kù)壓垮
解決方案:
- redis高可用:即搭建集群叮喳;
- 限流降級(jí):加鎖或者隊(duì)列來(lái)控制讀數(shù)據(jù)庫(kù)寫(xiě)緩存的線程數(shù)量被芳,比如對(duì)某個(gè)key只允許一個(gè)線程查詢和寫(xiě)數(shù)據(jù),其他線程等待
- 數(shù)據(jù)預(yù)熱:在正式部署前馍悟,手動(dòng)觸發(fā)預(yù)先訪問(wèn)一遍 加載緩存不同的key,設(shè)置不同的過(guò)期時(shí)間畔濒,讓緩存失效的時(shí)間點(diǎn)盡量均勻。
MySQL
流程
連接器->查詢緩存->分析器->優(yōu)化器->執(zhí)行器
慢查詢
-- 查詢超過(guò)多少秒才記錄
show VARIABLES like 'long_query_time';
-- 慢查詢開(kāi)啟狀態(tài)锣咒,慢查詢?nèi)罩敬娣盼恢?show VARIABLES like 'slow_query%';
-- 打開(kāi)慢日志記錄開(kāi)關(guān)
set GLOBAL slow_query_log = on;
-- 設(shè)置慢查詢?nèi)罩?set GLOBAL slow_query_log_file = '';
-- 設(shè)置超過(guò)2秒慢日志
set GLOBAL long_query_time = 2;
--查看事務(wù)
SELECT * FROM information_schema.INNODB_LOCKs;
--查看鎖
SELECT * FROM information_schema.INNODB_LOCK_waits;
--查看鎖等待
SELECT * FROM information_schema.INNODB_TRX;
kill trx_mysql_thread_id
關(guān)系型數(shù)據(jù)庫(kù)和非關(guān)系型數(shù)據(jù)庫(kù)
關(guān)系型:(SQL)
- 通過(guò)表和表之間侵状,行和列之間的關(guān)系進(jìn)行數(shù)據(jù)的存儲(chǔ)
非關(guān)系型:(NOT Noly SQL NoSQL) - redis,mongodb
- 非關(guān)系型數(shù)據(jù)庫(kù),key-value形式,對(duì)象存儲(chǔ)毅整,通過(guò)對(duì)象的自身的屬性來(lái)決定
死鎖
多個(gè)事務(wù)同時(shí)占有同一個(gè)資源并相互作用趣兄,并請(qǐng)求鎖定其他事務(wù)所占有的資源,從而導(dǎo)致相互依賴悼嫉,相互等待出現(xiàn)死鎖艇潭;
解決辦法:
a.Innodb引擎提供了檢測(cè)死鎖的方法,能檢測(cè)到死鎖的相互依賴戏蔑,系統(tǒng)直接報(bào)錯(cuò)蹋凝,否則會(huì)出現(xiàn)非常慢的查詢;
b.如果查詢時(shí)間超過(guò)設(shè)定的等待時(shí)間放棄鎖請(qǐng)求;
c.Innodb采用的死鎖處理方式是总棵,將持有最少行級(jí)排它鎖的事務(wù)進(jìn)行回滾鳍寂。
死鎖配置:
Innodb_lock_wait_timeout 超時(shí)時(shí)間設(shè)置
行鎖的本質(zhì)是鎖定主鍵索引
如果只鎖定的是非主鍵索引,會(huì)先鎖定非主鍵索引情龄,最終找到主鍵索引迄汛。
如果沒(méi)有索引會(huì)表鎖定;
查詢表被鎖定的方法
show open TABLES where In_use >0;
show processlist;
InnoDB和MyISAM的區(qū)別
InnoDB:
- 支持事務(wù)
- 外鍵約束
- 數(shù)據(jù)行鎖定
MyISAM
- 全文索引
- 表空間較小
物理空間位置
所有的數(shù)據(jù)庫(kù)文件都存在data目錄下,一個(gè)文件夾對(duì)應(yīng)一個(gè)數(shù)據(jù)庫(kù)骤视;
本質(zhì)還是文件的存儲(chǔ)
MySQL引擎在物理文件上的區(qū)別
- InnoDB在數(shù)據(jù)庫(kù)表中只有一個(gè).frm文件隔心,以及上級(jí)目錄下的ibdata1文件
- MYISAM 對(duì)應(yīng)文件
- .frm 表結(jié)構(gòu)對(duì)應(yīng)的文件
- .MYD 數(shù)據(jù)文件(data)
- *.MYI 索引文件(Index)
設(shè)置數(shù)據(jù)庫(kù)表的字符集編碼
支持中文的utf8
修改表
修改表名
ALTER TABLE teacher RENAME AD teacher1;
增加表的字段 字段名 列屬性
ALTER TABLE teacher1 ADD age INT(11);
修改表的字段(修改約束)
ALTER TABLE teacher1 MODIFY age VARCHAR(11)
字段重命名
ALTER TABLE teacher1 CHANGE age age1 INT(11);
刪除表的字段
ALTER TABLE teacher1 DROP age1
刪除表
DROP TABLE IF EXISTS teacher1
** MySQL數(shù)據(jù)管理**
外鍵(了解即可)
刪除有外鍵關(guān)系的表的時(shí)候,必須要先刪除引用別人的表(從表)尚胞,再刪除被引用的表(主表)硬霍;
JION連表查詢(7種查詢)
inner join: 如果表中至少有一個(gè)匹配,就返回行 (交集為基準(zhǔn))
left join: 會(huì)從左表中返回所有的值笼裳,即使右表中沒(méi)有匹配 (左表為基準(zhǔn))
right join:會(huì)從右表中返回所有的值唯卖,即使左表中沒(méi)有匹配 (右表為基準(zhǔn))
自連接及查詢
-- 常用函數(shù)
-- 數(shù)學(xué)運(yùn)算
SELECT ABS(-8) -- 絕對(duì)值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.4) -- 向下取整
SELECT RAND() -- 返回一個(gè) 0-1 之間的隨機(jī)數(shù)
SELECT SIGN() -- 判斷一個(gè)數(shù)的符號(hào) 0-0 負(fù)數(shù)返回-1 正數(shù)返回 1
-- 字符串函數(shù)
SELECT CHAR LENGTH('你好') -- 長(zhǎng)度
SELECT CONCAT('你','在','哪') -- 拼接字符串
SELECT INSERT('我的編程',i,2,'php') -- 查詢,從某個(gè)位置開(kāi)始替換某個(gè)長(zhǎng)度
SELECT LOWER('Str')
SELECT UPPER('str')
SELECT INSTR('kaung','a') -- 查找位置a
SELECT REPLACE('str','from_str','to_str')
SELECT SUBSTR(str FROM pos FOR len)
SELECT REVERSE(str)
-- 日期函數(shù)
SELECT CURRENT_DATE() -- 獲取當(dāng)前日期
SELECT CURDATE() -- 獲取當(dāng)前日期
SELECT NOW() -- 獲取當(dāng)前日期
SELECT LOCALTIME() -- 獲取本地時(shí)間
SELECT SYSDATE()
SELECT YEAR(now())
SELECT DAY(NOW())
DML語(yǔ)言
聚合函數(shù)
SELECT COUNT('name'); -- count(字段)躬柬,會(huì)忽略所有的null值
SELECT COUNT(1); -- count(1)拜轨,會(huì)統(tǒng)計(jì)表中的所有數(shù)據(jù),包含null,不會(huì)忽略所有的null值
SELECT COUNT(*); -- count(*)允青,會(huì)統(tǒng)計(jì)表中的所有數(shù)據(jù)橄碾,包含null,不會(huì)忽略所有的null值 如果多個(gè)列且沒(méi)有主鍵 效率 count(1) > count(*)
-- 執(zhí)行效率COUNT(列) > count(1) > count(*) 如果只有一個(gè)字段 COUNT(*)最優(yōu)
SELECT SUM([DISTINCT] expr)
SELECT AVG([DISTINCT] expr)
SELECT MIN([DISTINCT] expr)
SELECT MAX([DISTINCT] expr)
-- having 用于過(guò)濾 group 分組
SELECT SubjectName,AVG(studentResult) as 平均分,MAX(StudentResult) as 最高分,MIN(StudentResult) from result r
INNER JOIN subject sub on r.SubjectNo = sub.SubjectNo GROUP BY r.SubjectNo HAVING 平均分 > 80
事務(wù)(ACID)
要么都成功,要么都失敗
將一組SQL放在一個(gè)批次中去執(zhí)行
原子性(一起執(zhí)行不可分割)、一致性(前后狀態(tài)一致)法牲、隔離線史汗、持久性(事務(wù)如果沒(méi)有體檢恢復(fù)到原來(lái)的狀態(tài),提交后不可逆)
- 原子性:要么都成功拒垃,要么都失敗
- 一致性:事務(wù)前后的數(shù)據(jù)完整性要保持一致停撞,如1000塊轉(zhuǎn)賬,最終還是1000悼瓮,不會(huì)出現(xiàn)A轉(zhuǎn)出200B沒(méi)有收到200的情況
- 持久性: 事務(wù)一旦提交不可逆戈毒,被持久化到數(shù)據(jù)庫(kù)中
- 隔離性:事務(wù)的隔離性是多個(gè)用戶并發(fā)訪問(wèn)的數(shù)據(jù)庫(kù)時(shí),數(shù)據(jù)庫(kù)為每個(gè)用戶開(kāi)啟的事務(wù)横堡,不能被其他事務(wù)的操作數(shù)據(jù)所干擾埋市,事務(wù)之間要相互隔離
隔離所導(dǎo)致的問(wèn)題
臟讀:指一個(gè) 事務(wù) 讀取了另一個(gè) 事務(wù) 未提交的數(shù)據(jù)
不可重復(fù)讀:在一個(gè)事務(wù)內(nèi)讀取表中某一行數(shù)據(jù),多次讀取結(jié)果不同
幻讀:在一個(gè)事務(wù)內(nèi)讀取到了別人的事務(wù)插入的數(shù)據(jù)命贴,導(dǎo)致前后讀取數(shù)據(jù)不一致
1道宅、臟數(shù)據(jù)所指的就是未提交的數(shù)據(jù)。也就是說(shuō)套么,一個(gè)事務(wù)正在對(duì)一條記錄做修改,在這個(gè)事務(wù)完成并提交之前碳蛋,這條數(shù)據(jù)是處于待定狀態(tài)的(可能提交也可能回滾)胚泌,這時(shí),第二個(gè)事務(wù)來(lái)讀取這條沒(méi)有提交的數(shù)據(jù)肃弟,并據(jù)此做進(jìn)一步的處理玷室,就會(huì)產(chǎn)生未提交的數(shù)據(jù)依賴關(guān)系。這種現(xiàn)象被稱(chēng)為臟讀笤受。
2穷缤、不可重復(fù)讀(Non-Repeatable Reads):一個(gè)事務(wù)先后讀取同一條記錄,而事務(wù)在兩次讀取之間該數(shù)據(jù)被其它事務(wù)所修改箩兽,則兩次讀取的數(shù)據(jù)不同津肛,我們稱(chēng)之為不可重復(fù)讀。
3汗贫、幻讀(Phantom Reads):一個(gè)事務(wù)按相同的查詢條件重新讀取以前檢索過(guò)的數(shù)據(jù)身坐,卻發(fā)現(xiàn)其他事務(wù)插入了滿足其查詢條件的新數(shù)據(jù),這種現(xiàn)象就稱(chēng)為幻讀落包。
4部蛇、幻讀是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改咐蝇,比如這種修改涉及到表中的“全部數(shù)據(jù)行”涯鲁。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入“一行新數(shù)據(jù)”抹腿。那么岛请,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還存在沒(méi)有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺(jué)一樣.一般解決幻讀的方法是增加范圍鎖RangeS幢踏,鎖定檢索范圍為只讀髓需,這樣就避免了幻讀。
MySQL備份
數(shù)據(jù)庫(kù)備份的方式
- 直接拷貝物理文件(data文件)
- 在可視化數(shù)據(jù)庫(kù)工具中房蝉,手動(dòng)導(dǎo)出
- mysqldump在命令行導(dǎo)出
#導(dǎo)出
kuangdeMacBook-Pro:~ kuang$ mysqldump -hlocalhost -uroot -p123456 school student > D:/a.sql
#導(dǎo)入
進(jìn)入mysql
執(zhí)行:source D:/a.sql
主從復(fù)制
- 主數(shù)據(jù)庫(kù)將改變的數(shù)據(jù)記錄在本地的二進(jìn)制日志中(binary log);
- 從數(shù)據(jù)庫(kù)開(kāi)啟IO現(xiàn)程僚匆,將主庫(kù)中的log,拷貝到自己的relay log(中繼日志文件)中
- 從數(shù)據(jù)庫(kù)通過(guò)SQL線程將日志文件數(shù)據(jù)讀取到數(shù)據(jù)庫(kù)中
MYSQL主從復(fù)制,異步搭幻,串行咧擂,延遲
master:slave = 1:n
配置: 主機(jī)
1.關(guān)閉防火墻,
2.允許遠(yuǎn)程訪問(wèn)
3.conf中配置server-id=1 唯一標(biāo)識(shí)
- 配置二進(jìn)制文件路徑log-bin,放到data/mysql-bin目錄下
- 錯(cuò)誤記錄文件路徑log-err 放到data/mysql-err
- 主從同步時(shí) 忽略的數(shù)據(jù)庫(kù)
binlog-ingore-db=mysql - (可選)指定主從同步時(shí)檀蹋,同步哪些數(shù)據(jù)
binlog-do-db=test -
主機(jī)授權(quán)哪臺(tái)計(jì)算機(jī)中的數(shù)據(jù)庫(kù)是自己的從數(shù)據(jù)庫(kù)
從機(jī)
1.conf中配置server-id=2 唯一標(biāo)識(shí)
- log-bin=mysql-bin 路徑
- replicate-do-db=test
-
linux中的數(shù)據(jù) 授權(quán)哪臺(tái)計(jì)算機(jī)是自己的的主機(jī)
5.進(jìn)入從機(jī)的MySQL中配置主機(jī)相關(guān)信息
如圖:
開(kāi)啟主從同步
開(kāi)啟后查詢:
show master status \G
show slave status \G
觀察:Slave_IO_Running和Slave_SQL-Running是否正常
讀寫(xiě)分離(阿里云Mysql服務(wù)現(xiàn)在支持讀寫(xiě)分離功能)
主從同步的基礎(chǔ)上松申,實(shí)現(xiàn)讀寫(xiě)分離,需要中間件(MyCat)
mysql中解決并發(fā)問(wèn)題(臟讀俯逾、幻讀贸桶、不可重復(fù)讀)方法:讀寫(xiě)分離,因?yàn)樽x操作沒(méi)有并發(fā)問(wèn)題桌肴。如果不用讀寫(xiě)分離需要加鎖處理并發(fā)問(wèn)題皇筛,效率低下
mycat的作用
MyCat實(shí)現(xiàn)MySQL讀寫(xiě)分離,以及主庫(kù)出現(xiàn)故障的時(shí)候從庫(kù)自動(dòng)變?yōu)閷?xiě)庫(kù)坠七。主庫(kù)恢復(fù)后水醋,建議方案是讓之前的主庫(kù)變?yōu)閺膸?kù)。
關(guān)于讀寫(xiě)分離數(shù)據(jù)一致性問(wèn)題彪置,MyCat提供了一個(gè)slaveThreshold延遲配置拄踪,延遲時(shí)間大于配置時(shí)間后,從庫(kù)會(huì)被忽略掉拳魁,直接查詢主庫(kù)數(shù)據(jù)惶桐,防止讀到舊數(shù)據(jù)。
數(shù)據(jù)一致性問(wèn)題潘懊,還有種方案耀盗,就是半同步復(fù)制,即主庫(kù)在提交事務(wù)前會(huì)等待從庫(kù)是否以及成功復(fù)制日志卦尊,若成功則提交叛拷。這樣的話寫(xiě)效率會(huì)低
- 讀寫(xiě)分離
- 分表分庫(kù)
- 水平拆分(MyCat):訂單數(shù)據(jù)(訂單數(shù)據(jù)1、訂單數(shù)據(jù)2岂却、訂單數(shù)據(jù)3)
- 垂直拆分 (微服務(wù)):系統(tǒng)(訂單數(shù)據(jù)庫(kù)忿薇、用戶數(shù)據(jù)庫(kù))
防止MyCat單點(diǎn)故障裙椭,MyCat集群部署;
haproxy:入口分流,搭建多個(gè)MyCat集群署浩;
haproxy 也需要集群部署揉燃,防止單點(diǎn)故障
集群:防止單點(diǎn)故障
去中心化:
- 多個(gè)節(jié)點(diǎn)之間彼此發(fā)送心跳 (感知對(duì)方是否存活)
- 維護(hù)一個(gè)虛擬ip
keepalived:發(fā)送心跳,虛擬IP和haproxy的IP綁定,外界訪問(wèn)虛擬IP時(shí)筋栋,實(shí)際指向?qū)嶋H綁定IP炊汤,若綁定的失效,自動(dòng)綁定另外一個(gè)IP
完整實(shí)現(xiàn)弊攘,需要6臺(tái)服務(wù)器
MyCat配置
分庫(kù)分表主鍵自增id問(wèn)題
文章:https://blog.csdn.net/bjweimengshu/article/details/80162731?ivk_sa=1024320u
方案:生成全局唯一ID
UUID 32位 不推薦 無(wú)序
數(shù)據(jù)庫(kù)自增ID抢腐,每一次生成ID的時(shí)候,訪問(wèn)數(shù)據(jù)庫(kù)襟交,執(zhí)行語(yǔ)句插入一條記錄迈倍,生成一個(gè)ID,這樣一來(lái)捣域,每次都可以生成一個(gè)遞增的ID啼染。在分布式系統(tǒng)中可以利用DBproxy請(qǐng)求不同的分庫(kù),每個(gè)分庫(kù)設(shè)置不同的初始值焕梅,步長(zhǎng)和分庫(kù)數(shù)量相等迹鹅。這樣一來(lái)DB1生成的ID是1、4贞言、7斜棚、10,DB2生成的ID是2蜗字、5打肝、8脂新、11 DB3生成 3挪捕、6、9争便、12...
缺點(diǎn):ID的生成對(duì)數(shù)據(jù)庫(kù)嚴(yán)重依賴级零,不但影響性能,而且一旦數(shù)據(jù)庫(kù)掛點(diǎn)滞乙,服務(wù)將變的不可用snowflake 雪花算法(推薦)
id=0+41bit(時(shí)間戳)+10bit(工作機(jī)器id)+12bit(序列號(hào))
同一毫秒的ID數(shù) = 1024*4096 = 4194304
能夠支持絕大場(chǎng)景下的高并發(fā)
優(yōu)點(diǎn):
- 生成ID時(shí)不依賴于DB奏纪,完全在內(nèi)存中生成,高性能高可用
- ID呈趨勢(shì)遞增斩启,后續(xù)插入索引樹(shù)的時(shí)候性能較好
缺點(diǎn): - 依賴于系統(tǒng)時(shí)鐘的一致性序调。如果某臺(tái)機(jī)器的系統(tǒng)時(shí)鐘回?fù)埽锌赡茉斐蒊D沖突兔簇,或者ID亂序发绢。
snowflake 算法是 twitter 開(kāi)源的分布式 id 生成算法硬耍,采用 Scala 語(yǔ)言實(shí)現(xiàn),是把一個(gè) 64 位的 long 型的 id边酒,1 個(gè) bit 是不用的 + 用其中的 41 bit 作為毫秒數(shù) + 用 10 bit 作為工作機(jī)器 id + 12 bit 作為序列號(hào)经柴。
1 bit:不用,為啥呢墩朦?因?yàn)槎M(jìn)制里第一個(gè) bit 為如果是 1坯认,那么都是負(fù)數(shù),但是我們生成的 id 都是正數(shù)氓涣,所以第一個(gè) bit 統(tǒng)一都是 0牛哺。
41 bit:表示的是時(shí)間戳,單位是毫秒春哨。41 bit 可以表示的數(shù)字多達(dá) 2^41 - 1荆隘,也就是可以標(biāo)識(shí) 2^41 - 1 個(gè)毫秒值,換算成年就是表示69年的時(shí)間赴背。
10 bit:記錄工作機(jī)器 id椰拒,代表的是這個(gè)服務(wù)最多可以部署在 2^10臺(tái)機(jī)器上哪,也就是1024臺(tái)機(jī)器凰荚。但是 10 bit 里 5 個(gè) bit 代表機(jī)房 id燃观,5 個(gè) bit 代表機(jī)器 id。意思就是最多代表 2^5個(gè)機(jī)房(32個(gè)機(jī)房)便瑟,每個(gè)機(jī)房里可以代表 2^5 個(gè)機(jī)器(32臺(tái)機(jī)器)缆毁。
12 bit:這個(gè)是用來(lái)記錄同一個(gè)毫秒內(nèi)產(chǎn)生的不同 id,12 bit 可以代表的最大正整數(shù)是 2^12 - 1 = 4096到涂,也就是說(shuō)可以用這個(gè) 12 bit 代表的數(shù)字來(lái)區(qū)分同一個(gè)毫秒內(nèi)的 4096 個(gè)不同的 id脊框。
常見(jiàn)報(bào)錯(cuò):
Invalid DataSource:0 解決方案:防火墻、IP践啄、端口浇雹、權(quán)限問(wèn)題:臨時(shí)開(kāi)放全部權(quán)限
MongoDB
NoSQL(not only sql)
- 文檔型數(shù)據(jù)庫(kù)(bson格式和json一樣)
- 機(jī)于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),C++編寫(xiě)屿讽,主要用來(lái)處理大量的文檔昭灵。
- 介于關(guān)系型數(shù)據(jù)庫(kù)和非關(guān)系型數(shù)據(jù)庫(kù)的中間產(chǎn)品,是非關(guān)系型數(shù)據(jù)庫(kù)中功能最豐富的伐谈,最像關(guān)系型數(shù)據(jù)庫(kù)烂完。
應(yīng)用場(chǎng)景:Web應(yīng)用(key-value類(lèi)似,Value是結(jié)構(gòu)化的诵棵,不同的是數(shù)據(jù)庫(kù)可以了解Value的內(nèi)容)
優(yōu)點(diǎn):數(shù)據(jù)結(jié)構(gòu)要求不嚴(yán)格抠蚣,表結(jié)構(gòu)可變,不需要像關(guān)系型數(shù)據(jù)庫(kù)一樣需要預(yù)先定義表結(jié)構(gòu)
缺點(diǎn):查詢性能不高履澳,缺乏統(tǒng)一的查詢語(yǔ)句
Cookie和Session
Docker
- 概念:容器嘶窄、鏡像缓屠、倉(cāng)庫(kù);容器是鏡像的實(shí)例話對(duì)象
- Dockerfile 自定義鏡像文件
FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
#以上執(zhí)行會(huì)創(chuàng)建 3 層鏡像护侮。
#build成鏡像
$ docker build -t centos:v3 .
#在 Dockerfile 文件的存放目錄下敌完,執(zhí)行構(gòu)建動(dòng)作。
#以下示例羊初,通過(guò)目錄下的 Dockerfile 構(gòu)建一個(gè) centos:v3(鏡像名稱(chēng):#鏡像標(biāo)簽)滨溉。注:最后的 . 代表本次執(zhí)行的上下文路徑,下一節(jié)會(huì)介紹长赞。
#上下文路徑晦攒,是指 docker 在構(gòu)建鏡像,有時(shí)候想要使用到本機(jī)的文件(比如復(fù)制)得哆,docker build 命令得知這個(gè)路徑后脯颜,會(huì)將路徑下的所有內(nèi)容打包。
#如 COPY hom* /mydir/
- 自定義網(wǎng)絡(luò)贩据,使用自定義網(wǎng)絡(luò)栋操,可以讓容器間可以互ping聯(lián)通
- 端口映射
- docker-compose
Compose 是用于定義和運(yùn)行多容器 Docker 應(yīng)用程序的工具。通過(guò) Compose饱亮,您可以使用 YML 文件來(lái)配置應(yīng)用程序需要的所有服務(wù)矾芙。然后,使用一個(gè)命令近上,就可以從 YML 文件配置中創(chuàng)建并啟動(dòng)所有服務(wù)剔宪。
Compose 使用的三個(gè)步驟:
1. 使用 Dockerfile 定義應(yīng)用程序的環(huán)境。
2. 使用 docker-compose.yml 定義構(gòu)成應(yīng)用程序的服務(wù)壹无,這樣它們可以在隔離環(huán)境中一起運(yùn)行葱绒。
3. 最后,執(zhí)行 docker-compose up 命令來(lái)啟動(dòng)并運(yùn)行整個(gè)應(yīng)用程序斗锭。
# yaml 配置實(shí)例
version: "2.1"
services:
nginx:
image: nginx
ports:
- "8086:80"
volumes:
- /Users/kuang/lnmp/nginx/www:/usr/share/nginx/html
- /Users/kuang/lnmp/nginx/conf:/etc/nginx/conf.d
- /Users/kuang/lnmp/nginx/logs:/var/log/nginx
networks:
- lnmp-network
php:
image: php:5.6-fpm-alpine3.8
volumes:
- /Users/kuang/lnmp/nginx/www:/www
networks:
- lnmp-network
mysql:
image: mysql
ports:
- "3309:3306"
environment:
- MYSQL_ROOT_PASSWORD=123456
networks:
- lnmp-network
networks:
lnmp-network:
- 容器數(shù)據(jù)卷地淀,容器期間共享數(shù)據(jù),容器和宿主機(jī)共享數(shù)據(jù)拒迅。如:共享nginx的配置文件骚秦,共享PHP的項(xiàng)目目錄到宿主機(jī)她倘,在宿主機(jī)上修改代碼就會(huì)同步
-
容器的鏡像是一層一層疊加上去的璧微,使用的是聯(lián)合文件系統(tǒng)技術(shù),boosfs(內(nèi)核)->rootfs(基礎(chǔ)鏡像centos/ubuntu)->鏡像->鏡像->容器
上傳本地鏡像
dockerhub賬戶
xiaoxaio 密碼:a656842722
流程圖
自定義網(wǎng)路
kuangdeMacBook-Pro:~ kuang$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
kuangdeMacBook-Pro:~ kuang$ docker network inspect mynet
# 使用自定義網(wǎng)路
kuangdeMacBook-Pro:/ kuang$ docker run -d -P --name nginx-net-01 --net mynet nginx
4595c1a1007c192d3879062e1d342a58b823708c2ffae0aec0c138b2e75e1a1b
kuangdeMacBook-Pro:/ kuang$ docker run -d -P --name nginx-net-02 --net mynet nginx
4e541782f0b9782894521cf43a9f426e5fc7b8a6063b9c4692592dc998ee157e
#mynet中自動(dòng)創(chuàng)建網(wǎng)絡(luò)關(guān)聯(lián)
uangdeMacBook-Pro:~ kuang$ docker network inspect mynet
[
{
"Name": "mynet",
"Id": "668c48e5875c3c74f7d44697d7ccc8f4d1301530f8351dfaeb344d16a83a7edb",
"Created": "2021-06-22T12:34:07.8664049Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.168.0.0/16",
"Gateway": "192.168.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"4595c1a1007c192d3879062e1d342a58b823708c2ffae0aec0c138b2e75e1a1b": {
"Name": "nginx-net-01",
"EndpointID": "373eba4c55a9f0df3ef2e06766a75875aa7446a05d6e681bfbc6175abe35f0c1",
"MacAddress": "02:42:c0:a8:00:02",
"IPv4Address": "192.168.0.2/16",
"IPv6Address": ""
},
"4e541782f0b9782894521cf43a9f426e5fc7b8a6063b9c4692592dc998ee157e": {
"Name": "nginx-net-02",
"EndpointID": "b609b3bdfa75f4fb9cd2eb06bf0978f65ab2af805de3d506ac657dec631b7d53",
"MacAddress": "02:42:c0:a8:00:03",
"IPv4Address": "192.168.0.3/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
Nginx
nginx啟動(dòng)的時(shí)候會(huì)創(chuàng)建一個(gè)master主現(xiàn)程和多個(gè)worker線程硬梁,主線程負(fù)責(zé)調(diào)度子線程前硫,當(dāng)有客戶端訪問(wèn)時(shí),子線程是爭(zhēng)搶機(jī)制去獲取資源荧止。nginx支持熱更新屹电,當(dāng)熱更新時(shí)當(dāng)前在用的子線程是不會(huì)停止更新的阶剑,當(dāng)資源釋放后會(huì)重新去更新。
- 反向代理
作為服務(wù)器的代理危号,隱藏真實(shí)服務(wù)器IP地址牧愁,對(duì)外暴露的是代理服務(wù)器地址⊥饬客戶端只能訪問(wèn)代理服務(wù)器的地址猪半,從代理服務(wù)器獲取信息,至于代理服務(wù)器從哪一臺(tái)真實(shí)服務(wù)器獲取信息偷线,客戶端不知情磨确。反向代理可以配置負(fù)載均衡
正向代理,客服端代理声邦,客戶端需要配置代理服務(wù)器地址乏奥,客戶端訪問(wèn)真實(shí)的服務(wù)器地址『ゲ埽客戶端訪問(wèn)代理服務(wù)器邓了,代理服務(wù)器轉(zhuǎn)發(fā)請(qǐng)求溪掀,將數(shù)據(jù)返回給代理服務(wù)器忌傻,然后代理服務(wù)器將數(shù)據(jù)返回給客戶端。如翻墻竹揍,客戶端無(wú)法直接訪問(wèn)Google材失,通過(guò)代理可以訪問(wèn)痕鳍。正向代理也叫轉(zhuǎn)發(fā)代理,理論上可以訪問(wèn)任何域名龙巨。反向代理只能訪問(wèn)代理服務(wù)器域名笼呆。 - 負(fù)載均衡
- 輪循
upstream myserver {
server 127.0.0.1:8086;
server 127.0.0.1:8087;
}
server {
listen 80;
server_name 127.0.0.1 localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /Applications/MxSrvs/www/esound_vip;
index index.html index.php;
proxy_pass http://myserver;
proxy_connect_timeout 10;
}
- 權(quán)重
upstream myserver {
server 127.0.0.1:8086 weight=1;
server 127.0.0.1:8087 weight=10;
}
server {
listen 80;
server_name 127.0.0.1 localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /Applications/MxSrvs/www/esound_vip;
index index.html index.php;
proxy_pass http://myserver;
proxy_connect_timeout 10;
}
- ip_hash
upstream myserver {
ip_hash;
server 127.0.0.1:8086 weight=1 down;
server 127.0.0.1:8087 weight=1;
}
server {
listen 80;
server_name 127.0.0.1 localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /Applications/MxSrvs/www/esound_vip;
index index.html index.php;
proxy_pass http://myserver;
proxy_connect_timeout 10;
}
客戶端請(qǐng)求過(guò)來(lái)的ip,映射成hash值,然后分配到一個(gè)特定的服務(wù)器里面旨别。用戶下次請(qǐng)求時(shí)都會(huì)固定訪問(wèn)該服務(wù)器诗赌,它的session不會(huì)跨域到其他的服務(wù)中。
地址分配:hash(ip)%服務(wù)器數(shù)量 = 模值 每個(gè)模值對(duì)應(yīng)一臺(tái)服務(wù)器
如:如3臺(tái)服務(wù)器 t1秸弛、t2铭若、t3 對(duì)應(yīng) 0 1 2 5%3=2 這個(gè)hash值的客戶端會(huì)分配到t3服務(wù)器。
如何在nginx里面使用ip_hash?
直接添加ip_hash關(guān)鍵字即可递览,后續(xù)同一ip的訪問(wèn)將只會(huì)請(qǐng)求同一個(gè)服務(wù)器叼屠。
注意事項(xiàng)
1. 一旦使用了ip_hash,當(dāng)我們需要移除一臺(tái)服務(wù)器的時(shí)候绞铃,不能直接刪除這個(gè)配置項(xiàng)镜雨,而是需要在這臺(tái)服務(wù)器配置后面加上關(guān)鍵字down,表示不可用儿捧;
2. 因?yàn)槿绻苯右瞥渲庙?xiàng)荚坞,會(huì)導(dǎo)致hash算法發(fā)生更改挑宠,后續(xù)所有的請(qǐng)求都會(huì)發(fā)生混亂;
- 高并發(fā)颓影,高可用集群(keepalive)備份綁定虛擬IP機(jī)制
兩臺(tái)nginx服務(wù)器各淀,一個(gè)主服務(wù)器,一個(gè)備份服務(wù)器诡挂,當(dāng)主服務(wù)器宕機(jī)的時(shí)候揪阿,自動(dòng)切換到備份服務(wù)器。
keepalived插件咆畏。主服務(wù)器IP綁定虛擬服務(wù)器IP南捂,當(dāng)主服務(wù)器宕機(jī)后,備份服務(wù)器IP綁定虛擬IP旧找。
1. 兩臺(tái)nginx服務(wù)
2. 需要keepalived
3. 需要一個(gè)虛擬ip
keepalived安裝配置
-
腳本文件溺健,檢查nginx是否宕機(jī)
[圖片上傳中...(image.png-a7b2cc-1624457694839-0)]
-
虛擬ip配置
- 動(dòng)靜分離
nginx可以在該服務(wù)器下創(chuàng)建文件目錄,存放圖片,CSS,JS等靜態(tài)資源钮蛛,配置好后可以直接訪問(wèn)鞭缭,提高效率
upstream myserver {
ip_hash;
server 127.0.0.1:8086 weight=1 down;
server 127.0.0.1:8087 weight=1;
}
server {
listen 80;
server_name 127.0.0.1 localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /Applications/MxSrvs/www/esound_vip;
index index.html index.php;
proxy_pass http://myserver;
proxy_connect_timeout 10;
}
location /images/ {
root /Applications/MxSrvs/www/esound_vip/tp6/public/static/;
autoindex on;
}
#請(qǐng)求地址
http://localhost/images/home_cooperation_banner.png
PHP-FPM
PHP內(nèi)置PHP-FPM功能,需要手動(dòng)設(shè)置開(kāi)啟
PHP-FPM 負(fù)責(zé)管理一個(gè)進(jìn)程池來(lái)處理來(lái)自 Web 服務(wù)器的 HTTP 動(dòng)態(tài)請(qǐng)求魏颓,在 PHP-FPM 中岭辣,master 進(jìn)程負(fù)責(zé)與 Web 服務(wù)器進(jìn)行通信,接收 HTTP 請(qǐng)求甸饱,再將請(qǐng)求轉(zhuǎn)發(fā)給 worker 進(jìn)程進(jìn)行處理沦童,worker 進(jìn)程主要負(fù)責(zé)動(dòng)態(tài)執(zhí)行 PHP 代碼,處理完成后叹话,將處理結(jié)果返回給 Web 服務(wù)器偷遗,再由 Web 服務(wù)器將結(jié)果發(fā)送給客戶端。這就是 PHP-FPM 的基本工作原理驼壶。
最大請(qǐng)求數(shù):最大處理請(qǐng)求數(shù)是指一個(gè)php-fpm的worker進(jìn)程在處理多少個(gè)請(qǐng)求后就終止掉氏豌,master進(jìn)程會(huì)重新respawn一個(gè)新的。
這個(gè)配置的主要目的是避免php解釋器或程序引用的第三方庫(kù)造成的內(nèi)存泄露热凹。
pm.max_requests = 10240