您好,登錄后才能下訂單哦!
這篇文章主要講解了“python操作redis事務的方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“python操作redis事務的方法”吧!
類型 | 特點 | 使用場景 |
---|---|---|
string | 簡單key-value類型,value可為字符串和數字 | 常規計數(微博數, 粉絲數等功能) |
hash | 是一個string類型的field和value的映射表,hash特別適合用于存儲對象 | 存儲部分可能需要變更的數據(比如用戶信息) |
list | 有序可重復列表 | 消息隊列等 |
set | 無序不可重復列表 | 存儲并計算關系(如微博,關注人或粉絲存放在集合,可通過交集、并集、差集等操作實現如共同關注、共同喜好等功能) |
sorted set | 每個元素帶有分值的集合 | 各種排行榜 |
特點
1. 單獨的隔離操作:事務中的所有命令會被序列化、按順序執行,在執行的過程中不會被其他客戶端發送來的命令打斷 2. 不保證原子性:redis中的一個事務中如果存在命令執行失敗,那么其他命令依然會被執行,沒有回滾機制
事務命令
1、MULTI # 開啟事務 mysql begin 2、命令1 # 執行命令 3、命令2 ... ... 4、EXEC # 提交到數據庫執行 mysql commit 4、DISCARD # 取消事務 mysql 'rollback'
使用步驟
# 開啟事務 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退出這個事務 這個在命令在執行調用之前會發生錯誤。例如,這個命令可能有語法錯誤(錯誤的參數數量,錯誤的命令名) 處理方案:語法錯誤則自動執行discard 案例: 127.0.0.1:6379[7]> MULTI OK 127.0.0.1:6379[7]> get a QUEUED 127.0.0.1:6379[7]> getsss a (error) ERR unknown command 'getsss' 127.0.0.1:6379[7]> 127.0.0.1:6379[7]> 127.0.0.1:6379[7]> EXEC (error) EXECABORT Transaction discarded because of previous errors. # 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不支持回滾?
定義:批量執行redis命令,減少通信io
注意:此為客戶端技術
示例
import redis # 創建連接池并連接到redis pool = redis.ConnectionPool(host = '127.0.0.1',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()
性能對比
# 創建連接池并連接到redis pool = redis.ConnectionPool(host = '127.0.0.1',db=0,port=6379) r = redis.Redis(connection_pool=pool) def withpipeline(r): p = r.pipeline() for i in range(1000): key = 'test1' + str(i) value = i+1 p.set(key, value) p.execute() def withoutpipeline(r): for i in range(1000): key = 'test2' + str(i) value = i+1 r.set(key, value)
python 操作 redis事務
with r.pipeline(transaction=true) as pipe pipe.multi() pipe.incr("books") pipe.incr("books") values = pipe.execute()
作用: 事務過程中,可對指定key進行監聽,命令提交時,若被監聽key對應的值未被修改時,事務方可提交成功,否則失敗
> watch books OK > multi OK > incr books QUEUED > exec # 事務執行失敗 (nil) watch之后,再開一個終端進入redis > incr books # 修改book值 (integer) 1
python操作watch
#同時對一個賬戶進行操作, 當前余額 * 2
持久化定義
將數據從掉電易失的內存放到永久存儲的設備上
為什么需要持久化
因為所有的數據都在內存上,所以必須得持久化
1、保存真實的數據 2、將服務器包含的所有數據庫數據以二進制文件的形式保存到硬盤里面 3、默認文件名 :/var/lib/redis/dump.rdb
創建rdb文件的兩種方式
**方式一:**redis終端中使用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 263行: dir /var/lib/redis # 表示rdb文件存放路徑 253行: dbfilename dump.rdb # 文件名 # 兩個命令比較 SAVE比BGSAVE快,因為需要創建子進程,消耗額外的內存 # 補充:可以通過查看日志文件來查看redis都做了哪些操作 # 日志文件:配置文件中搜索 logfile logfile /var/log/redis/redis-server.log
方式二:設置配置文件條件滿足時自動保存(使用最多)
# redis配置文件默認 218行: save 900 1 219行: save 300 10 表示如果距離上一次創建RDB文件已經過去了300秒,并且服務器的所有數據庫總共已經發生了不少于10次修改,那么自動執行BGSAVE命令 220行: save 60 10000 1、只要三個條件中的任意一個被滿足時,服務器就會自動執行BGSAVE 2、每次創建RDB文件之后,服務器為實現自動持久化而設置的時間計數器和次數計數器就會被清零,并重新開始計數,所以多個保存條件的效果不會疊加 # 該配置項也可以在命令行執行 [不推薦] redis>save 60 10000
RDB缺點
1、創建RDB文件需要將服務器所有的數據庫的數據都保存起來,這是一個非常消耗資源和時間的操作,所以服務器需要隔一段時間才創建一個新的RDB文件,也就是說,創建RDB文件不能執行的過于頻繁,否則會嚴重影響服務器的性能 2、可能丟失數據
1、存儲的是命令,而不是真實數據 2、默認不開啟 # 開啟方式(修改配置文件) 1、/etc/redis/redis.conf 672行: appendonly yes # 把 no 改為 yes 676行: appendfilename "appendonly.aof" 2、重啟服務 sudo /etc/init.d/redis-server restart
AOF持久化原理及優點
# 原理 1、每當有修改數據庫的命令被執行時, 2、因為AOF文件里面存儲了服務器執行過的所有數據庫修改的命令,所以給定一個AOF文件,服務器只要重新執行一遍AOF文件里面包含的所有命令,就可以達到還原數據庫的目的 # 優點 用戶可以根據自己的需要對AOF持久化進行調整,讓Redis在遭遇意外停機時不丟失任何數據,或者只丟失一秒鐘的數據,這比RDB持久化丟失的數據要少的多
特殊說明
# 因為 雖然服務器執行一個修改數據庫的命令,就會把執行的命令寫入到AOF文件,但這并不意味著AOF文件持久化不會丟失任何數據,在目前常見的操作系統中,執行系統調用write函數,將一些內容寫入到某個文件里面時,為了提高效率,系統通常不會直接將內容寫入硬盤里面,而是將內容放入一個內存緩存區(buffer)里面,等到緩沖區被填滿時才將存儲在緩沖區里面的內容真正寫入到硬盤里 # 所以 1、AOF持久化:當一條命令真正的被寫入到硬盤里面時,這條命令才不會因為停機而意外丟失 2、AOF持久化在遭遇停機時丟失命令的數量,取決于命令被寫入到硬盤的時間 3、越早將命令寫入到硬盤,發生意外停機時丟失的數據就越少,反之亦然
策略 - 配置文件
# 打開配置文件:/etc/redis/redis.conf,找到相關策略如下 1、701行: alwarys 服務器每寫入一條命令,就將緩沖區里面的命令寫入到硬盤里面,服務器就算意外停機,也不會丟失任何已經成功執行的命令數據 2、702行: everysec(# 默認) 服務器每一秒將緩沖區里面的命令寫入到硬盤里面,這種模式下,服務器即使遭遇意外停機,最多只丟失1秒的數據 3、703行: no 服務器不主動將命令寫入硬盤,由操作系統決定何時將緩沖區里面的命令寫入到硬盤里面,丟失命令數量不確定 # 運行速度比較 always:速度慢 everysec和no都很快,默認值為everysec
AOF重寫
思考:AOF文件中是否會產生很多的冗余命令?
為了讓AOF文件的大小控制在合理范圍,避免胡亂增長,redis提供了AOF重寫功能,通過這個功能,服務器可以產生一個新的AOF文件 -- 新的AOF文件記錄的數據庫數據和原由的AOF文件記錄的數據庫數據完全一樣 -- 新的AOF文件會使用盡可能少的命令來記錄數據庫數據,因此新的AOF文件的提及通常會小很多 -- AOF重寫期間,服務器不會被阻塞,可以正常處理客戶端發送的命令請求
示例
原有AOF文件 | 重寫后的AOF文件 |
---|---|
select 0 | SELECT 0 |
sadd myset peiqi | SADD myset peiqi qiaozhi danni lingyang |
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> BGREWRITEAOF Background append only file rewriting started 2、修改配置文件讓服務器自動執行BGREWRITEAOF命令 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 解釋 1、只有當AOF文件的增量大于100%時才進行重寫,也就是大一倍的時候才觸發 # 第一次重寫新增:64M # 第二次重寫新增:128M # 第三次重寫新增:256M(新增128M)
RDB和AOF持久化對比
RDB持久化 | AOF持久化 |
---|---|
全量備份,一次保存整個數據庫 | 增量備份,一次保存一個修改數據庫的命令 |
保存的間隔較長 | 保存的間隔默認為一秒鐘 |
數據還原速度快 | 數據還原速度一般,冗余命令多,還原速度慢 |
執行SAVE命令時會阻塞服務器,但手動或者自動觸發的BGSAVE不會阻塞服務器 | 無論是平時還是進行AOF重寫時,都不會阻塞服務器 |
# 用redis用來存儲真正數據,每一條都不能丟失,都要用always,有的做緩存,有的保存真數據,我可以開多個redis服務,不同業務使用不同的持久化,新浪每個服務器上有4個redis服務,整個業務中有上千個redis服務,分不同的業務,每個持久化的級別都是不一樣的。
數據恢復(無需手動操作)
既有dump.rdb,又有appendonly.aof,恢復時找誰? 先找appendonly.aof
配置文件常用配置總結
# 設置密碼 1、requirepass password # 開啟遠程連接 2、bind 127.0.0.1 ::1 注釋掉 3、protected-mode no 把默認的 yes 改為 no # rdb持久化-默認配置 4、dbfilename 'dump.rdb' 5、dir /var/lib/redis # rdb持久化-自動觸發(條件) 6、save 900 1 7、save 300 10 8、save 60 10000 # aof持久化開啟 9、appendonly yes 10、appendfilename 'appendonly.aof' # aof持久化策略 11、appendfsync always 12、appendfsync everysec # 默認 13、appendfsync no # aof重寫觸發 14、auto-aof-rewrite-percentage 100 15、auto-aof-rewrite-min-size 64mb # 設置為從服務器 16、salveof <master-ip> <master-port>
Redis相關文件存放路徑
1、配置文件: /etc/redis/redis.conf 2、備份文件: /var/lib/redis/*.rdb|*.aof 3、日志文件: /var/log/redis/redis-server.log 4、啟動文件: /etc/init.d/redis-server # /etc/下存放配置文件 # /etc/init.d/下存放服務啟動文件
定義
1、一個Redis服務可以有多個該服務的復制品,這個Redis服務成為master,其他復制品成為slaves 2、master會一直將自己的數據更新同步給slaves,保持主從同步 3、只有master可以執行寫命令,slave只能執行讀命令
作用
分擔了讀的壓力(高并發)
原理
從服務器執行客戶端發送的讀命令,比如GET、LRANGE、SMEMMBERS、HGET、ZRANGE等等,客戶端可以連接slaves執行讀請求,來降低master的讀壓力
實現方式
方式一(Linux命令行實現)
redis-server --slaveof --masterauth
# 從服務端 redis-server --port 6300 --slaveof 127.0.0.1 6379 # 從客戶端 redis-cli -p 6300 127.0.0.1:6300> keys * # 發現是復制了原6379端口的redis中數據 127.0.0.1:6300> set mykey 123 (error) READONLY You can't write against a read only slave. 127.0.0.1:6300> # 從服務器只能讀數據,不能寫數據
方式二(Redis命令行實現)
# 兩條命令 1、>slaveof IP PORT 2、>slaveof no one # 服務端啟動 redis-server --port 6301 # 客戶端連接 tarena@tedu:~$ redis-cli -p 6301 127.0.0.1:6301> keys * 1) "myset" 2) "mylist" 127.0.0.1:6301> set mykey 123 OK # 切換為從 127.0.0.1:6301> slaveof 127.0.0.1 6379 OK 127.0.0.1:6301> set newkey 456 (error) READONLY You can't write against a read only slave. 127.0.0.1:6301> keys * 1) "myset" 2) "mylist" # 再切換為主 127.0.0.1:6301> slaveof no one OK 127.0.0.1:6301> set name hello OK
方式三(利用配置文件)
# 每個redis服務,都有1個和他對應的配置文件 # 兩個redis服務 1、6379 -> /etc/redis/redis.conf 2、6300 -> /home/tarena/redis_6300.conf # 修改配置文件 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:1 username guods (error) READONLY You can't write against a read only slave.
問題:master掛了怎么辦?
1、一個Master可以有多個Slaves 2、Slave下線,只是讀請求的處理性能下降 3、Master下線,寫請求無法執行 4、其中一臺Slave使用SLAVEOF no one命令成為Master,其他Slaves執行SLAVEOF命令指向這個新的Master,從它這里同步數據 # 以上過程是手動的,能夠實現自動,這就需要Sentinel哨兵,實現故障轉移Failover操作
演示
1、啟動端口6400redis,設置為6379的slave redis-server --port 6400 redis-cli -p 6400 redis>slaveof 127.0.0.1 6379 2、啟動端口6401redis,設置為6379的slave redis-server --port 6401 redis-cli -p 6401 redis>slaveof 127.0.0.1 6379 3、關閉6379redis sudo /etc/init.d/redis-server stop 4、把6400redis設置為master redis-cli -p 6400 redis>slaveof no one 5、把6401的redis設置為6400redis的salve redis-cli -p 6401 redis>slaveof 127.0.0.1 6400 # 這是手動操作,效率低,而且需要時間,有沒有自動的???
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 6380 tarena@tedu:~$ redis-cli -p 6380 127.0.0.1:6380> slaveof 127.0.0.1 6379 OK 3、啟動6381的redis服務器,設置為6379的從 redis-server --port 6381 tarena@tedu:~$ redis-cli -p 6381 127.0.0.1:6381> slaveof 127.0.0.1 6379
**2、**安裝并搭建sentinel哨兵
# 1、安裝redis-sentinel sudo apt install redis-sentinel 驗證: sudo /etc/init.d/redis-sentinel stop # 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 #4、將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> #如果master有密碼,則需要添加該配置 sentinel auth-pass <master-name> <password> #master多久失聯才認為是不可用了,默認是30秒 sentinel down-after-milliseconds <master-name> <milliseconds>
python獲取master
from redis.sentinel import Sentinel #生成哨兵連接 sentinel = Sentinel([('localhost', 26379)], socket_timeout=0.1) #初始化master連接 master = sentinel.master_for('tedu', socket_timeout=0.1, db=1) slave = sentinel.slave_for('tedu',socket_timeout=0.1, db=1) #使用redis相關命令 master.set('mymaster', 'yes') print(slave.get('mymaster'))
感謝各位的閱讀,以上就是“python操作redis事務的方法”的內容了,經過本文的學習后,相信大家對python操作redis事務的方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。