【慢查詢】
1 # 1 我們配置一個時間,如果查詢時間超過了我們設定的時間,我們就認為這是一個慢查詢 2 # 2 慢查詢是一個先進先出的佇列,固定長度,儲存在記憶體中--->透過設定慢查詢,以後超過我們設定時間的命令,就會放在這個佇列中 3 # 3 後期我們透過查詢這個佇列,過濾出 慢命令--》最佳化慢命令 4 5 6 # 4 實操: 7 1 配置慢查詢 8 # 設定記錄所有命令 9 config set slowlog-log-slower-than 0 10 # 最多記錄100條 11 config set slowlog-max-len 100 12 # 持久化到本地配置檔案 13 config rewrite 14 15 2 檢視慢查詢佇列 16 slowlog get [n] #獲取慢查詢佇列 17 ''' 18 日誌由4個屬性組成: 19 1)日誌的標識id 20 2)發生的時間戳 21 3)命令耗時 22 4)執行的命令和引數 23 ''' 24 slowlog len #獲取慢查詢佇列長度 25 slowlog reset #清空慢查詢佇列 26 27 28 # mysql : slow_query_log
。
。
【pipline命令管道】
1 #1 Redis的pipeline(管道)功能在命令列中沒有,但redis是支援pipeline的,而且在各個語言版的client中都有相應的實現 2 3 # 2 pipeline期間將“獨佔”連結,多個命令,放到一個pipline(管道中),要麼都執行,要麼都不執行 4 5 # 3 python中使用pipline 6 import redis 7 8 pool = redis.ConnectionPool(host='192.168.241.129', port=6379, password='jh123') 9 conn = redis.Redis(connection_pool=pool) 10 # pipe = r.pipeline(transaction=False) 11 # 建立pipeline 12 pipe =conn.pipeline(transaction=True) 13 # 開啟事務 14 pipe.multi() 15 16 pipe.set('name', 'jh') 17 # 其他程式碼,可能出異常 18 pipe.set('role', 'nb') 19 20 pipe.execute() 21 22 23 # 4 事務四大特性 24 -原子性 25 -永續性 26 -一致性 27 -隔離性 28 # 6 redis有沒有事務,能不能有這四大特性? 29 -因為redis,能實現事務的四大特性---》咱們說它支援 30 -透過pipline實現原子性--》透過pipline可以實現事務 31 -pipline只支援單例項,叢集環境,不支援---》叢集環境不支援事務 32 33 34 # 7 原生操作,實現樂觀鎖 35 36 # 7.1 mutil 開啟事務,放到管道中一次性執行 37 multi # 開啟事務 38 set name xxxx 39 set age 18 40 exec ,然後再去查,就發現資料改了 41 42 43 # 7.2 模擬事務回顧 ,樂觀鎖 44 # 在開啟事務之前,先watch 45 watch age 46 multi 47 decr age 48 exec 49 50 # 另一臺機器 51 multi 52 decr age 53 exec # 先執行,上面的執行就會失敗(樂觀鎖,被wathc的事務不會執行成功) 54 55 56 57 # 7.3 使用redis實現樂觀鎖 58 59 60 ## 利用redis的樂觀鎖,實現秒殺系統的資料同步(基於watch實現), 61 ## 使用者1 62 import redis 63 conn = redis.Redis(host='192.168.241.129',port=6379) 64 with conn.pipeline() as pipe: 65 # 先監視,自己的值沒有被修改過 66 conn.watch('count') 67 # 事務開始 68 pipe.multi() 69 old_count = conn.get('count') 70 count = int(old_count) 71 input('我考慮一下') 72 if count > 0: # 有庫存 73 pipe.set('count', count - 1) 74 75 # 執行,把所有命令一次性推送過去 76 ret = pipe.execute() 77 print(type(ret)) 78 print(ret) 79 ## 使用者2 80 import redis 81 conn = redis.Redis(host='127.0.0.1',port=6379) 82 with conn.pipeline() as pipe: 83 # 先監視,自己的值沒有被修改過 84 conn.watch('count') 85 # 事務開始 86 pipe.multi() 87 old_count = conn.get('count') 88 count = int(old_count) 89 if count > 0: # 有庫存 90 pipe.set('count', count - 1) 91 # 執行,把所有命令一次性推送過去 92 ret=pipe.execute() 93 print(type(ret)) 94 95 # 注:windows下如果資料被修改了,不會拋異常,只是返回結果的列表為空,mac和linux會直接拋異常 96 97 # 秒殺系統核心邏輯測試,建立100個執行緒併發秒殺(程式碼有問題) 98 import redis 99 from threading import Thread 100 def choose(name, conn): 101 with conn.pipeline() as pipe: 102 # 先監視,自己的值沒有被修改過 103 conn.watch('count') 104 # 事務開始 105 pipe.multi() 106 old_count = conn.get('count') 107 count = int(old_count) 108 # input('我考慮一下') 109 # time.sleep(random.randint(1, 2)) 110 if count > 0: # 有庫存 111 pipe.set('count', count - 1) 112 113 # 執行,把所有命令一次性推送過去 114 ret = pipe.execute() 115 print(ret) 116 if len(ret) > 0: 117 print('第%s個人搶購成功' % name) 118 else: 119 print('第%s個人搶購失敗' % name) 120 121 122 if __name__ == '__main__': 123 conn = redis.Redis(host='192.168.241.129', port=6379) 124 for i in range(100): 125 126 t = Thread(target=choose, args=(i, conn)) 127 t.start()
。
。
【釋出訂 1 # 釋出訂閱(觀察者模式):釋出者釋出了訊息,所有的訂閱者都可以收到,就是生產者消費者模型
2 -生產者消費者 釋出訂閱模型 3 -生產者消費者 佇列 4 5 # 原生實現 6 -釋出訊息: 7 publish channel message 8 -訂閱(現有訂閱者,然後釋出者才有訊息) 9 subscribe channel 10 -接收訊息 11 -只要釋出者一發布,訂閱者都會受到 12 13 14 # python+redis實現 15 import redis 16 # 連線到Redis伺服器 17 r = redis.Redis(host='localhost', port=6379, db=0) 18 # 釋出者 19 20 r.publish('channel', 'message') 21 22 23 24 import redis 25 # 連線到Redis伺服器 26 r = redis.Redis(host='localhost', port=6379, db=0) 27 # 訂閱者 28 sub = r.pubsub() 29 sub.subscribe('channel') 30 for message in sub.listen(): 31 print(message)
if isinstance(message['data'],bytes):
print(message['data'].decode('utf-8'))
if message['data'].decode('utf-8')['type']=='下單':
print(message['data'].decode('utf-8')['user'],'傳送簡訊')
。
。
【bitmap點陣圖】
1 #1 本質是字串 2 3 #2 操作位元位 4 b i g 5 01100011 01101001 01100111 6 set hello big #放入key位hello 值為big的字串 7 getbit hello 0 #取點陣圖的第0個位置,返回0 8 getbit hello 1 #取點陣圖的第1個位置,返回1 如上圖 9 10 # 我們可以直接操縱位 11 setbit key offset value #給點陣圖指定索引設定值 12 setbit hello 7 1 #把hello的第7個位置設為1 這樣,big就變成了cig 13 14 15 # 3 獨立使用者統計---》統計日活---》使用者量足夠大--》節約記憶體 16 -10億使用者 使用者id1 2 3 10億 17 18 1個bytes--》8個位元位---》能表示多少種變化? 19 2的7次方-1 :-128 到127之間 20 8個bytes--》64個位元位--》9223372036854775808 21 22 如果以集合儲存:存一個使用者,就要8個bytes---》存1億使用者 8 bytes*1億 23 24 -統計日活,只要使用者登入,就把使用者id放到集合中 25 -晚上只需要統計一下 集合大小---》就能統計出日活 26 -使用集合儲存---》1--》32位--》1億使用者 5千萬左右---》需要 200MB空間 27 int8個位元位表示範圍 -128--127之間 28 int16 29 int32 個位元位表示範圍 -2的31次方---2的31次方 2147483648 30 31 -使用點陣圖---》12.5MB空間 32 33 34 # 獲取前3位中1的個數 35 bitcount name 0 3
。
。
1 # 1 基於HyperLogLog演算法:極小的空間完成獨立數量統計,本質還是字串 2 3 # 2 4 -放值:pfadd uuids "uuid1" "uuid2" "uuid3" "uuid4" 5 -統計個數:pfcount uuids 6 -判斷一個值是否在裡面:pfadd uuids "uuid1"(返回1/0) 7 8 # 3 統計日活使用者 9 10 # 4 去重:爬過的網址,就不爬了--》存一下爬過的 11 'www.baidu.com'--->放到 pfadd 中--》返回1,說明沒爬過--》繼續爬取--》如果返回0,不爬了 12 13 # 5 黑白名單 14 15 # 6 注意 16 百萬級別獨立使用者統計,百萬條資料只佔15k 17 錯誤率 0.81% 18 無法取出單條資料,只能統計個數 19 20 # 7 類似於布隆過濾器,演算法不一樣
。
。
1 # 1 geo 地理位置資訊 2 GEO(地理資訊定位):儲存經緯度,計算兩地距離,範圍等 3 北京:116.28,39.55 4 天津:117.12,39.08 5 可以計算天津到北京的距離,天津周圍50km的城市,外賣等 6 7 # 2 經緯度哪裡來? 8 - web端:js獲取--》掉介面,傳給後端 9 - 安卓,ios端:執行緒的程式碼 10 -微信小程式 11 12 # 3 js獲取經緯度 13 if (navigator.geolocation) { 14 navigator.geolocation.getCurrentPosition(function(position) { 15 var latitude = position.coords.latitude; 16 var longitude = position.coords.longitude; 17 console.log("經度:" + longitude); 18 console.log("緯度:" + latitude); 19 }); 20 } else { 21 console.log("瀏覽器不支援Geolocation API"); 22 } 23 24 25 # 4 增加地理位置資訊 26 geoadd key longitude latitude member #增加地理位置資訊 27 28 geoadd cities:locations 116.28 39.55 beijing #把北京地理資訊天津到cities:locations中 29 geoadd cities:locations 117.12 39.08 tianjin 30 geoadd cities:locations 114.29 38.02 shijiazhuang 31 geoadd cities:locations 118.01 39.38 tangshan 32 geoadd cities:locations 115.29 38.51 baoding 33 34 35 # 5 獲取天津的經緯度 geopos key member #獲取地理位置資訊 36 geopos cities:locations tianjin 37 # 根據經緯度--》文字 38 from geopy.geocoders import Nominatim 39 geolocator = Nominatim(user_agent="my_application") 40 def geolocate_point(latitude, longitude): 41 location = geolocator.reverse(f"{latitude}, {longitude}") 42 return location.address 43 # 示例使用經緯度 44 latitude = 39.983424 45 longitude = 116.307224 46 address = geolocate_point(latitude, longitude) 47 print(address) 48 49 # 6 統計兩個地理位置之間的距離 50 geodist cities:locations beijing tianjin km #北京到天津的距離,89公里 51 52 # 7 統計某個地理位置方圓xx公里,有xx 53 georadiusbymember cities:locations beijing 150 km
。
。
【持久化】
1 # 1 什麼是持久化 2 redis的所有資料儲存在記憶體中,對資料的更新將非同步的儲存到硬碟上 3 4 # 2 持久化的實現方式 5 快照:某時某刻資料的一個完成備份, 6 -mysql的Dump:寫一個mysql自動定時備份和清理前後端程式 7 -redis的RDB:某一刻,把記憶體中得資料,儲存到硬碟上這個操作就是rbd的持久化 8 寫日誌:任何操作記錄日誌,要恢復資料,只要把日誌重新走一遍即可 9 -mysql的 Binlog 10 -Redis的 AOF 11 12 # 3 redis有三種持久化方案 13 -rdb:快照 14 -aof:日誌 15 -混合持久化:rdb+aof混合方案
。
rdb
1 # 4 rdb方案 :三種方式 2 1 人工同步:客戶端 : save # 同步操作,會阻塞其他命令--》單執行緒架構 3 2 人工非同步:客戶端:bgsave # 非同步操作,不會阻塞其他命令 4 3 配置檔案 5 save 900 1 #配置一條 6 save 300 10 #配置一條 7 save 60 10000 #配置一條 8 9 save 60 5 10 11 # 5 最佳配置 12 #最佳配置 13 save 900 1 14 save 300 10 15 save 60 10000 16 dbfilename dump-6379.rdb #以埠號作為檔名,可能一臺機器上很多reids,不會亂 17 dir ./bigdiskpath #儲存路徑放到一個大硬碟位置目錄 18 stop-writes-on-bgsave-error yes #出現錯誤停止 19 rdbcompression yes #壓縮 20 rdbchecksum yes #校驗 21 22 23 # 6 確定 RDB問題 24 耗時,耗效能: 25 不可控,可能會丟失資料
。
aof
1 # 1 客戶端每寫入一條命令,都記錄一條日誌,放到日誌檔案中,如果出現當機,可以將資料完全恢復 2 # 2 AOF的三種策略日誌不是直接寫到硬碟上,而是先放在緩衝區,緩衝區根據一些策略,寫到硬碟上always:redis–》寫命令重新整理的緩衝區—》每條命令fsync到硬碟—》AOF檔案everysec(預設值):redis——》
寫命令重新整理的緩衝區—》每秒把緩衝區fsync到硬碟–》AOF檔案no:redis——》寫命令重新整理的緩衝區—》作業系統決定,緩衝區fsync到硬碟–》AOF檔案 3 # 3 配置檔案appendonly yes #將該選項設定為yes,開啟appendfilename "appendonly-${port}.aof" 4 #檔案儲存的名字appendfsync everysec 5 #採用第二種策略dir /bigdiskpath 6 #存放的路徑no-appendfsync-on-rewrite yesappendonly yesappendfilename "appendonly.aof"appendfsync everysecno-appendfsync-on-rewrite yes 7 8 # 4 放在了檔案中appendonly.aof.1.base.rdb :永久的appendonly.aof.1.incr.aof :臨時的appendonly.aof.manifest: 哪些檔案存了資料