redis学习笔记,常用方法
Redis-day01-note
Redis介紹
- 特點及優點
- 與其他數據庫對比
- 應用場景
- 數據庫排名
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-lnfujJcG-1573565054411)(E:\工作相關\講課文件\Redis\redis_day01_note\db_rank.png)]
- redis版本
- 誕生歷程
- Redis附加功能
安裝
- Ubuntu
- Windows
配置文件詳解
- 配置文件所在路徑
- 設置連接密碼
- 允許遠程連接
-
遠程連接測試
Windows連接Ubuntu的Redis服務
數據類型
字符串類型(string)
特點
1、字符串、數字,都會轉為字符串來存儲 2、以二進制的方式存儲在內存中必須掌握命令
1、set key value 2、setnx key value 3、set key value ex seconds 4、get key 5、mset key1 value1 key2 value2 6、mget key1 key2 key3 7、stren key # 數字操作 8、incr key 9、decr key擴展命令
1、append key value 2、setrange key index value 3、getrange key start stop 4、incrby key step 5、decrby key step常用命令
-
set | get命令
作用: 設置鍵值,獲取鍵對應的值
命令格式: set key value
? get key
-
set命令之 - setnx
setnx key value : 鍵不存在時才能進行設置**(必須掌握)**
-
set命令之 - ex
作用: 設置過期時間
命令格式: set key value ex seconds
-
mset | mget
作用: 同時設置多個值,獲取多個值
? 鍵的命名規范
? mset wang::email wangweichao@tedu.cn
127.0.0.1:6379> mset wang::email wangweichao@tedu.cn guo::email guods@tedu.cn OK 127.0.0.1:6379> mget wang::email guo::email 1) "wangweichao@tedu.cn" 2) "guods@tedu.cn" 127.0.0.1:6379>-
strlen
作用: 獲取值的長度
命令格式: strlen key
-
字符串索引操作
setrange key 索引值 value
作用: 從索引值開始,value替換原內容
? getrange key 起始值 終止值
? 作用: 獲取指定范圍切片內容
127.0.0.1:6379> get message "hello tarena" 127.0.0.1:6379> getrange message 0 4 "hello" 127.0.0.1:6379> getrange message 0 -1 "hello tarena" 127.0.0.1:6379>-
append key value
作用: 追加拼接value的值
整數操作
? INCRBY key 步長
? DECRBY key 步長
127.0.0.1:6379> set number 10 OK 127.0.0.1:6379> get number "10" 127.0.0.1:6379> INCRBY number 5 (integer) 15 127.0.0.1:6379> get number "15" 127.0.0.1:6379> DECRBY number 5 (integer) 5 127.0.0.1:6379> get number "5"? INCR key : +1操作
? DECR key : -1操作
127.0.0.1:6379> incr number (integer) 7 127.0.0.1:6379> decr number (integer) 6 127.0.0.1:6379> get number "6" 127.0.0.1:6379>? 應用場景
抖音上有人關注你了,是不是可以用INCR呢,如果取消關注了是不是可以用DECR浮點數操作
? incrbyfloat key step
127.0.0.1:6379> get number "10" 127.0.0.1:6379> INCRBYFLOAT number 6.66 "12.66" 127.0.0.1:6379> INCRBYFLOAT number -6.66 "6" 127.0.0.1:6379> # 先轉為數字類型,然后再進行相加減,不能使用appendstring命令匯總
# 字符串操作 1、set key value 2、setnx key value 3、get key 3、mset 4、mget 5、set key value ex seconds 6、strlen key # 數字操作 7、incrby key 步長 8、decrby key 步長 9、incr key 10、decr key 11、incrbyfloat key number # 設置過期時間的兩種方式 # 方式一 1、set key value ex 3 # 方式二 1、set key value 2、expire key 5 # 秒 3、pexpire key 5 # 毫秒 # 查看存活時間 ttl key # 刪除過期 persist key- 通用命令
string數據類型注意
# key值取值原則 1、key值不宜過長,消耗內存,且在數據中查找這類鍵值的計算成本高 2、不宜過短,可讀性較差 # 值 1、一個字符串類型的值最多能存儲512M內容練習
1、查看 db0 庫中所有的鍵select 0keys * 2、設置鍵 trill:username 對應的值為 user001,并查看set trill:username 'user001' 3、獲取 trill:username 值的長度strlen trill:username 4、一次性設置 trill:password 、trill:gender、trill:fansnumber 并查看(值自定義)mset trill:password '123456' trill:gender 'm' trill:fansnumber 10mget trill:password trill:gender trill:fansnumber 5、查看鍵 trill:score 是否存在exists trill:score 6、增加10個粉絲incrby trill:fansnumber 10 7、增加2個粉絲(一個一個加)incr trill:fansnumber incr trill:fansnumber 8、有3個粉絲取消關注你了decrby trill:fansnumber 10 9、又有1個粉絲取消關注你了decrby trill:fansnumber 1 10、思考、思考、思考...,清除當前庫flushdb 11、一萬個思考之后,清除所有庫flushall列表數據類型(List)
- 特點
- 頭尾壓入元素(LPUSH | RPUSH)
? 1、LPUSH key value
? 2、RPUSH key value
127.0.0.1:6379> LPUSH mylist1 0 1 2 3 4 (integer) 5 127.0.0.1:6379> LRANGE mylist1 0 -1 1) "4" 2) "3" 3) "2" 4) "1" 5) "0" 127.0.0.1:6379> RPUSH mylist2 0 1 2 3 4 (integer) 5 127.0.0.1:6379> LRANGE mylist2 0 -1 1) "0" 2) "1" 3) "2" 4) "3" 5) "4" 127.0.0.1:6379>-
查看|設置 列表元素
查看(LRANGE)
LRANGE key start stop # 查看列表中所有元素 LRANGE key 0 -1獲取指定位置元素(LINDEX)
LINDEX key index設置指定位置元素的值(LSET)
LSET key index value獲取列表長度(LLEN)
LLEN key -
頭尾彈出元素(LPOP | RPOP)
LPOP key : 從列表頭部彈出一個元素
RPOP key : 從列表尾部彈出一個元素
RPOPLPUSH source destination : 從一個列表尾部彈出元素壓入到另一個列表頭部
-
移除指定元素(LREM)
LREM key count value
count>0:表示從頭部開始向表尾搜索,移除與value相等的元素,數量為count count<0:表示從尾部開始向表頭搜索,移除與value相等的元素,數量為count count=0:移除表中所有與value相等的值示例
127.0.0.1:6379> LRANGE mylist1 0 -1 1) "3" 2) "2" 127.0.0.1:6379> LPUSH mylist1 3 2 (integer) 4 127.0.0.1:6379> LRANGE mylist1 0 -1 1) "2" 2) "3" 3) "3" 4) "2" 127.0.0.1:6379> LREM mylist1 1 2 (integer) 1 127.0.0.1:6379> LRANGE mylist1 0 -1 1) "3" 2) "3" 3) "2" 127.0.0.1:6379> LREM mylist1 1 3 (integer) 1 127.0.0.1:6379> LRANGE mylist1 0 -1 1) "3" 2) "2" 127.0.0.1:6379> -
**去除指定范圍外元素(LTRIM) **
LTRIM key start stop
127.0.0.1:6379> LRANGE mylist2 0 -1 1) "1" 2) "0" 3) "1" 4) "2" 5) "3" 6) "4" 127.0.0.1:6379> LTRIM mylist2 0 -2 OK 127.0.0.1:6379> LRANGE mylist2 0 -1 1) "1" 2) "0" 3) "1" 4) "2" 5) "3" 127.0.0.1:6379>應用場景: 保存微博評論最后500條
LTRIM user001::comments 0 499 -
列表中插入值(LINSERT)
LINSERT key BEFORE|AFTER pivot value
key和pivot不存在,不進行任何操作
示例代碼
127.0.0.1:6379> LRANGE mylist2 0 -1 1) "0" 2) "1" 3) "2" 4) "3" 5) "4" 127.0.0.1:6379> LINSERT mylist2 after 2 666 (integer) 6 127.0.0.1:6379> LINSERT mylist2 before 4 888 (integer) 7 127.0.0.1:6379> LRANGE mylist2 0 -1 1) "0" 2) "1" 3) "2" 4) "666" 5) "3" 6) "888" 7) "4" 127.0.0.1:6379> -
阻塞彈出(BLPOP | BRPOP)
BLPOP key timeout
BRPOP key timeout
1、如果彈出的列表不存在或者為空,就會阻塞 2、超時時間設置為0,就是永久阻塞,直到有數據可以彈出 3、如果多個客戶端阻塞再同一個列表上,使用First In First Service原則,先到先服務示例
127.0.0.1:6379> BLPOP mylist2 0 1) "mylist2" 2) "3" 127.0.0.1:6379> BLPOP mylist2 0 1) "mylist2" 2) "2" 127.0.0.1:6379> BLPOP mylist2 0 1) "mylist2" 2) "1" 127.0.0.1:6379> BLPOP mylist2 0 # 阻塞了
列表常用命令總結
# 增 1、LPUSH key value1 value2 2、RPUSH key value1 value2 3、RPOPLPUSH source destination 4、LINSERT key after|before value newvalue # 查 5、LRANGE key start stop 6、LLEN key # 刪 7、LPOP key 8、RPOP key 9、BLPOP key timeout 10、BRPOP key timeout 11、LREM key count value 12、LTRIM key start stop # 改 13、LSET key index newvalue練習
1、查看所有的鍵keys * 2、向列表 spider::urls 中以RPUSH放入如下幾個元素:01_baidu.com、02_taobao.com、03_sina.com、04_jd.com、05_xxx.comRPUSH spider::urls 01_baidu.com 02_taobao.com 03_sina.com 04_jd.com 05_xxx.com 3、查看列表中所有元素LRANGE spider::urls 0 -1 4、查看列表長度LLEN spider::urls 5、將列表中01_baidu.com 改為 01_tmall.comLSET spider::urls 0 01_tmall.com 6、在列表中04_jd.com之后再加1個元素 02_taobao.comLINSERT spider::urls after 04_jd.com 02_taobao.com 7、彈出列表中的最后一個元素RPOP spider::urls 8、刪除列表中所有的 02_taobao.comLREM spider::urls 0 02_taobao.com 9、剔除列表中的其他元素,只剩前3條LTRIM spider::urls 0 2與python交互
- 模塊
Ubuntu
sudo pip3 install redisWindows
python -m pip install redis- 使用流程
- 通用命令代碼示例
字符串命令代碼示例
import redisr = redis.Redis(host='192.168.43.49',port=6379,db=0)r.set('mystring','python') # b'python' print(r.get('mystring')) # False print(r.setnx('mystring','socket')) # mset:參數為字典 r.mset({'mystring2':'mysql','mystring3':'mongodb'}) # mget:結果為一個列表 print(r.mget('mystring','mystring2','mystring3')) # mystring長度:6 print(r.strlen('mystring')) # 數字類型操作 r.set('number',10) r.incrby('number',5) r.decrby('number',5) r.incr('number') r.decr('number') r.incrbyfloat('number',6.66) r.incrbyfloat('number',-6.66) # b'10' print(r.get('number'))python操作list
import redisr = redis.Redis(host='192.168.43.49',port=6379,db=0) # ['mysql','redis'] r.lpush('pylist','redis','mysql') # ['mysql','redis','django','spider'] r.rpush('pylist','django','spider') # ['mysql','redis','django','spider','AI'] r.linsert('pylist','after','spider','AI') # 5 print(r.llen('pylist')) # ['redis','django','spider'] r.lpop('pylist') r.rpop('pylist') # ['redis','django','spider'] print(r.lrange('pylist',0,-1)) # ['redis','spider'] r.lrem('pylist',0,'django') # 返回True,['redis'] r.ltrim('pylist',0,0) # 返回True,['spiderman'] r.lset('pylist',0,'spiderman')r.delete('pylist')位圖操作bitmap(重要)
位圖不是真正的數據類型,它是定義在字符串類型中
一個字符串類型的值最多能存儲512M字節的內容,位上限:2^32
強勢點
可以實時的進行統計,極其節省空間。官方在模擬1億2千8百萬用戶的模擬環境下,在一臺MacBookPro上,典型的統計如“日用戶數”的時間消耗小于50ms, 占用16MB內存設置某一位上的值
setbit key offset value # offset是偏移量,從0開始示例
# 默認擴展位以0填充 127.0.0.1:6379> set mykey ab OK 127.0.0.1:6379> get mykey "ab" 127.0.0.1:6379> SETBIT mykey 0 1 (integer) 0 127.0.0.1:6379> get mykey "\xe1b" 127.0.0.1:6379>獲取某一位上的值
GETBIT key offset
127.0.0.1:6379> GETBIT mykey 3 (integer) 0 127.0.0.1:6379> GETBIT mykey 0 (integer) 1 127.0.0.1:6379>bitcount
統計鍵所對應的值中有多少個 1
127.0.0.1:6379> SETBIT user001 1 1 (integer) 0 127.0.0.1:6379> SETBIT user001 30 1 (integer) 0 127.0.0.1:6379> bitcount user001 (integer) 2 127.0.0.1:6379>應用場景案例
網站用戶的上線次數統計(尋找活躍用戶)
用戶名為key,上線的天作為offset,上線設置為1
示例: 用戶名為 user001 的用戶,今年第1天上線,第30天上線
SETBIT user001 1 1
SETBIT user001 30 1
BITCOUNT user001
代碼實現
import redisr = redis.Redis(host='192.168.43.49',port=6379,db=2,password='123456')# user1,一年之中第1天和第5天登錄 r.setbit('user001',1,1) r.setbit('user001',5,1) # user2,一年之中第100天和第200天登錄 r.setbit('user002',100,1) r.setbit('user002',200,1) # user3,一年之中好多天登錄 for i in range(0,365,2):r.setbit('user003',i,1) # user4,一年之中好多天登錄 for i in range(0,365,3):r.setbit('user004',i,1)user_list = r.keys('user*') print(user_list)# 活躍用戶 active_users = [] # 不活躍用戶 noactive_user = []for user in user_list:# 統計位圖中有多少個 1login_count = r.bitcount(user)if login_count >= 100:active_users.append((user,login_count))else:noactive_user.append((user,login_count))# 打印活躍用戶 for active in active_users:print('活躍用戶:',active)list案例: 一個進程負責生產url,一個進程負責消費url
進程1: 生產者
import redis import random import timeurls_list = ['01_baidu.com','02_sina.com','03_taobao.com','04_tmall.com','05_jd.com' ] r = redis.Redis(host='192.168.43.49',db=0,password='123456') while True:url = random.choice(urls_list)r.lpush('spider::urls',url)time.sleep(random.randint(1,5))進程2: 消費者
import redisr = redis.Redis(host='192.168.43.49',db=0,password='123456')while True:# 結果為元組try:url = r.blpop('spider::urls',3)print(url[1])r.lrem('spider::urls',count=0,value=url[1])except:print('爬取結束')breakredis_day01回顧
Redis的特點
1、基于key-value的非關系型數據庫 2、基于內存存儲,速度很快 3、基于內存存儲,經常當作緩存型數據庫使用,常用信息存儲在熱地是數據庫中五大數據類型
1、字符串類型(string) 2、列表類型(list) 3、哈希類型(hash) 4、集合類型(set) 5、有序集合類型(sorted set)字符串類型
# 設置key相關操作 1、set key value 2、setnx key value 3、mset k1 v1 k2 v2 k3 v3 4、set key value ex seconds 5、set key value 5、expire key 5 5、pexpire key 5 5、ttl key 5、persist key # 獲取key相關操作 6、get key 7、mget k1 k2 k3 8、strlen key # 數字相關操作 7、incrby key 步長 8、decrby key 步長 9、incr key 10、decr key 11、incrbyfloat key number列表類型
# 插入元素相關操作 1、LPUSH key value1 value2 2、RPUSH key value1 value2 3、RPOPLPUSH source destination 4、LINSERT key after|before value newvalue # 查詢相關操作 5、LRANGE key start stop 6、LLEN key # 刪除相關操作 7、LPOP key 8、RPOP key 9、BLPOP key timeout 10、BRPOP key timeout 11、LREM key count value 12、LTRIM key start stop # 修改指定元素相關操作 13、LSET key index newvalue思考:
Redis列表如何當做共享隊列來使用???
# 同學你好,你還記得小米應用商店爬取URL地址的案例嗎? 1、生產者消費者模型 2、生產者進程在列表中 LPUSH | RPUSH 數據,消費者進程在列表中 RPOP | LPOP 數據redis_day02筆記
Python操作字符串類型
import redisr = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)r.set('mystring','python') # b'python' print(r.get('mystring')) # False print(r.setnx('mystring','socket')) # mset:參數為字典 r.mset({'mystring2':'mysql','mystring3':'mongodb'}) # mget:結果為一個列表 print(r.mget('mystring','mystring2','mystring3')) # mystring長度:6 print(r.strlen('mystring')) # 數字類型操作 r.set('number',10) r.incrby('number',5) r.decrby('number',5) r.incr('number') r.decr('number') r.incrbyfloat('number',6.66) r.incrbyfloat('number',-6.66) # b'10' print(r.get('number'))位圖操作bitmap
定義
1、位圖不是真正的數據類型,它是定義在字符串類型中 2、一個字符串類型的值最多能存儲512M字節的內容,位上限:2^32 # 1MB = 1024KB # 1KB = 1024Byte(字節) # 1Byte = 8bit(位)強勢點
可以實時的進行統計,極其節省空間。官方在模擬1億2千8百萬用戶的模擬環境下,在一臺MacBookPro上,典型的統計如“日用戶數”的時間消耗小于50ms, 占用16MB內存設置某一位上的值(setbit)
# 設置某一位上的值(offset是偏移量,從0開始) setbit key offset value # 獲取某一位上的值 GETBIT key offset # 統計鍵所對應的值中有多少個 1 BITCOUNT key示例
# 默認擴展位以0填充 127.0.0.1:6379> set mykey ab OK 127.0.0.1:6379> get mykey "ab" 127.0.0.1:6379> SETBIT mykey 0 1 (integer) 0 127.0.0.1:6379> get mykey "\xe1b" 127.0.0.1:6379>獲取某一位上的值
GETBIT key offset
127.0.0.1:6379> GETBIT mykey 3 (integer) 0 127.0.0.1:6379> GETBIT mykey 0 (integer) 1 127.0.0.1:6379>bitcount
統計鍵所對應的值中有多少個 1
127.0.0.1:6379> SETBIT user001 1 1 (integer) 0 127.0.0.1:6379> SETBIT user001 30 1 (integer) 0 127.0.0.1:6379> bitcount user001 (integer) 2 127.0.0.1:6379>應用場景案例
網站用戶的上線次數統計(尋找活躍用戶)
用戶名為key,上線的天作為offset,上線設置為1
示例: 用戶名為 user001 的用戶,今年第1天上線,第30天上線
SETBIT user001 1 1
SETBIT user001 30 1
BITCOUNT user001
代碼實現
import redisr = redis.Redis(host='192.168.43.49',port=6379,db=0)# user1,一年之中第1天和第5天登錄 r.setbit('user001',1,1) r.setbit('user001',5,1) # user2,一年之中第100天和第200天登錄 r.setbit('user002',100,1) r.setbit('user002',200,1) # user3,一年之中好多天登錄 for i in range(0,365,2):r.setbit('user003',i,1) # user4,一年之中好多天登錄 for i in range(0,365,3):r.setbit('user004',i,1)user_list = r.keys('user*') print(user_list)# 活躍用戶 active_users = [] # 不活躍用戶 noactive_user = []for user in user_list:# 統計位圖中有多少個 1login_count = r.bitcount(user)if login_count >= 100:active_users.append((user,login_count))else:noactive_user.append((user,login_count))# 打印活躍用戶 for active in active_users:print('活躍用戶:',active)Hash散列數據類型
- 定義
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-cVs8X0e3-1573565054414)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1562834840173.png)]
1、由field和關聯的value組成的鍵值對 2、field和value是字符串類型 3、一個hash中最多包含2^32-1個鍵值對- 優點
- 缺點(不適合hash情況)
基本命令操作
# 1、設置單個字段 HSET key field value HSETNX key field value # 2、設置多個字段 HMSET key field value field value # 3、返回字段個數 HLEN key # 4、判斷字段是否存在(不存在返回0) HEXISTS key field # 5、返回字段值 HGET key field # 6、返回多個字段值 HMGET key field filed # 7、返回所有的鍵值對 HGETALL key # 8、返回所有字段名 HKEYS key # 9、返回所有值 HVALS key # 10、刪除指定字段 HDEL key field # 11、在字段對應值上進行整數增量運算 HINCRBY key filed increment # 12、在字段對應值上進行浮點數增量運算 HINCRBYFLOAT key field incrementpython基本方法
# 1、更新一條數據的屬性,沒有則新建 hset(name, key, value) # 2、讀取這條數據的指定屬性, 返回字符串類型 hget(name, key) # 3、批量更新數據(沒有則新建)屬性 hmset(name, mapping) # 4、批量讀取數據(沒有則新建)屬性 hmget(name, keys, *args) # 5、獲取這條數據的所有屬性和對應的值,返回字典類型 hgetall(name) # 6、獲取這條數據的所有屬性名,返回列表類型 hkeys(name) # 7、刪除這條數據的指定屬性 hdel(name, *keys)Python代碼hash散列
import redisr = redis.Redis(host="192.168.43.49", port=6379, db=0,password='123456') # 新建一條鍵名為"userinfo"的數據, 包含屬性username r.hset("userinfo", "username", 'zhanshen001') # 更改鍵名為"userinfo"的數據, 更改屬性username的值 r.hset("userinfo", "username", 'zhanshen002')# 取出屬性username的值 username = r.hget("userinfo", "username")# 輸出看一下(發現屬性值已經為str) print('username',username)# 屬性集合 user_dict = {"password": "123456","name": "Wang Success","sex": "male","height": '178',"Tel": '13838383888', } # 批量添加屬性 r.hmset("userinfo", user_dict) # 取出所有數據(返回值為字典) h_data = r.hgetall("userinfo") print('all:', h_data) # 刪除屬性(可以批量刪除) r.hdel("userinfo", "Tel") # 取出所有屬性名 h_keys = r.hkeys("userinfo") print('all_key_name:',h_keys) # 取出所有屬性值 h_values = r.hvals('userinfo') print('all_values:',h_values)應用場景:微博好友關注
1、用戶ID為key,Field為好友ID,Value為關注時間user:10000 user:606 20190520user:10000 user:605 20190521 2、用戶維度統計統計數包括:關注數、粉絲數、喜歡商品數、發帖數用戶為key,不同維度為field,value為統計數比如關注了5人HSET user:10000 fans 5HINCRBY user:10000 fans 1應用場景: redis+mysql+hash組合使用
-
原理
用戶想要查詢個人信息 1、到redis緩存中查詢個人信息 2、redis中查詢不到,到mysql查詢,并緩存到redis 3、再次查詢個人信息 -
代碼實現
import redis import pymysql# 1、到redis中查詢個人信息 # 2、redis中查詢不到,到mysql查詢,并緩存到redis # 3、再次查詢個人信息username = input('請輸入用戶名:')# 到redis緩存中查詢 r = redis.Redis(host='192.168.153.128',port=6379,password='123456',db=0)# 如果redis中沒有緩存,則返回空字典{} result = r.hgetall(username) print('redis中找到:',result)if not result:db = pymysql.connect('192.168.153.128','tiger','123456','spider',charset='utf8')cursor = db.cursor()cursor.execute('select gender,age from user where username=%s',[username])# (('zhanshen001','m',30),)userinfo = cursor.fetchall()if not userinfo:print('MySQL中用戶信息不存在')else:dict = {'gender':userinfo[0][0],'age':userinfo[0][1]}# hmset第二個參數為字典r.hmset(username,dict)# 設置過期時間為5分鐘r.expire(username,60*5)print('redis緩存成功')
mysql數據庫中數據更新信息后同步到redis緩存
用戶修改個人信息時,要將數據同步到redis緩存
import redis import pymysql# 當用戶修改個人信息時,要同步更新到redis緩存中username = input('請輸入用戶名:') new_age = input('請輸入新年齡:')# 連接redis準備更新 r = redis.Redis(host='192.168.153.128',port=6379,password='123456',db=0) # 連接MySQL db = pymysql.connect('192.168.153.128','tiger','123456','spider',charset='utf8') cursor = db.cursor() cursor.execute('update user set age=%s where username=%s',[new_age,username]) db.commit()# 同步更新redis緩存 r.hset(username,'age',new_age) print('已同步到redis緩存') # 設置過期時間為5分鐘 r.expire(username,60*5)集合數據類型(set)
- 特點
- 基本命令
案例: 新浪微博的共同關注
需求: 當用戶訪問另一個用戶的時候,會顯示出兩個用戶共同關注過哪些相同的用戶
設計: 將每個用戶關注的用戶放在集合中,求交集即可
實現:
user001 = {‘peiqi’,‘qiaozhi’,‘danni’}
user002 = {‘peiqi’,‘qiaozhi’,‘lingyang’}
user001和user002的共同關注為:
SINTER user001 user002
結果為: {‘peiqi’,‘qiaozhi’}
python操作set
# 1、給name對應的集合中添加元素 sadd(name,values) r.sadd("set_name","tom") r.sadd("set_name","tom","jim")# 2、獲取name對應的集合的所有成員 smembers(name)# 3、獲取name對應的集合中的元素個數 scard(name) r.scard("set_name")# 4、檢查value是否是name對應的集合內的元素 sismember(name, value)# 5、隨機刪除并返回指定集合的一個元素 spop(name)# 6、刪除集合中的某個元素 srem(name, value) r.srem("set_name", "tom")# 7、獲取多個name對應集合的交集 sinter(keys, *args)r.sadd("set_name","a","b") r.sadd("set_name1","b","c") r.sadd("set_name2","b","c","d")print(r.sinter("set_name","set_name1","set_name2")) #輸出:{b'b'}# 8、獲取多個name對應的集合的并集 sunion(keys, *args) r.sunion("set_name","set_name1","set_name2")python代碼實現微博關注
import redisr = redis.Redis(host='192.168.153.128',port=6379,password='123456')# 用戶1關注的人 r.sadd('user_one','peiqi','qiaozhi','danni') # 用戶2關注的人 r.sadd('user_two','peiqi','qiaozhi','lingyang')# user001和user002的共同關注的人為??求差集 result = r.sinter('user_one','user_two') # 把集合中的每個元素轉為string數據類型 focus_on_set = set() for r in result:focus_on_set.add(r.decode())print(focus_on_set)有序集合sortedset
- 特點
-
示例
一個保存了水果價格的有序集合
| 元素 | 西瓜 | 葡萄 | 芒果 | 香蕉 | 蘋果 |
? 一個保存了員工薪水的有序集合
| 元素 | lucy | tom | jim | jack |
? 一個保存了正在閱讀某些技術書的人數
| 元素 | 核心編程 | 阿凡提 | 本拉登 | 阿姆斯特朗 | 比爾蓋茨 |
- 增加
zadd key score member
# 在有序集合中添加一個成員 zadd key score member # 查看指定區間元素(升序) zrange key start stop [withscores] # 查看指定區間元素(降序) ZREVRANGE key start stop [withscores] # 查看指定元素的分值 ZSCORE key member # 返回指定區間元素 # offset : 跳過多少個元素 # count : 返回幾個 # 小括號 : 開區間 zrangebyscore fruits (2.0 8.0 zrangebyscore key min max [withscores] [limit offset count] # 刪除成員 zrem key member # 增加或者減少分值 zincrby key increment member # 返回元素排名 zrank key member # 返回元素逆序排名 zrevrank key member # 刪除指定區間內的元素 zremrangebyscore key min max # 返回集合中元素個數 zcard key # 返回指定范圍中元素的個數 zcount key min max zcount fruits 4 7 zcount fruits (4 7 # 并集 zunionstore destination numkeys key [weights 權重值] [AGGREGATE SUM|MIN|MAX] # 交集:和并集類似,只取相同的元素 ZINTERSTORE destination numkeys key1 key2 WEIGHTS weight AGGREGATE SUM|MIN|MAX- 查看: 指定索引區間元素(升序)
zrange key start stop [withscores]
127.0.0.1:6379> ZRANGE salary 0 -1 1) "lucy" 2) "tom" 3) "jim" 4) "jack" 127.0.0.1:6379> ZRANGE salary 0 -1 withscores 1) "lucy" 2) "6000" 3) "tom" 4) "8000" 5) "jim" 6) "10000" 7) "jack" 8) "12000" 127.0.0.1:6379>-
查看: 指定索引區間元素(降序)
ZREVRANGE key start stop [withscores]
-
顯示指定元素的分值
ZSCORE key member
-
返回指定區間元素
zrangebyscore key min max [withscores] [limit offset count]
offset : 跳過多少個元素
count : 返回幾個
小括號 : 開區間 zrangebyscore fruits (2.0 8.0
- 刪除
zrem key member
127.0.0.1:6379> ZREM salary jim (integer) 1 127.0.0.1:6379> ZRANGE salary 0 -1 withscores 1) "lucy" 2) "6000" 3) "tom" 4) "8000" 5) "jack" 6) "12000" 127.0.0.1:6379>-
增加或者減少分值
zincrby key increment member
- 返回元素的排名(索引)
zrank key member
127.0.0.1:6379> zrank salary jack (integer) 2 127.0.0.1:6379>- 返回元素逆序排名
zrevrank key member
127.0.0.1:6379> ZREVRANK salary jack (integer) 0 127.0.0.1:6379> ZREVRANK salary lucy (integer) 2 127.0.0.1:6379>- 刪除指定區間內的元素
zremrangebyscore key min max
127.0.0.1:6379> ZREMRANGEBYSCORE salary 4000 6000 (integer) 1 127.0.0.1:6379> ZRANGE salary 0 -1 withscores 1) "tom" 2) "8000" 3) "jack" 4) "14000" 127.0.0.1:6379>-
返回集合中元素個數
zcard key
-
返回指定范圍中元素的個數
zcount key min max
zcount fruits 4 7
zcount fruits (4 7
127.0.0.1:6379> ZRANGE salary 0 -1 withscores 1) "tom" 2) "8000" 3) "jack" 4) "14000" 127.0.0.1:6379> zcount salary 8000 14000 (integer) 2 # 不包含8000,包含14000 127.0.0.1:6379> zcount salary (8000 14000 (integer) 1 127.0.0.1:6379> -
并集
zunionstore destination numkeys key [weights ] [AGGREGATE SUM|MIN|MAX]
127.0.0.1:6379> zadd stu_score1 60 tom 70 jim (integer) 2 127.0.0.1:6379> zadd stu_score2 80 tom 90 lucy (integer) 2 # 默認為SUM 127.0.0.1:6379> ZUNIONSTORE stu_score3 2 stu_score1 stu_score2 (integer) 3 127.0.0.1:6379> ZRANGE stu_score3 0 -1 withscores 1) "jim" 2) "70" 3) "lucy" 4) "90" 5) "tom" 6) "140" 127.0.0.1:6379> # WEIGHTS 和 AGGREGATE 127.0.0.1:6379> ZRANGE stu_score1 0 -1 withscores 1) "tom" 2) "60" 3) "jim" 4) "70" 127.0.0.1:6379> ZRANGE stu_score2 0 -1 withscores 1) "tom" 2) "80" 3) "lucy" 4) "90" # 權重1給stu_score1,權重0.5給stu_score2,算完權重之后求和SUM 127.0.0.1:6379> ZUNIONSTORE stu_score8 2 stu_score1 stu_score2 weights 1 0.5 AGGREGATE SUM (integer) 3 127.0.0.1:6379> ZRANGE stu_score8 0 -1 withscores 1) "lucy" 2) "45" 3) "jim" 4) "70" 5) "tom" 6) "100" 127.0.0.1:6379> -
交集
ZINTERSTORE destination numkeys key1 key2 WEIGHTS weight AGGREGATE SUM|MIN|MAX
和并集類似,只取相同的元素
python操作sorted set
import redisr = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0) # 注意第二個參數為字典 r.zadd('salary',{'tom':6000,'jim':8000,'jack':12000}) # 結果為列表中存放元組[(),(),()] print(r.zrange('salary',0,-1,withscores=True)) print(r.zrevrange('salary',0,-1,withscores=True)) # start:起始值,num:顯示條數 print(r.zrangebyscore('salary',6000,12000,start=1,num=2,withscores=True)) # 刪除 r.zrem('salary','tom') print(r.zrange('salary',0,-1,withscores=True)) # 增加分值 r.zincrby('salary',5000,'jack') print(r.zrange('salary',0,-1,withscores=True)) # 返回元素排名 print(r.zrank('salary','jack')) print(r.zrevrank('salary','jack')) # 刪除指定區間內的元素 r.zremrangebyscore('salary',6000,8000) print(r.zrange('salary',0,-1,withscores=True)) # 統計元素個數 print(r.zcard('salary')) # 返回指定范圍內元素個數 print(r.zcount('salary',6000,20000)) # 并集 r.zadd('salary2',{'jack':17000,'lucy':8000}) r.zunionstore('salary3',('salary','salary2'),aggregate='max') print(r.zrange('salary3',0,-1,withscores=True)) # 交集 r.zinterstore('salary4',('salary','salary2'),aggregate='max') print(r.zrange('salary4',0,-1,withscores=True))案例1:網易音樂排行榜
1、每首歌的歌名作為元素(先不考慮重復) 2、每首歌的播放次數作為分值 3、使用ZREVRANGE來獲取播放次數最多的歌曲代碼實現
import redisr = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)r.zadd('ranking',{'song1':1,'song2':1,'song3':1,'song4':1}) r.zadd('ranking',{'song5':1,'song6':1,'song7':1}) r.zadd('ranking',{'song8':1,'song9':1})r.zincrby('ranking',50,'song3') r.zincrby('ranking',60,'song5') r.zincrby('ranking',80,'song7') # 獲取前10名 rlist = r.zrevrange('ranking',0,2,withscores=True)i = 1 for r in rlist:print('第%d名:%s' % (i,r[0].decode()))i += 1案例2: 京東商品暢銷榜
# 第1天 ZADD mobile-001 5000 'huawei' 4000 'oppo' 3000 'iphone' # 第2天 ZADD mobile-002 5200 'huawei' 4300 'oppo' 3230 'iphone' # 第3天 ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone' 問題:如何獲取三款收集的銷量排名? ZUNIONSTORE mobile-001:003 mobile-001 mobile-002 mobile-003 # 可否? # 正確 1、ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone' 2、ZUNIONSTORE mobile-001:003 mobile-001 mobile-002 mobile-003 AGGREGATE MAXpython代碼實現
import redisr = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)# 第1天 day01_dict = {'huawei' : 5000,'oppo' : 4000,'iphone' : 3000 } # 第2天 day02_dict = {'huawei' : 5200,'oppo' : 4300,'iphone' : 3230 } # 第3天 day03_dict = {'huawei' : 5500,'oppo' : 4660,'iphone' : 3580 } r.zadd('mobile-day01',day01_dict) r.zadd('mobile-day02',day02_dict) r.zadd('mobile-day03',day03_dict)r.zunionstore('mobile-day01:03',('mobile-day01','mobile-day02','mobile-day03'),aggregate='max') rlist = r.zrevrange('mobile-day01:03',0,-1,withscores=True)i = 1 for r in rlist:print('第{}名:{}'.format(i,r[0].decode()) )redis_day02回顧
五大數據類型
1、字符串類型(string) 2、列表類型(list) 3、哈希類型(hash) 4、集合類型(set) 5、有序集合類型(sorted set)位圖操作(bitmap)
# 應用場景 1、可以實時的進行數據統計(網站用戶的上線次數統計) # 常用命令 1、setbit key offset value 2、BITCOUNT key哈希(散列)類型
# 應用場景 1、很適合存儲對象類型,比如說用戶ID作為key,用戶的所有屬性及值作為key對應的value (用戶維度統計-各種數據統計-發帖數、粉絲數等) # 常用命令 HSET key field value HSETNX key field value HMSET key field value field valueHGET key field HMGET key field filed HGETALL key HKEYS key HVALS keyHLEN key HEXISTS key fieldHINCRBY key filed increment HINCRBYFLOAT key field incrementHDEL key field集合類型
# 應用場景 1、共同關注、共同好友 # 常用命令SADD key member1 member2SMEMBERS key SCARD keySREM key member1 member2 SRANDOMMEMBER key [count]SISMEMBER key memberSDIFF key1 key2 SDIFFSTORE destination key1 key2SINTER key1 key2 SINTERSTORE destination key1 key2SUNION key1 key2 SUNIONSTORE destination key1 key2有序集合
# 應用場景 1、各種排行榜1、游戲:列出前100名高分選手2、列出某用戶當前的全球排名3、各種日排行榜、周排行榜、月排行榜 # 常用命令 zadd key score memberZRANGE key start stop [withscores] ZREVRANGE key start stop [withscores] ZRANGEBYSCORE key min max [withscores] [limit offset count] ZSCORE key member ZCOUNT key min max ZCARD keyZRANK key member ZREVRANK key memberZINCRBY key increment memberZREM key member ZREMRANGEBYSCORE key min maxzunionstore destination numkeys key [weights 權重值] [AGGREGATE SUM|MIN|MAX] ZINTERSTORE destination numkeys key1 key2 WEIGHTS weight AGGREGATE SUM|MIN|MAXredis_day03筆記
有序集合sortedset
有序集合的交集與并集
# 交集(weights代表權重值,aggregate代表聚合方式 - 先計算權重值,然后再聚合) ZINTERSTORE destination numkeys key1 key2 WEIGHTS weight AGGREGATE SUM|MIN|MAX # 并集(weights代表權重值,aggregate代表聚合方式 - 先計算權重值,然后再聚合) ZUNIONSTORE destination numkeys key [weights 權重值] [AGGREGATE SUM|MIN|MAX]案例1:網易音樂排行榜
1、每首歌的歌名作為元素(先不考慮重復) 2、每首歌的播放次數作為分值 3、使用ZREVRANGE來獲取播放次數最多的歌曲代碼實現
import redisr = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)r.zadd('ranking',{'song1':1,'song2':1,'song3':1,'song4':1}) r.zadd('ranking',{'song5':1,'song6':1,'song7':1}) r.zadd('ranking',{'song8':1,'song9':1})r.zincrby('ranking',50,'song3') r.zincrby('ranking',60,'song5') r.zincrby('ranking',80,'song7') # 獲取前10名 rlist = r.zrevrange('ranking',0,2,withscores=True)i = 1 for r in rlist:print('第%d名:%s' % (i,r[0].decode()))i += 1案例2: 京東商品暢銷榜
# 第1天 ZADD mobile-001 5000 'huawei' 4000 'oppo' 3000 'iphone' # 第2天 ZADD mobile-002 5200 'huawei' 4300 'oppo' 3230 'iphone' # 第3天 ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone' 問題:如何獲取三款手機的銷量排名? ZUNIONSTORE mobile-001:003 mobile-001 mobile-002 mobile-003 # 可否? # 正確 1、ZADD mobile-003 5500 'huawei' 4660 'oppo' 3580 'iphone' 2、ZUNIONSTORE mobile-001:003 mobile-001 mobile-002 mobile-003 AGGREGATE MAXpython代碼實現
import redisr = redis.Redis(host='192.168.43.49',port=6379,password='123456',db=0)# 第1天 day01_dict = {'huawei' : 5000,'oppo' : 4000,'iphone' : 3000 } # 第2天 day02_dict = {'huawei' : 5200,'oppo' : 4300,'iphone' : 3230 } # 第3天 day03_dict = {'huawei' : 5500,'oppo' : 4660,'iphone' : 3580 } r.zadd('mobile-day01',day01_dict) r.zadd('mobile-day02',day02_dict) r.zadd('mobile-day03',day03_dict)r.zunionstore('mobile-day01:03',('mobile-day01','mobile-day02','mobile-day03'),aggregate='max') rlist = r.zrevrange('mobile-day01:03',0,-1,withscores=True)i = 1 for r in rlist:print('第{}名:{}'.format(i,r[0].decode()) )數據持久化
持久化定義
將數據從掉電易失的內存放到永久存儲的設備上為什么需要持久化
因為所有的數據都在內存上,所以必須得持久化- 數據持久化分類之 - RDB模式(默認開啟)
默認模式
1、保存真實的數據 2、將服務器包含的所有數據庫數據以二進制文件的形式保存到硬盤里面 3、默認文件名 :/var/lib/redis/dump.rdb創建rdb文件的兩種方式
**方式一:**服務器執行客戶端發送的SAVE或者BGSAVE命令
127.0.0.1:6379> SAVE OK # 特點 1、執行SAVE命令過程中,redis服務器將被阻塞,無法處理客戶端發送的命令請求,在SAVE命令執行完畢后,服務器才會重新開始處理客戶端發送的命令請求 2、如果RDB文件已經存在,那么服務器將自動使用新的RDB文件代替舊的RDB文件 # 工作中定時持久化保存一個文件127.0.0.1:6379> BGSAVE Background saving started # 執行過程如下 1、客戶端 發送 BGSAVE 給服務器 2、服務器馬上返回 Background saving started 給客戶端 3、服務器 fork() 子進程做這件事情 4、服務器繼續提供服務 5、子進程創建完RDB文件后再告知Redis服務器# 配置文件相關操作 /etc/redis/redis.conf dir /var/lib/redis # 表示rdb文件存放路徑 dbfilename dump.rdb # 文件名# 兩個命令比較 SAVE比BGSAVE快,因為需要創建子進程,消耗額外的內存# 補充:可以通過查看日志文件來查看redis都做了哪些操作 # 日志文件:配置文件中搜索 logfile logfile /var/log/redis/redis-server.log方式二:設置配置文件條件滿足時自動保存(使用最多)
# 命令行示例 redis>save 300 10表示如果距離上一次創建RDB文件已經過去了300秒,并且服務器的所有數據庫總共已經發生了不少于10次修改,那么執行BGSAVE命令 redis>save 60 10000表示'如果距離上一次創建rdb文件已經過去60秒,并且服務器所有數據庫總共已經發生了不少于10000次修改,那么執行bgsave命令'# redis配置文件默認 save 900 1 save 300 10 save 60 100001、只要三個條件中的任意一個被滿足時,服務器就會自動執行BGSAVE2、每次創建RDB文件之后,服務器為實現自動持久化而設置的時間計數器和次數計數器就會被清零,并重新開始計數,所以多個保存條件的效果不會疊加- 數據持久化分類之 - AOF(AppendOnlyFile,默認未開啟)
特點
1、存儲的是命令,而不是真實數據 2、默認不開啟 # 開啟方式(修改配置文件) 1、/etc/redis/redis.confappendonly yes # 把 no 改為 yesappendfilename "appendonly.aof" 2、重啟服務sudo /etc/init.d/redis-server restartRDB缺點
1、創建RDB文件需要將服務器所有的數據庫的數據都保存起來,這是一個非常消耗資源和時間的操作,所以服務器需要隔一段時間才創建一個新的RDB文件,也就是說,創建RDB文件不能執行的過于頻繁,否則會嚴重影響服務器的性能 2、可能丟失數據AOF持久化原理及優點
# 原理1、每當有修改數據庫的命令被執行時,服務器就會將執行的命令寫入到AOF文件的末尾2、因為AOF文件里面存儲了服務器執行過的所有數據庫修改的命令,所以給定一個AOF文件,服務器只要重新執行一遍AOF文件里面包含的所有命令,就可以達到還原數據庫的目的# 優點用戶可以根據自己的需要對AOF持久化進行調整,讓Redis在遭遇意外停機時不丟失任何數據,或者只丟失一秒鐘的數據,這比RDB持久化丟失的數據要少的多安全性問題考慮
# 因為雖然服務器執行一個修改數據庫的命令,就會把執行的命令寫入到AOF文件,但這并不意味著AOF文件持久化不會丟失任何數據,在目前常見的操作系統中,執行系統調用write函數,將一些內容寫入到某個文件里面時,為了提高效率,系統通常不會直接將內容寫入硬盤里面,而是將內容放入一個內存緩存區(buffer)里面,等到緩沖區被填滿時才將存儲在緩沖區里面的內容真正寫入到硬盤里# 所以1、AOF持久化:當一條命令真正的被寫入到硬盤里面時,這條命令才不會因為停機而意外丟失2、AOF持久化在遭遇停機時丟失命令的數量,取決于命令被寫入到硬盤的時間3、越早將命令寫入到硬盤,發生意外停機時丟失的數據就越少,反之亦然策略 - 配置文件
# 打開配置文件:/etc/redis/redis.conf,找到相關策略如下 1、alwarys服務器每寫入一條命令,就將緩沖區里面的命令寫入到硬盤里面,服務器就算意外停機,也不會丟失任何已經成功執行的命令數據 2、everysec(# 默認)服務器每一秒將緩沖區里面的命令寫入到硬盤里面,這種模式下,服務器即使遭遇意外停機,最多只丟失1秒的數據 3、no服務器不主動將命令寫入硬盤,由操作系統決定何時將緩沖區里面的命令寫入到硬盤里面,丟失命令數量不確定# 運行速度比較 always:速度慢 everysec和no都很快,默認值為everysecAOF文件中是否會產生很多的冗余命令?
為了讓AOF文件的大小控制在合理范圍,避免胡亂總長,redis提供了AOF重寫功能,通過這個功能,服務器可以產生一個新的AOF文件-- 新的AOF文件記錄的數據庫數據和原由的AOF文件記錄的數據庫數據完全一樣-- 新的AOF文件會使用盡可能少的命令來記錄數據庫數據,因此新的AOF文件的提及通常會小很多-- AOF重寫期間,服務器不會被阻塞,可以正常處理客戶端發送的命令請求示例
| select 0 | SELECT 0 |
| sadd myset peiqi | SADD myset peiqi qiaozhi danni |
| sadd myset qiaozhi | SET msg ‘hello tarena’ |
| sadd myset danni | RPUSH mylist 2 3 5 |
| sadd myset lingyang | |
| INCR number | |
| INCR number | |
| DEL number | |
| SET message ‘hello world’ | |
| SET message ‘hello tarena’ | |
| RPUSH mylist 1 2 3 | |
| RPUSH mylist 5 | |
| LPOP mylist |
AOF文件重寫方法觸發
1、客戶端向服務器發送BGREWRITEAOF命令127.0.0.1:6379> BGREWRITEAOFBackground append only file rewriting started2、修改配置文件讓服務器自動執行BGREWRITEAOF命令auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb# 解釋1、只有當AOF文件的增量大于100%時才進行重寫,也就是大一倍的時候才觸發# 第一次重寫新增:64M# 第二次重寫新增:128M# 第三次重寫新增:256M(新增128M)RDB和AOF持久化對比
| 全量備份,一次保存整個數據庫 | 增量備份,一次保存一個修改數據庫的命令 |
| 保存的間隔較長 | 保存的間隔默認為一秒鐘 |
| 數據還原速度快 | 數據還原速度一般,冗余命令多,還原速度慢 |
| 執行SAVE命令時會阻塞服務器,但手動或者自動觸發的BGSAVE不會阻塞服務器 | 無論是平時還是進行AOF重寫時,都不會阻塞服務器 |
| 更適合數據備份 | 更適合用來保存數據,通常意義上的數據持久化,在appendfsync always模式下運行時 |
Redis主從復制
- 定義
- 作用
- 原理
-
兩種實現方式
方式一(命令行實現1)
redis-server --slaveof
? 方式一(命令行實現2)
# 服務端啟動 redis-server --port 6380 # 客戶端連接 tarena@tedu:~$ redis-cli -p 6300 127.0.0.1:6300> keys * 1) "myset" 2) "mylist" 127.0.0.1:6300> set mykey 123 OK # 切換為從 127.0.0.1:6300> slaveof 127.0.0.1 6379 OK 127.0.0.1:6300> set newkey 456 (error) READONLY You can't write against a read only slave. 127.0.0.1:6300> keys * 1) "myset" 2) "mylist" # 再切換為主 127.0.0.1:6300> slaveof no one OK 127.0.0.1:6300> set name hello OK方式二(修改配置文件)
# 修改配置文件 vi redis_6300.conf slaveof 127.0.0.1 6379 port 6300 # 啟動redis服務 redis-server redis_6300.conf # 客戶端連接測試 redis-cli -p 6300 127.0.0.1:6300> hset user_001 username guods (error) READONLY You can't write against a read only slave.問題總結
1、一個Master可以有多個Slaves 2、Slave下線,只是讀請求的處理性能下降 3、Master下線,寫請求無法執行 4、其中一臺Slave使用SLAVEOF no one命令成為Master,其他Slaves執行SLAVEOF命令指向這個新的Master,從它這里同步數據 # 以上過程是手動的,能夠實現自動,這就需要Sentine哨兵,實現故障轉移Failover操作演示
1、啟動端口6400redis,設置為6379的slaveredis-server --port 6400redis-cli -p 6400redis>slaveof 127.0.0.1 6379 2、啟動端口6401redis,設置為6379的slaveredis-server --port 6401redis-cli -p 6401redis>slaveof 127.0.0.1 6379 3、關閉6379redissudo /etc/init.d/redis-server stop 4、把6400redis設置為masterredis-cli -p 6401redis>slaveof no one 5、把6401的redis設置為6400redis的salveredis-cli -p 6401redis>slaveof 127.0.0.1 6400 # 這是手動操作,效率低,而且需要時間,有沒有自動的???官方高可用方案Sentinel
Redis之哨兵 - sentinel
1、Sentinel會不斷檢查Master和Slaves是否正常 2、每一個Sentinel可以監控任意多個Master和該Master下的Slaves案例演示
? **1、**環境搭建
# 共3臺redis的服務器,如果是不同機器端口號可以是一樣的 1、啟動6379的redis服務器sudo /etc/init.d/redis-server start 2、啟動6380的redis服務器,設置為6379的從redis-server --port 6380tarena@tedu:~$ redis-cli -p 6380127.0.0.1:6380> slaveof 127.0.0.1 6379OK 3、啟動6381的redis服務器,設置為6379的從redis-server --port 6381tarena@tedu:~$ redis-cli -p 6381127.0.0.1:6381> slaveof 127.0.0.1 6379? **2、**安裝并搭建sentinel哨兵
# 1、安裝redis-sentinel sudo apt install redis-sentinel# 2、新建配置文件sentinel.conf port 26379 Sentinel monitor tedu 127.0.0.1 6379 1# 3、啟動sentinel 方式一: redis-sentinel sentinel.conf 方式二: redis-server sentinel.conf --sentinel# 將master的redis服務終止,查看從是否會提升為主 sudo /etc/init.d/redis-server stop # 發現提升6381為master,其他兩個為從 # 在6381上設置新值,6380查看 127.0.0.1:6381> set name tedu OK# 啟動6379,觀察日志,發現變為了6381的從 主從+哨兵基本就夠用了sentinel.conf解釋
# sentinel監聽端口,默認是26379,可以修改 port 26379 # 告訴sentinel去監聽地址為ip:port的一個master,這里的master-name可以自定義,quorum是一個數字,指明當有多少個sentinel認為一個master失效時,master才算真正失效 sentinel monitor <master-name> <ip> <redis-port> <quorum>博客項目解決高并發問題
1、在數據庫中創建庫 blog_server,指定字符編碼utf8
mysql -uroot -p123456 mysql>create database blog_server charset utf8;2、同步數據庫,并在user_profile中插入表記錄
1、python3 manage.py makemigrations 2、python3 manage.py migrate 3、insert into user_profile values ('guoxiaonao','guoxiaonao','guoxiaonao@tedu.cn','123456','aaaaaaaa','bbbbbbbb','cccccccc');3、啟動django項目,并找到django路由測試 test_api函數
1、python3 manage.py runserver 2、查看項目的 urls.py 路由,打開firefox瀏覽器輸入地址:http://127.0.0.1:8000/test_api # 返回結果: code 2004、在數據庫表中創建測試字段score
1、user/models.py添加:score = models.IntegerField(verbose_name=u'分數',null=True,default=0) 2、同步到數據庫python3 manage.py makemigrations userpython3 manage.py migrate user 3、到數據庫中確認查看3、在blog_server/views.py中補充 test_api 函數,對數據庫中score字段進行 +1 操作
from user.models import UserProfile def test_api(request):#JsonResponse 1,將返回內容序列化成json#2,response中添加 content-type: application/json# return JsonResponse({'code':200})u = UserProfile.objects.get(username='guoxiaonao')u.score += 1u.save()return JsonResponse({'msg': 'test is ok'})4、啟多個服務端,模擬30個并發請求
(1)在tools中新建py文件 test_api.py,模擬30個并發請求
import threading import requests import randomdef getRequest():url='http://127.0.0.1:8000/test_api'url2='http://127.0.0.1:8001/test_api'get_url = random.choice([url, url2])requests.get(get_url)ts = [] for i in range(30):t=threading.Thread(target=getRequest,args=())ts.append(t)if __name__ == '__main__':for t in ts:t.start()for t in ts:t.join()(2) python3 test_api.py
(3) 在數據庫中查看 score 字段的值
并沒有+30,而且沒有規律,每次加的次數都不同,如何解決???解決方案:redis分布式鎖
def test_api(request):# 解決方法二:redis分布式鎖import redispool = redis.ConnectionPool(host='localhost', port=6379, db=0)r = redis.Redis(connection_pool=pool)try:with r.lock('guoxiaonao', blocking_timeout=3) as lock:u = UserProfile.objects.get(username='guoxiaonao')u.score += 1u.save()except Exception as e:print('lock is failed')day04筆記
Redis事務
特點
1. 單獨的隔離操作:事務中的所有命令會被序列化、按順序執行,在執行的過程中不會被其他客戶端發送來的命令打斷 2. 不保證原子性:redis中的一個事務中如果存在命令執行失敗,那么其他命令依然會被執行,沒有回滾機制事務命令
1、MULTI # 開啟事務 2、命令1 # 執行命令 3、命令2 ... ... 4、EXEC # 提交到數據庫執行 4、DISCARD # 取消事務使用步驟
# 開啟事務 127.0.0.1:6379> MULTI OK # 命令1入隊列 127.0.0.1:6379> INCR n1 QUEUED # 命令2入隊列 127.0.0.1:6379> INCR n2 QUEUED # 提交到數據庫執行 127.0.0.1:6379> EXEC 1) (integer) 1 2) (integer) 1事務中命令錯誤處理
# 1、命令語法錯誤,命令入隊失敗,直接自動discard退出這個事務這個命令在執行調用之前會發生錯誤。例如,這個命令可能有語法錯誤(錯誤的參數數量,錯誤的命令名),或者其他某些緊急的狀態,如內存溢出處理方案:客戶端發生了第一個錯誤情況,在exec執行之前發生的。通過檢查隊列命令返回值:如果這個命令回答這個隊列的命令是正確的,否者redis會返回一個錯誤。如果那里發生了一個隊列命令錯誤,大部分客戶端將會退出并丟棄這個事務# 2、命令語法沒錯,但類型操作有誤,則事務執行調用之后失敗,無法進行事務回滾從我們施行了一個由于錯誤的value的key操作(例如對著String類型的value施行了List命令操作)處理方案:發生在EXEC之后的是沒有特殊方式去處理的:即使某些命令在事務中失敗,所有的其他命令都將會被執行。 127.0.0.1:6379> MULTI OK 127.0.0.1:6379> set num 10 QUEUED 127.0.0.1:6379> LPOP num QUEUED 127.0.0.1:6379> exec 1) OK 2) (error) WRONGTYPE Operation against a key holding the wrong kind of value 127.0.0.1:6379> get num "10" 127.0.0.1:6379>為什么redis不支持事務回滾
- 觀點
pipeline補充
python使用pipeline()與execute()批量進行批量操作
作用:減少數據庫的IO來提升數據庫的性能
pipe = r.pipeline() pipe.REDIS命令 pipe.REDIS命令 pipe.execute()示例
import redis# 創建連接池并連接到redis pool = redis.ConnectionPool(host = '192.168.153.130',db=0,port=6379) r = redis.Redis(connection_pool=pool)# 第一組 pipe = r.pipeline() pipe.set('fans',50) pipe.incr('fans') pipe.incrby('fans',100) pipe.execute()# 第二組 pipe.get('fans') pipe.get('pwd') # [b'151', b'123'] result = pipe.execute() print(result)Redis常見問題匯總
- Redis優點
-
來介紹一下redis中的數據類型
類型特點使用場景 string 簡單key-value類型,value可為字符串和數字 常規計數(微博數, 粉絲數等功能) hash 是一個string類型的field和value的映射表,hash特別適合用于存儲對象 存儲部分可能需要變更的數據(比如用戶信息) list 有序可重復列表 關注列表,粉絲列表,消息隊列等 set 無序不可重復列表 存儲并計算關系(如微博,關注人或粉絲存放在集合,可通過交集、并集、差集等操作實現如共同關注、共同喜好等功能) sorted set 每個元素帶有分值的集合 各種排行榜 -
redis中的持久化方案
-
使用過Redis分布式鎖么,它是什么回事?
從redis2.8開始,set命令集成了兩個參數,nx和ex,先拿nx來爭搶鎖,搶到之后,再用ex參數給鎖加一個過期時間防止鎖忘記了釋放,造成死鎖 應用場景:秒殺活動進程1:set miaosha aaa nx ex 3 獲取鎖秒殺記錄 -1del miaosha進程2:set miaosha 111 nx ex 3 無法獲取鎖# 2.8以前是兩條命令,這樣容易造成死鎖 # setnx key value # 獲取鎖 # expier key 5 # 釋放鎖# 解決方法:redis分布式鎖import redispool = redis.ConnectionPool(host='localhost', port=6379, db=0)r = redis.Redis(connection_pool=pool)try:with r.lock('guoxiaonao', blocking_timeout=3) as lock:u = UserProfile.objects.get(username='yanxu')u.score += 1u.save()except Exception as e:print('lock is failed')return JsonResponse({"msg": 'test is ok'}) -
緩存穿透
-
緩存擊穿
# 原理 緩存沒有,數據庫有,一般是緩存時間到期, 順勢并發太大#解決方案 1、熱點數據不過期 2、上鎖: 重新設計緩存的使用方式,當我們通過key去查詢數據時,首先查詢緩存,如果沒有,就通過分布式鎖進行加鎖,取得鎖的進程查DB并設置緩存,然后解鎖;其他進程如果發現有鎖就等待,然后等解鎖后返回緩存數據或者再次查詢DB -
緩存雪崩
# 原理 緩存中大批量數據過期,導致瞬時大批量不同請求注入DB# 解決方案 解決方案 1、緩存設置隨機時間(避免緩存設置相近的有效期;為有效期增加隨機值) 2、熱點數據不過期 -
哈希碰撞
# 在位置處發生哈希碰撞 name --> 哈希處理 --> 哈希值 --> 哈希函數算值找位置(比如是30) age --> 哈希處理 --> 哈希值 --> 哈希函數算值如果算出來的也是30 則發生了哈希碰撞
總結
以上是生活随笔為你收集整理的redis学习笔记,常用方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 房地产业务学习 04 -房企信息化 谁忽
- 下一篇: 《了不起的盖茨比》中体现的人生观、价值观