溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

python操作redis事務的方法

發(fā)布時間:2022-03-29 15:47:32 來源:億速云 閱讀:316 作者:iii 欄目:互聯(lián)網(wǎng)科技

這篇文章主要講解了“python操作redis事務的方法”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“python操作redis事務的方法”吧!

五大數(shù)據(jù)類型及應用場景

類型特點使用場景
string簡單key-value類型,value可為字符串和數(shù)字常規(guī)計數(shù)(微博數(shù), 粉絲數(shù)等功能)
hash是一個string類型的field和value的映射表,hash特別適合用于存儲對象存儲部分可能需要變更的數(shù)據(jù)(比如用戶信息)
list有序可重復列表消息隊列等
set無序不可重復列表存儲并計算關系(如微博,關注人或粉絲存放在集合,可通過交集、并集、差集等操作實現(xiàn)如共同關注、共同喜好等功能)
sorted set每個元素帶有分值的集合各種排行榜

事務

特點

1. 單獨的隔離操作:事務中的所有命令會被序列化、按順序執(zhí)行,在執(zhí)行的過程中不會被其他客戶端發(fā)送來的命令打斷
2. 不保證原子性:redis中的一個事務中如果存在命令執(zhí)行失敗,那么其他命令依然會被執(zhí)行,沒有回滾機制

事務命令

1、MULTI  # 開啟事務          mysql   begin
2、命令1  # 執(zhí)行命令          
3、命令2 ... ...
4、EXEC  # 提交到數(shù)據(jù)庫執(zhí)行    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
# 提交到數(shù)據(jù)庫執(zhí)行
127.0.0.1:6379> EXEC
1) (integer) 1
2) (integer) 1

事務中命令錯誤處理

# 1、命令語法錯誤,命令入隊失敗,直接自動discard退出這個事務
  這個在命令在執(zhí)行調用之前會發(fā)生錯誤。例如,這個命令可能有語法錯誤(錯誤的參數(shù)數(shù)量,錯誤的命令名)
  處理方案:語法錯誤則自動執(zhí)行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、命令語法沒錯,但類型操作有誤,則事務執(zhí)行調用之后失敗,無法進行事務回滾
   我們執(zhí)行了一個由于錯誤的value的key操作(例如對著String類型的value施行了List命令操作) 
   處理方案:發(fā)生在EXEC之后的是沒有特殊方式去處理的:即使某些命令在事務中失敗,其他命令都將會被執(zhí)行。

案例
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 流水線

定義:批量執(zhí)行redis命令,減少通信io

注意:此為客戶端技術

示例

import redis
# 創(chuàng)建連接池并連接到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()

性能對比

# 創(chuàng)建連接池并連接到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()

watch - 樂觀鎖

作用: 事務過程中,可對指定key進行監(jiān)聽,命令提交時,若被監(jiān)聽key對應的值未被修改時,事務方可提交成功,否則失敗

> watch books
OK
> multi
OK
> incr books
QUEUED
> exec  # 事務執(zhí)行失敗
(nil)


watch之后,再開一個終端進入redis
> incr books  # 修改book值
(integer) 1

python操作watch

#同時對一個賬戶進行操作, 當前余額 * 2

數(shù)據(jù)持久化

持久化定義

將數(shù)據(jù)從掉電易失的內存放到永久存儲的設備上

為什么需要持久化

因為所有的數(shù)據(jù)都在內存上,所以必須得持久化

RDB模式(默認開啟)

1、保存真實的數(shù)據(jù)
2、將服務器包含的所有數(shù)據(jù)庫數(shù)據(jù)以二進制文件的形式保存到硬盤里面
3、默認文件名 :/var/lib/redis/dump.rdb

創(chuàng)建rdb文件的兩種方式

**方式一:**redis終端中使用SAVE或者BGSAVE命令

127.0.0.1:6379> SAVE
OK
# 特點
1、執(zhí)行SAVE命令過程中,redis服務器將被阻塞,無法處理客戶端發(fā)送的命令請求,在SAVE命令執(zhí)行完畢后,服務器才會重新開始處理客戶端發(fā)送的命令請求
2、如果RDB文件已經(jīng)存在,那么服務器將自動使用新的RDB文件代替舊的RDB文件
# 工作中定時持久化保存一個文件

127.0.0.1:6379> BGSAVE
Background saving started
# 執(zhí)行過程如下
1、客戶端 發(fā)送 BGSAVE 給服務器
2、服務器馬上返回 Background saving started 給客戶端
3、服務器 fork() 子進程做這件事情
4、服務器繼續(xù)提供服務
5、子進程創(chuàng)建完RDB文件后再告知Redis服務器

# 配置文件相關
/etc/redis/redis.conf
263行: dir /var/lib/redis # 表示rdb文件存放路徑
253行: dbfilename dump.rdb  # 文件名

# 兩個命令比較
SAVE比BGSAVE快,因為需要創(chuàng)建子進程,消耗額外的內存

# 補充:可以通過查看日志文件來查看redis都做了哪些操作
# 日志文件:配置文件中搜索 logfile
logfile /var/log/redis/redis-server.log

方式二:設置配置文件條件滿足時自動保存(使用最多)

# redis配置文件默認
218行: save 900 1
219行: save 300 10
    表示如果距離上一次創(chuàng)建RDB文件已經(jīng)過去了300秒,并且服務器的所有數(shù)據(jù)庫總共已經(jīng)發(fā)生了不少于10次修改,那么自動執(zhí)行BGSAVE命令
220行: save 60 10000
  1、只要三個條件中的任意一個被滿足時,服務器就會自動執(zhí)行BGSAVE
  2、每次創(chuàng)建RDB文件之后,服務器為實現(xiàn)自動持久化而設置的時間計數(shù)器和次數(shù)計數(shù)器就會被清零,并重新開始計數(shù),所以多個保存條件的效果不會疊加
    
# 該配置項也可以在命令行執(zhí)行 [不推薦] 
redis>save 60 10000

RDB缺點

1、創(chuàng)建RDB文件需要將服務器所有的數(shù)據(jù)庫的數(shù)據(jù)都保存起來,這是一個非常消耗資源和時間的操作,所以服務器需要隔一段時間才創(chuàng)建一個新的RDB文件,也就是說,創(chuàng)建RDB文件不能執(zhí)行的過于頻繁,否則會嚴重影響服務器的性能
2、可能丟失數(shù)據(jù)

AOF(AppendOnlyFile)

1、存儲的是命令,而不是真實數(shù)據(jù)
2、默認不開啟
# 開啟方式(修改配置文件)
1、/etc/redis/redis.conf
  672行: appendonly yes # 把 no 改為 yes
  676行: appendfilename "appendonly.aof"
2、重啟服務
  sudo /etc/init.d/redis-server restart

AOF持久化原理及優(yōu)點

# 原理
   1、每當有修改數(shù)據(jù)庫的命令被執(zhí)行時, 
   2、因為AOF文件里面存儲了服務器執(zhí)行過的所有數(shù)據(jù)庫修改的命令,所以給定一個AOF文件,服務器只要重新執(zhí)行一遍AOF文件里面包含的所有命令,就可以達到還原數(shù)據(jù)庫的目的

# 優(yōu)點
  用戶可以根據(jù)自己的需要對AOF持久化進行調整,讓Redis在遭遇意外停機時不丟失任何數(shù)據(jù),或者只丟失一秒鐘的數(shù)據(jù),這比RDB持久化丟失的數(shù)據(jù)要少的多

特殊說明

# 因為
  雖然服務器執(zhí)行一個修改數(shù)據(jù)庫的命令,就會把執(zhí)行的命令寫入到AOF文件,但這并不意味著AOF文件持久化不會丟失任何數(shù)據(jù),在目前常見的操作系統(tǒng)中,執(zhí)行系統(tǒng)調用write函數(shù),將一些內容寫入到某個文件里面時,為了提高效率,系統(tǒng)通常不會直接將內容寫入硬盤里面,而是將內容放入一個內存緩存區(qū)(buffer)里面,等到緩沖區(qū)被填滿時才將存儲在緩沖區(qū)里面的內容真正寫入到硬盤里

# 所以
  1、AOF持久化:當一條命令真正的被寫入到硬盤里面時,這條命令才不會因為停機而意外丟失
  2、AOF持久化在遭遇停機時丟失命令的數(shù)量,取決于命令被寫入到硬盤的時間
  3、越早將命令寫入到硬盤,發(fā)生意外停機時丟失的數(shù)據(jù)就越少,反之亦然

策略 - 配置文件

# 打開配置文件:/etc/redis/redis.conf,找到相關策略如下
1、701行: alwarys
   服務器每寫入一條命令,就將緩沖區(qū)里面的命令寫入到硬盤里面,服務器就算意外停機,也不會丟失任何已經(jīng)成功執(zhí)行的命令數(shù)據(jù)
2、702行: everysec(# 默認)
   服務器每一秒將緩沖區(qū)里面的命令寫入到硬盤里面,這種模式下,服務器即使遭遇意外停機,最多只丟失1秒的數(shù)據(jù)
3、703行: no
   服務器不主動將命令寫入硬盤,由操作系統(tǒng)決定何時將緩沖區(qū)里面的命令寫入到硬盤里面,丟失命令數(shù)量不確定

# 運行速度比較
always:速度慢
everysec和no都很快,默認值為everysec

AOF重寫

思考:AOF文件中是否會產(chǎn)生很多的冗余命令?

為了讓AOF文件的大小控制在合理范圍,避免胡亂增長,redis提供了AOF重寫功能,通過這個功能,服務器可以產(chǎn)生一個新的AOF文件
  -- 新的AOF文件記錄的數(shù)據(jù)庫數(shù)據(jù)和原由的AOF文件記錄的數(shù)據(jù)庫數(shù)據(jù)完全一樣
  -- 新的AOF文件會使用盡可能少的命令來記錄數(shù)據(jù)庫數(shù)據(jù),因此新的AOF文件的提及通常會小很多
  -- AOF重寫期間,服務器不會被阻塞,可以正常處理客戶端發(fā)送的命令請求

示例

原有AOF文件重寫后的AOF文件
select 0SELECT 0
sadd myset peiqiSADD myset peiqi qiaozhi danni lingyang
sadd myset qiaozhiSET msg ‘hello tarena’
sadd myset danniRPUSH 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重寫-觸發(fā)

1、客戶端向服務器發(fā)送BGREWRITEAOF命令
   127.0.0.1:6379> BGREWRITEAOF
   Background append only file rewriting started

2、修改配置文件讓服務器自動執(zhí)行BGREWRITEAOF命令
  auto-aof-rewrite-percentage 100
  auto-aof-rewrite-min-size 64mb
  # 解釋
    1、只有當AOF文件的增量大于100%時才進行重寫,也就是大一倍的時候才觸發(fā)
        # 第一次重寫新增:64M
        # 第二次重寫新增:128M
        # 第三次重寫新增:256M(新增128M)

RDB和AOF持久化對比

RDB持久化AOF持久化
全量備份,一次保存整個數(shù)據(jù)庫增量備份,一次保存一個修改數(shù)據(jù)庫的命令
保存的間隔較長保存的間隔默認為一秒鐘
數(shù)據(jù)還原速度快數(shù)據(jù)還原速度一般,冗余命令多,還原速度慢
執(zhí)行SAVE命令時會阻塞服務器,但手動或者自動觸發(fā)的BGSAVE不會阻塞服務器無論是平時還是進行AOF重寫時,都不會阻塞服務器


# 用redis用來存儲真正數(shù)據(jù),每一條都不能丟失,都要用always,有的做緩存,有的保存真數(shù)據(jù),我可以開多個redis服務,不同業(yè)務使用不同的持久化,新浪每個服務器上有4個redis服務,整個業(yè)務中有上千個redis服務,分不同的業(yè)務,每個持久化的級別都是不一樣的。

數(shù)據(jù)恢復(無需手動操作)

既有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持久化-自動觸發(fā)(條件)
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重寫觸發(fā)
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/下存放服務啟動文件

Redis主從復制

  • 定義

1、一個Redis服務可以有多個該服務的復制品,這個Redis服務成為master,其他復制品成為slaves
2、master會一直將自己的數(shù)據(jù)更新同步給slaves,保持主從同步
3、只有master可以執(zhí)行寫命令,slave只能執(zhí)行讀命令
  • 作用

分擔了讀的壓力(高并發(fā))
  • 原理

從服務器執(zhí)行客戶端發(fā)送的讀命令,比如GET、LRANGE、SMEMMBERS、HGET、ZRANGE等等,客戶端可以連接slaves執(zhí)行讀請求,來降低master的讀壓力
  • 實現(xiàn)方式

    • 方式一(Linux命令行實現(xiàn))

      redis-server --slaveof --masterauth

      # 從服務端
      redis-server --port 6300 --slaveof 127.0.0.1 6379
      # 從客戶端
      redis-cli -p 6300
      127.0.0.1:6300> keys * 
      # 發(fā)現(xiàn)是復制了原6379端口的redis中數(shù)據(jù)
      127.0.0.1:6300> set mykey 123
      (error) READONLY You can't write against a read only slave.
      127.0.0.1:6300> 
      # 從服務器只能讀數(shù)據(jù),不能寫數(shù)據(jù)


    • 方式二(Redis命令行實現(xiàn))

      # 兩條命令
      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下線,寫請求無法執(zhí)行
4、其中一臺Slave使用SLAVEOF no one命令成為Master,其他Slaves執(zhí)行SLAVEOF命令指向這個新的Master,從它這里同步數(shù)據(jù)
# 以上過程是手動的,能夠實現(xiàn)自動,這就需要Sentinel哨兵,實現(xiàn)故障轉移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
# 這是手動操作,效率低,而且需要時間,有沒有自動的???

Sentinel哨兵

Redis之哨兵 - sentinel

1、Sentinel會不斷檢查Master和Slaves是否正常
2、每一個Sentinel可以監(jiān)控任意多個Master和該Master下的Slaves

案例演示

**1、**環(huán)境搭建

# 共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
# 發(fā)現(xiàn)提升6381為master,其他兩個為從
# 在6381上設置新值,6380查看
127.0.0.1:6381> set name tedu
OK

# 啟動6379,觀察日志,發(fā)現(xiàn)變?yōu)榱?381的從
主從+哨兵基本就夠用了

sentinel.conf解釋

# sentinel監(jiān)聽端口,默認是26379,可以修改
port 26379
# 告訴sentinel去監(jiān)聽地址為ip:port的一個master,這里的master-name可以自定義,quorum是一個數(shù)字,指明當有多少個sentinel認為一個master失效時,master才算真正失效
sentinel monitor <master-name> <ip> <redis-port> <quorum>

#如果master有密碼,則需要添加該配置
sentinel auth-pass <master-name> <password>

#master多久失聯(lián)才認為是不可用了,默認是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事務的方法”的內容了,經(jīng)過本文的學習后,相信大家對python操作redis事務的方法這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI