解鎖Redis不一樣的知識

1. Redis基本操作

① 安裝Redis

② 啓動Redis

③ 配置Redis

# 找到自己redis配置文件,然後修改這個配置文件
[root@master redis]# vim redis.conf
protected-mode yes    # 打開保護模式
port 6380                          # 生產環境中端口不要使用默認的6379,使用其它端口,如6380等。
requirepass xxx        	  # 找到requirepass,設置redis的啓動密碼,xxx是自定義的密碼
bind 0.0.0.0                      # 如果想讓外部計算機也連接redis,可以設置綁定的ip。

設置好配置文件後要指定這個配置文件啓動redis:

[root@master redis]# redis-server redis.conf 
27615:C 10 Oct 2019 08:39:39.974 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
27615:C 10 Oct 2019 08:39:39.974 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=27615, just started
27615:C 10 Oct 2019 08:39:39.974 # Configuration loaded

[root@master redis]# ps -ef |grep redis
root     27616     1  0 08:39 ?        00:00:00 redis-server 0.0.0.0:6380
root     27659 26530  0 08:40 pts/0    00:00:00 grep --color=auto redis

# 注意如果redis可以在多個端口開啓多個進程 ,只需按不同的配置文件(配置不同的端口)啓動即可
[root@master redis]# ps -ef |grep redis
root     27616     1  0 08:39 ?        00:00:00 redis-server 0.0.0.0:6380
root     28016     1  0 08:46 ?        00:00:00 redis-server 0.0.0.0:6390
root     28029 26530  0 08:46 pts/0    00:00:00 grep --color=auto redis

如果你的redis在本地,使用客戶端命令連接redis的時候,只需要指定端口。如果你的redis在服務器中,打開客戶端的時候記得要指定端口指定主機地址:

thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136
106.12.115.136:6380> 

如果你開始操作數據庫,這個時候redis會要求讓你輸入啓動密碼:

thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136
106.12.115.136:6380> set username thanlon  
(error) NOAUTH Authentication required.
106.12.115.136:6380> auth redis   		# 密碼錯誤
(error) ERR invalid password
106.12.115.136:6380> auth redis       # 密碼正確
OK

# 也可以在連接redis服務端的時候指定redis啓動密碼,使用-a參數。但是,不建議,因爲直接暴露了密碼,redis也會提示你這樣可能是不安全的。
thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136 -a redis
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
106.12.115.136:6380> 

關閉redisk可以直接殺死進程,但這樣可能會造成數據丟失。建議使用客戶端發起關閉redis服務的,着屬於正常關閉redis,可以數據的安全:

# 設置了啓動密碼,所以被拒絕關閉
thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136 shutdown
(error) NOAUTH Authentication required.
# 我們帶上密碼來關閉,這樣就成功關閉了
thanlon@plus-book:~$ redis-cli -p 6380 -h 106.12.115.136 -a redis shutdown
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
thanlon@plus-book:~$ 
# 再到服務器確定關閉與否(redis已經被成功關閉)
[root@master ~]# ps -ef |grep redis
root     28786 28722  0 08:57 pts/1    00:00:00 grep --color=auto redis
2. Redis主從複製
  • redis集羣中數據庫的複製是通過主從同步來實現的
  • 主節點(Master)把數據分發給從節點(Slave)
  • 主從同步的好處在於高可用,redis節點有冗餘設計

在這裏插入圖片描述

準備兩臺機器,我這裏使用的是VMware虛擬化兩臺cetnos機器,ip分別是10.0.0.2和10.0.0.3,跟別作爲主、從數據庫。就使用這兩臺機器來做redis的主從同步。另外,爲了方便使用,我使用XShell軟件來連接我的這兩臺linux機器。

① 爲兩天機器安裝redis,上文有介紹,在這裏不贅述:https://blog.csdn.net/Thanlon/article/details/100941385#41_redis_548

② 配置主(Master)數據庫的配置文件

# 查看配置文件有用的信息行
[root@slave redis]# grep -v '#|^$' /usr/local/redis/redis.conf
# 編輯配置文件
[root@master redis]# vim redis.conf
# 修改下面幾行爲
bind 10.0.0.2      # 綁定本機的ip地址。外網情況下,不要綁定端口,直接bind 0.0.0.0
daemonize yes      # 設置後臺進程方式運行
requirepass redis  # 爲主redis設置密碼
# 查看redis是否設置密碼
10.0.0.2:6379> config get requirepass
1) "requirepass" # 關鍵字 
2) "redis"    	 # 密碼
# 可以更改密碼
10.0.0.2:6379> config set requirepass "redis"
OK
# 指定此配置文件啓動redis
[root@master redis]# redis-server redis.conf

③ 配置從(Slave)數據庫的配置文件

# 查看配置文件有用的信息行
[root@slave redis]# grep -v '#|^$' /usr/local/redis/redis.conf
# 編輯從數據庫配置文件
[root@master redis]# vim redis.conf
# 修改下面幾行爲
bind 10.0.0.3             # 綁定本機的ip地址。外網情況下,不要綁定端口,直接bind 0.0.0.0
replicaof 10.0.0.2 6379   # Master的ip和端口
masterauth redis          # Master的密碼
# 指定此配置文件啓動redis
[root@slave redis]# redis-server redis.conf

④ 主從同步的驗證

  • 主服務器的操作
# 登錄主redis
[root@master redis]# redis-cli -h 10.0.0.2
# 輸入主redis密碼
10.0.0.2:6379> auth redis
OK
# 向主redis中添加數據
10.0.0.2:6379> set username thanlon
OK
# 查看主redis中的已經添加的數據
10.0.0.2:6379> keys *
1) "username"
  • 從服務器的操作
# 登錄從redis
[root@slave redis]# redis-cli -h 10.0.0.3
# 查看從redis的數據(從redis中一開始沒有數據)
10.0.0.3:6379> keys *
1) "username"
# 如果操作(例如刪除)從主redis中同步的數據,就會提示數據是隻讀的
10.0.0.3:6379> del username
(error) READONLY You can't write against a read only replica.

注意:如果兩個redis鏈接不成功,要排查redis是不是同一個版本、是不是都是源碼安裝或yum安裝的。

3. Redis多實例配置

redis支持多實例的用法,也就是一個服務器可以運行多個redis服務端。我們這裏把只用Master一臺服務器就可以了。

# 查看redis下的文件(redis.conf是從源碼包中拷貝過來的)
[root@master redis]# ls
bin  dump.rdb  redis.conf
# 修改該配置文件
[root@master redis]# mv redis.conf redis-6379.conf
# 將該配置文件備份(備份與否都可以,此步可忽略)
[root@master redis]# cp redis-6379.conf redis-6379.conf.bak
# 再複製一個redis-6379.conf並命名爲redis-6380.conf作爲另一個實例
[root@master redis]# cp redis-6379.conf redis-6380.conf 
# 修改redis-6379.conf配置文件中的參數
bind 10.0.0.2
port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
# 修改redis-6380.conf配置文件中的參數
bind 10.0.0.2
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
# 查看redis的運行狀態
[root@master redis]# ps -ef |grep redis
root       6436      1  0 Oct09 ?        00:00:17 redis-server 10.0.0.2:6379
root       6485      1  0 00:55 ?        00:00:00 redis-server 10.0.0.2:6380
root       6498   6402  0 00:56 pts/1    00:00:00 grep --color=auto redis

PS:上面的操作表示兩個redis實例的配置已經完成,下面我們將這兩個實例做主從同步

# 修改“從數據庫”的配置文件redis_6379.conf
[root@master redis]# vim redis-6379.conf 
# 找到replicaof參數修改如下,表示從10.0.0.26379端口同步
replicaof 10.0.0.2 6379
# 開始兩個實例服務
[root@master redis]# redis-server redis-6379.conf
[root@master redis]# redis-server redis-6380.conf
# 客戶端連接這兩個端口的redis服務
[root@master redis]# redis-cli -p 6379 -h 10.0.0.2
[root@master redis]# redis-cli -p 6380 -h 10.0.0.2
# 6379端口所在的redis客戶端進行添加數據操作
10.0.0.2:6379> set username thanlon
OK
# 查看6380端口所在的redis客戶端的數據,至此配置成功
10.0.0.2:6380> keys *
1) "username"
4. Python連接Redis

第一種方式使用的是普通的連接:

# -*- coding: utf-8 -*-
import redis

conn = redis.Redis(host='106.12.115.133', port=6379,password='xxx')
conn.set('name', 'kiku')
print(conn.get('name'))

第二種方式使用的是連接池連接(與線程池是一樣的,可以防止重複的連接節省開銷,建議使用這種方式):

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.133', port=6379, max_connections=1000,password='xxx')  # max_connections最大連接數
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
5. Python操作Redis

① String操作
redis中的String在內存中按照一個name對應一個value來存儲

  • set(name, value, ex=None, px=None, nx=False, xx=False):在redis中設置值,默認不存在則創建存在則修改
ex:過期時間()
px:過期時間(毫秒)
nx:如果設置爲True,只有name不存在時,當前set操作才執行(添加)
xx:如果設置爲True,只有name存在時,當前set才執行操作(修改)
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.get('name'))  # b'thanlon'
  • setnx(name,value):設置值,只有name不存在時,執行設置操作
  • setex(name,value,time):設置值,time是過期時間(數字秒或timedelta對象)
  • psetex(name,time_ms,value):設置值,time_ms是過期時間(數字秒或timedelta對象)
  • mset(*args,**keargs):批量設置值,如:
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.mset({'name':'thanlon','age':23})
  • get(name):獲取值
  • mget(keys,*args):批量獲取值,如:
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.mget('name', 'age'))  # [b'thanlon', b'23']
print(conn.mget(['name', 'age']))  # 與上一行等價
  • getset(name,value):設置新值並獲取原來的值
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.getset('name', 'kiku'))  # b'thanlon'
  • getrange(key,start,end):獲取子序列(根據字節獲取,非字符),start表示起始位置(字節);end表示結束位置(字節)。Python2中代表的是字符。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.getrange('name', 0, 2))  # 三個字符:b'kik'
conn.set('name', '奈何先生')
print(conn.getrange('name', 0, 2))  # 以中文字節形式獲取中文呢:b'\xe5\xa5\x88'
  • setrange(name,offset,value):修改字符串內容,從指定字符串索引開始後替換(新值太長時,則向後添加)。offset表示字符串索引,字節(一個漢字三個字節);value是要設置的值。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
print(conn.get('name'))
conn.setrange('name', 7, 'kiku')  #
print(conn.get('name'))  # b'thanlonkiku'
  • setbit(name,offset,value):對name對應的值的二進制表示的位進行操作,修改二進制位。name是redis中的name,offseet是位的索引(將值變換成二進制後再進行索引),value的值只能是1或0。
  • getbit(name,offset):獲取name對應的值的二進制表示中的某位的值,可用來判斷獲取的是0還是1
  • bitcount(key,start=None,end=None):獲取二進制數中有多少個1
  • bitop(operation,dest,*keys):獲取多個值,並將值作做位運算,將最後的結果保存至新的name對應的值
參數:
operation--------AND(),OR(),NOT(),XOR(異或)
dest---------------新的redisd的name
*keys------------- 要查找的redis的name
例如:獲取n1,n2,n3對應的值,然後將所有的值做位運算(求並集),然後將結果保存在new_name對應的值中
bitop('AND','new_name','n1','n2','n3')
  • strlen(name):返回name對應值的字節長度(一個漢字3個字節)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
print(conn.strlen('name'))
conn.set('name', '奈何先生')  # 一個漢字三個字節
print(conn.strlen('name'))
  • incr(self,name,amount=1):自增,name對應的值,當name不存在時,則創建name=amount,否則則自增。同incrby(self,name,amount=1)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.get('age'))  # b'24'
conn.incr('age')
print(conn.get('age'))  # b'25'
  • decr(self,name,amount=1):自減,name對應的值,當name不存在時,則創建name=amount,否則則自減。同decrby(self,name,amount=1)。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.get('age'))  # b'25'
conn.decr('age')
print(conn.get('age'))  # b'24'
  • incrbyfloat(self,name,amount=1.0):自增,只不過可以自增浮點數,如果amount的值是負的,則表示自減,注意沒有decrbyfloat(self,name,amount=1.0)
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.get('no'))  # None
conn.incrbyfloat('no')
print(conn.get('no'))  # b'1'
conn.incrbyfloat('no', 0.1)
print(conn.get('no'))  # b'1.1'
  • append(key,value):在name對應的值後面追加內容
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.set('name', 'thanlon')
print(conn.get('name'))  # b'thanlon'
conn.append('name', ' love kiku')
print(conn.get('name'))  # b'thanlon love kiku'

② hash操作
redis中的hash類型可以看成具有String key和String Value的map容器。所以,該類型非常適合於存儲值對象的信息,如:username,password,age,sex等。我們可以使用redis的hash來存儲session。

  • hset(name,key,value):name對應的hash中設置一個鍵值對,參數name是redis的name,key是name對應的hash中的key,value是name對應的hash中的value。hsetnx(name,key,value)表示當name對應的hash中不存在當前key時則創建(相當於添加)
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hset('admin','name','thanlon')
conn.hset('admin','age',23)
  • hmset(name,mapping):在name對應的hash中批量設置鍵值對
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.hmset('admin', {'name': 'thanlon', 'age': 23, 'sex': '男'})
  • hget(name,key):在name對應的hash中獲取key的值value
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.hset('admin','name','thanlon')
conn.hset('admin','age',23)
print(conn.hget('admin','name'))
print(conn.hget('admin','age'))
  • hmget(name,keys,*args):在name對應hash中獲取多個key的值value
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hmset('admin', {'name': 'thanlon', 'age': 23, 'sex': '男'})
print(conn.hmget('admin', 'name', 'age', 'sex'))  # [b'thanlon', b'23', b'\xe7\x94\xb7']
  • hgetall(name):獲取name對應的hash的所有鍵值,以字典類型返回
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hgetall('admin'))  # {b'name': b'thanlon', b'age': b'23', b'sex': b'\xe7\x94\xb7'}
  • hlen(name):獲取name對應的hash中鍵值對的個數
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hlen('admin'))  # 3
  • hkeys(name):獲取name對應的hash中所有key的值,列表形式返回
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hkeys('admin'))  # [b'name', b'age', b'sex']
  • hvals(name):獲取name對應的hash中所有value值
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hvals('admin'))#[b'thanlon', b'23', b'\xe7\x94\xb7']
  • hexits(name,key):檢查name對應的hash是否存在當前輸入的key
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hexists('admin', 'age'))  # True
  • hdel(name,*keys):將name對應的hash中的指定key的鍵值對刪除
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
print(conn.hdel('admin', 'sex', 'age'))  # 2
  • hincrby(name,key,amount=1):自增name對應的hash值中的指定key值,不存在則創建key=mount
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hincrby('admin',1,amount=2)
print(conn.hget('admin', 1))  # b'2'
  • hincrbyfloat(name,key,amount=1.0):
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
conn.hincrbyfloat('admin', 2, amount=0.1)
print(conn.hget('admin', 2))  # b'1.1'
  • hscan(name,cursor=0,match=None,count=None):增量式迭代獲取,對於數據大的數據非常有用。hscan可以實現分片地獲取數據,並非一次性將數據全部獲取完放置內存被撐爆。name是redis中的name,cursor是遊標(基於遊標分批獲取數據),match是匹配指定的key,默認None,表示所有key,count是每次分片最少獲取的個數,默認是None表示採用redis的默認分片個數。如:
# 第一次:
cursor1,data1 = conn.hscan('xxx',cursor=0,match=None,count=None)
# 第二次:
cursor2,data2 = conn.hscan('xxx',cursor=cursor1,match=None,count=None)
……
直到返回值cursor的值爲0時,表示數據已經通過分片獲取完畢。
  • hscan_iter(name,match=None,count=None):利用yield封裝hscan創建生成器,實現分批去redis中獲取數據
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.101', port=6379, password='xxx')
conn = redis.Redis(connection_pool=pool)
for item in conn.hscan_iter('admin'):
    print(item)
# (b'name', b'thanlon')
# (b'sex', b'man')
# (b'age', b'23')

③ List操作

  • lpush(name,values):在name對應的list中添加元素,每個新的元素添加到列表的最左邊
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('names', 'thanlon')
conn.lpush('names', 'kiku')
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
  • lpushx(name,value):在name對應的list中添加元素,只有name存在時,值添加到列表的最左邊
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpushx('names', '奈何先生')
  • llen(name):name對應的list元素的個數
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
print(conn.llen('names'))  # 2
  • linsert(name,where,refvalue,value):在name對應的列表的某一個值前或後插入一個新值。where只能寫兩個值一個是BEFORE,一個是AFTER。refvalue是標杆值,即:在它的前後插入數據,value是要插入的數據。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
conn.linsert('names', 'after', 'thanlon', 'john')
conn.linsert('names', 'before', 'thanlon', 'Tom')
print(conn.lrange('names', 0, -1))  # [b'kiku',b'Tom', b'thanlon', b'john']
  • lset(name,index,value):對name對應的list中某一個索引位置重新賦值,index是list的索引位置,value是要設置的值。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
conn.lset('names', 0, 'Tom')
print(conn.lrange('names', 0, -1))  # [b'Tom', b'john']
  • lrem(name,count,value):在name對應的list中刪除指定的值,count=0表示刪除列表中所有指定的值,count=2表示從前到後刪除2個,count=-2表示從後向前刪除2個。
# -*- coding: utf-8 -*-
# 刪除所有指定的“Tom”
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'Tom', b'Tom', b'Thanlon', b'kiku', b'john']
conn.lrem('names', 0, 'Tom')  # 刪除所有的Tom
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku', b'john']
# 從前到後刪除2個“Tom”
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'Tom', b'Tom', b'Thanlon', b'kiku', b'john', b'Tom']
conn.lrem('names', 2, 'Tom')
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku', b'john', b'Tom']
  • lpop(name):在name對應的列表的最左側獲取第一個元素並刪除,返回值則是第一個元素。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lpop('names'))  # b'kiku'
  • lindex(name,index):在name對應的列表中根據索引獲取列表中的元素
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lindex('names', 0))  # b'kiku'
print(conn.lindex('names', 1))  # b'thanlon'
  • lrange(name,start,end):在name對應的列表分片獲取數據。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'kiku', b'thanlon']
  • ltrim(name,start,end):在name對應的列表中移除沒有在start~end索引之間的值。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku', b'john', b'Tom']
conn.ltrim('names', 0, 1)  # 0~1
print(conn.lrange('names', 0, -1))  # [b'Thanlon', b'kiku']
  • rpoplpush(src,dst):從一個列表取出最右邊的元素,同時將其添加至另外一個列表的最左邊,src是要取數據的列表的name,dst是要添加數據列表name。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('developers', 'Thanlon')
conn.lpush('developers', 'Kiku')
conn.lpush('masters', 'John')
conn.lpush('masters', 'Maria')
print(conn.lrange('developers', 0, -1))  # [b'Kiku', b'Thanlon']
print(conn.lrange('masters', 0, -1))  # [ b'Maria', b'John']
conn.rpoplpush('developers', 'masters')  # 將developers列表中的最右邊元素添加到masters列表中元素的最左邊
print(conn.lrange('developers', 0, -1))  # [b'Kiku']
print(conn.lrange('masters', 0, -1))  # [b'Thanlon', b'Maria', b'John']
  • blpop(keys,timeout):將多個值進行排列,按照從左到右去pop對應列表的元素。timeout是超時時間,當元素所有列表的數據獲取完後,阻塞等待列表內有數據的時間(秒),0表示永遠阻塞。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('names', 'Thanlon')
conn.lpush('names', 'Kiku')
conn.lpush('names', 'John')
conn.lpush('names', 'Maria')
print(conn.lrange('names', 0, -1))  # [b'Maria', b'John', b'Kiku', b'Thanlon']
print(conn.blpop('names'))  # (b'names', b'Maria')
print(conn.lrange('names', 0, -1))  # [b'John', b'Kiku', b'Thanlon']
print(conn.blpop('names'))  # (b'names', b'John')
print(conn.lrange('names', 0, -1))  # [b'Kiku', b'Thanlon']
  • brpoplpush(src,dst,timeout=0):從一個列表取出最右邊的元素,同時將其添加至另外一個列表的最左邊。前面有介紹rpoplpush方法,這裏只是可以添加超時時間。
  • 自定義增量迭代:**由於redis類庫中沒有提供對列表元素的增量迭代,如果想要循環name對應的列表的所有元素,就需要獲取name對應的列表,然後循環列表。但是如果列表非常大,就有可能在獲取name對應的列表時撐爆內存,所以,有必要自定義增量迭代功能。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)

def list_iter(name):
    list_count = conn.llen(name)
    for index in range(0, list_count):
        yield conn.lindex(name, index)

for item in list_iter('names'):
    print(item)
# b'Kiku'
# b'Thanlon'

④ Set操作:Set集合不允許重複的列表

  • sadd(name,values):對name對應的集合添加元素
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.sadd('employees', 'thanlon')
conn.sadd('employees', 'kiku')
  • scard(name):獲取name對應集合中的元素個數
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.scard('employees'))
  • sadiff(keys,*args):在第一個name對應的集合中且不在其它name對應的集合中的元素集合
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# employees:kiku,thanlon
# bosses:Tom,John
print(conn.sdiff('employees', 'bosses'))  # {b'kiku', b'thanlon'}
  • sdiffstore(dest,keys,*args):獲取在第一個name對應的集合中且不在其它name對應的集合中的元素集合,再將其新加入到dest對應的集合中。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# employees:kiku,thanlon
# bosses:Tom,John
print(conn.sdiffstore('dest', 'employees', 'bosses'))  # dest:{b'kiku', b'thanlon'}
  • sinter(keys,*args):獲取多個name對應集合的交集。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Thanlon', b'Tom'}
print(conn.sinter('employees', 'bosses'))  # {b'Tom'}
  • sinterstore(dest,keys,*args):獲取多一個name對應集合的交集,再將其加入到dest對應的集合中
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Thanlon', b'Tom'}
conn.sinterstore('dest', 'employees', 'bosses')
print(conn.smembers('dest'))  # {b'Tom'}
  • sismember(name,value):檢查value是否是name對應的集合成員。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'thanlon', b'kiku'}
print(conn.sismember('employees', 'thanlon'))  # True
  • smembers(name):獲取name對應集合的所有成員。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'kiku', b'thanlon'}
  • smove(src,dst,value):把某一個成員從一個集合(src)中移到另外一個集合(dst)中。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Thanlon', b'Kiku'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
conn.smove('employees', 'bosses', 'Thanlon')
print(conn.smembers('employees'))  # {b'Thanlon', b'Kiku'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
  • spop(name):從集合的右側(尾部)移除一個成員,並將其返回
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('bosses'))  # {b'John', b'Thanlon', b'Tom'}
print(conn.spop('bosses'))  # b'Thanlon'
print(conn.smembers('bosses'))  # {b'Tom', b'John'}
  • srandmember(name,number):從name對應的集合中隨機獲取numbers個元素
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# 如果nmber沒有指定則默認是1
print(conn.srandmember('employees'))  # b'Kiku'
print(conn.srandmember('employees', number=2))  # [b'Kiku', b'Tom']
  • srem(name,values):在name 對應的集合中刪除某些值
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
conn.srem('employees', 'Kiku')
print(conn.smembers('employees'))  # {b'Tom'}
  • sunion(keys,*args):獲取多個name對應集合的並集
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
print(conn.sunion('employees', 'bosses'))  # {b'Kiku', b'John', b'Tom'}
  • sunionstore(dest,keys,*args):獲取多個name對應集合的並集,並將結果保存到dest對應的集合中
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.smembers('employees'))  # {b'Kiku', b'Tom'}
print(conn.smembers('bosses'))  # {b'John', b'Tom'}
print(conn.sunionstore('dest', 'employees', 'bosses'))
print(conn.smembers('dest'))  # {b'Kiku', b'John', b'Tom'}
  • sscan(name,cursor=0,match=None,count=None):同字符串操作,用於迭代分批獲取數據,避免內存消耗太大。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
# 第一次:
cursor1, data1 = conn.sscan('employees', cursor=0, match=None, count=1)
print(data1)  # [b'Thanlon']
# 第二次:
cursor2, data2 = conn.sscan('employees', cursor=cursor1, match=None, count=2)
print(data2)  # [b'John', b'Kiku', b'Tom', b'Maria']
  • sscan_iter(name,match=None,count=None):同字符串操作,用於迭代分批獲取數據,避免內存消耗太大
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
for item in conn.sscan_iter('employees', match=None, count=None):
    print(item)
# b'Thanlon'
# b'John'
# b'Kiku'
# b'Tom'
# b'Maria'

⑤ 有序集合
在集合的基礎上,爲每個元素排序。元素的排序需要根據另外一個值來進行比較,所以對於有序集合,每個元素有兩個值,即值和分數,分數專門用來做排序。

  • zdd(name,mapping,nx,xx,ch,incr):在name對應的有序集合中添加元素(有兩種方式)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('zset1', {'thanlon': 1, 'kiku': 2, 'Tom': 0})
  • zcard(name):獲取name對應的有序集合元素的數量
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'thanlon', b'kiku']
print(conn.zcard('zset1'))  # 3
  • zcount(name,min,max):獲取name對應的有序集合中分數在[min,max]之間的數
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'thanlon', b'kiku']
print(conn.zcount('zset1', 0, 1))  # 2
  • zincrby(name,amount,value):自增name對應的有序集合的name對應的分數
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'thanlon', b'kiku']
conn.zincrby('zset1', 10, 'thanlon')
print(conn.zrange('zset1', 0, -1))  # [b'Tom', b'kiku', b'thanlon']
  • zrange(name,start,end,desc=False,withscores=False,score_cast_func=float):按照索引獲取name對應的有序集合的元素。參數:start是有序集合索引起始位置;end是有序集合索引結束位置 ;desc是排序規則,默認按照從小到大排序;withscores是是否獲取元素的分數,默認是獲取元素的值;score_cast_func是對分數進行數據轉換的函數。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('name', {'Thanlon': 1, 'Kiku': 2, 'Tom': 0, 'Maria': -2})
print(conn.zrange('name', 0, 0))  # [b'Maria']
print(conn.zrange('name', 0, 0, desc=True))  # [b'Kiku']
print(conn.zrange('name', 0, 1))  # [b'Maria', b'Tom'], 0, 1只決定取的數量,不表示分數範圍
  • zrank(name,value):獲取值在name對應的有序集合中的排行(從0開始)
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('name', {'Thanlon': 1, 'Kiku': 2, 'Tom': 0, 'Maria': -2})
print(conn.zrange('name', 0, -1))  # [b'Maria', b'Tom', b'Thanlon', b'Kiku']
print(conn.zrank('name', 'Thanlon'))  # 2,表示排第三位(是從0開始的)
  • zrangebylex(self, name, min, max, start=None, num=None):當有序集合的所有成員都具有相同的分數,有序集合的元素會根據成員的值來進行排序。對集合中的每個成員進行逐個字節的對比,並按照從低到高的順序,返回排序後的集合成員。min是左區間,+和-分別表示正無限和負無限,(或者表示開區間,[表示 閉區間;max是右區間的值;start是對結果進行分片處理的索引位置,num是對結果進行分片處理,索引後面有num個元素。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 100, 'Kiku': 100, 'Maria': 100}) 
#  # 字節轉換成數字來一個一個比較
print(conn.zrange('students', 0, -1)) # [b'Kiku', b'Maria', b'Thanlon']
ret = conn.zrangebylex('students', '-', '[Maria') # [b'Kiku', b'Maria']
ret2 = conn.zrangebylex('students', '-', '(Maria')# [b'Kiku']
print(ret)
print(ret2)
  • zrem(self, name, *values):刪除name對應的有序集合值是value的成員
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 100, 'Kiku': 100, 'Maria': 100})
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria', b'Thanlon']
conn.zrem('students', 'Thanlon')  # 刪除name對應有序集合中的Thanlon
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria']
  • zremrangebyrank(name,min,max):根據排行來刪除
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 0, 'Kiku': 1, 'Maria': 2})
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria', b'Thanlon']
conn.zremrangebyrank('students', 0, 1)  # 刪除排名在第一名到第二名
print(conn.zrange('students', 0, -1))  # [b'Maria']
  • zremrangebyscore(name, min, max):根據分數範圍刪除有序集合中的元素加
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 59, 'Kiku': 100, 'Maria': 100})
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria', b'Thanlon']
# 根據分數來刪除有序集合裏面的值,這裏刪除的是分數在0~59之間的,只有Thanlon是滿足加的,所以刪除它
conn.zremrangebyscore('students', 0, 59)
print(conn.zrange('students', 0, -1))  # [b'Kiku', b'Maria']
  • zremrangebylex(name, min, max):根據指定的範圍的值刪除
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 100, 'Kiku': 100, 'Maria': 100})
#  # 字節轉換成數字來一個一個比較
print(conn.zrange('students', 0, -1, withscores=True))  # [(b'Kiku', 100.0), (b'Maria', 100.0), (b'Thanlon', 100.0)]
conn.zremrangebylex('students', '-', '[Maria')
print(conn.zrange('students', 0, -1, withscores=True))  # [(b'Thanlon', 100.0)]
  • zscore(name, value):根據name對應有序集合中的value對應的分數
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zscore('students', 'Maria'))  # 100.0
  • zinterstore(self, dest, keys, aggregate=None):獲取兩個有序集合的交集,如果遇到相同的值不同的分數,則按照aggregate進行操作,aggregate的值有SUM 、MIN和MAX,默認是SUM。使用小寫sum也對,不區分大小。
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('bosses', 0, -1, withscores=True))  # [(b'Jack', 1.0), (b'Thanlon', 4.0)]
print(conn.zrange('employees', 0, -1, withscores=True))  # [(b'thanlon', 0.0), (b'Jack', 2.0)]
conn.zinterstore('dest', ['bosses', 'employees'])
print(conn.zrange('dest', 0, -1, withscores=True))  # [(b'Jack', 3.0)]
  • zunionstore( dest, keys, aggregate=None):獲取兩個有序集合的並集,如果遇到相同的值不同的分數,則按照aggregate進行操作,aggregate的值有SUM 、MIN和MAX
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.zrange('bosses', 0, -1, withscores=True))  # [(b'Jack', 1.0), (b'Thanlon', 4.0)]
print(conn.zrange('employees', 0, -1, withscores=True))  # [(b'thanlon', 0.0), (b'Jack', 2.0)]
conn.zunionstore('dest', ['bosses', 'employees'])
print(conn.zrange('dest', 0, -1, withscores=True))  # [(b'thanlon', 0.0), (b'Jack', 3.0), (b'Thanlon', 4.0)]
  • zscan(name, cursor=0, match=None, count=None,score_cast_func=float):
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 59, 'Kiku': 100, 'Maria': 100})
cursor1, data1 = conn.zscan('students', cursor=0, match=None, count=None, score_cast_func=float)
print(data1)  # [(b'Thanlon', 59.0), (b'Kiku', 100.0), (b'Maria', 100.0)]
  • scan_iter(name, match=None, count=None,score_cast_func=float):
# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.zadd('students', {'Thanlon': 59, 'Kiku': 100, 'Maria': 100})
for item in conn.zscan_iter('students', score_cast_func=float):
    print(item)
# (b'Thanlon', 59.0)
# (b'Kiku', 100.0)
# (b'Maria', 100.0)

⑥ 其它常用操作

  • delete(*names):刪除redis任意一種數據類型
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.delete('teachers')
  • exists(*names):檢查redis中的name是否存在
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.exists('students'))  # 1表示存在
  • keys(pattern=’*’):默認是所有的keys
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.keys())  # [b'bosses', b'dest_tmp', b'students']
print(conn.keys('bo?ses'))  # [b'bosses']
print(conn.keys('b*s'))  # [b'bosses']
print(conn.keys('b[ao]sses'))  # [b'bosses'],要麼匹配bosses,否則匹配basses
  • expire(name, time):爲某個redis的name設置超時時間,redis中設置超時時間的粒度比較小,只能對name對應的數據的整體做超時時間。比如,hash中一個name對應多個key-value,我們只能對這多個key-value整體設置超時時間,不可以對key-value做超時時間。
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.expire('students', time=100)  # 超時時間必須是integer類型的
  • rename(src, dst):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.keys())  # [b'employees', b'dest_tmp']
conn.rename('employees', 'bosses')
print(conn.keys())  # [b'bosses', b'dest_tmp']
  • move(name, db):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.keys())  # [b'bosses', b'dest_tmp']
conn.move('bosses', 15)
print(conn.keys())  # [b'dest_tmp']
  • randomkey():隨機獲取redis中的name
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.randomkey())#b'dest_tmp'
  • type(name):獲取redis中name的數據類型
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.type('dest_tmp'))  # b'set'
  • scan(cursor=0, match=None, count=None):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
print(conn.scan())  # (0, [b'dest_tmp'])
  • scan_iter(match=None, count=None):
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
for item in conn.scan_iter():
    print(item)
# b'dest_tmp'
6. 管道

管道是用來做事務的,python連接redis在執行每次請求都會創建(連接池申請連接)和斷開(歸還連接池)一次連接操作,如果想要在一次請求中指定多個命令,則可以使用pipline實現一次請求指定多個命令,並且默認情況下一次pipline是原子性操作。

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pipe = conn.pipeline(transaction=True)
pipe.set('name', 'thanlon')
pipe.set('name', 'kiku')
pipe.execute()  # 整體提交,如果一條發生錯誤,整個就不會生效
7. Redis發佈和訂閱

發佈者:

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.publish('news', 'Pay Attention To!')

接收者1:

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pb = conn.pubsub()
pb.subscribe('news')
while True:
    print(pb.parse_response()) # [b'message', b'news', b'Pay Attention To!']

接收者2:

# -*- coding: utf-8 -*-
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pb = conn.pubsub()
pb.subscribe('news')
while True:
    print(pb.parse_response()) # [b'message', b'news', b'Pay Attention To!']
8. Redis面試題
  • redis和memcached的比較:redis不僅支持簡單的k/v類型的數據,同時還提供list,set,hash等數據結構的存儲;memcached不支持主從,redis支持主從,可用於數據的備份,即master-slave模式的數據備份;Redis支持數據的持久化,可以將內存中的數據保持在磁盤中,重啓的時候可以再次加載進行使用。
  • redis中數據庫默認有多少個數據庫及作用:16個數據庫;所有數據庫保存到結構 redisServer 的一個成員 redisServer.db 數組中。當我們選擇數據庫 select number 時,程序直接通過 redisServer.db[number] 來切換數據庫。有時候當程序需要知道自己是在哪個數據庫時,直接讀取 redisDb.id 即可。
  • python如何操作redis模塊:安裝redis模塊(或庫),然後使用redis模塊與redis服務端創建連接之後,進行一系列redis的操作
  • 如何循環顯示redis中某個列表比較大的數據量的每一個值:可以嘗試將對象分拆成幾個key-value, 使用multiGet獲取值,這樣分拆的意義在於分拆單次操作的壓力,將操作壓力平攤到多個redis實例中,降低對單個redis的io影響
  • redis如何實現主從複製和數據同步機制:在從redis數據庫(slave)配置文件中添加replicaof參數用於綁定主庫(master)的ip和端口;在slave啓動時,會向其master發送一條SYNC消息,master收到slave的這條消息之後,將可能啓動後臺進程進行備份,備份完成之後就將備份的數據發送給slave。
  • redis中的sentinel的作用:sentinel是一個獨立運行的進程,用於監控master-slave集羣,一旦發現master宕機,會進行自動切換到slave。[用於監控redis集羣中Master狀態的工具]
  • 如何實現redis集羣:採用主從模式,通過增加slave來增加併發讀的能力,master的寫能力是個瓶頸;還有hash slot的模式,將Redis的寫操作分攤到了多個節點上,提高寫的併發能力,擴容簡單。
  • redis中默認有多少個哈希槽:16384個哈希槽
  • 簡述redis的有哪幾種持久化策略及比較:redis有RDB和AOF兩種持久化策略,RDF相當於快照,保存數據塊,還原數據快,適合災難恢復。但是RDB只要符合要求就會照快照,會佔用一部分系統資源,適用於內存比充足的機器。AOF是持續化佔用極少的內存資源,採用日誌記錄redis操作。但是日誌文件會特別大,不適用於災難恢復,恢復效率遠遠低於RDB。適用於內存較小的機器。[簡單回答:RDF是快照形式的,直接把內存中的數據保存到一個dump文件中;AOF是把所有的對redis的服務器進行修改的命令都存到一個文件裏]
  • 列舉redis支持的過期策略:定期刪除和惰性刪除策略,定期刪除指的是每隔一定時間就抽取一些設置了過期時間的key,檢查是否過期,如果過期了就把刪除。惰性策略是在獲取key的時候,如果此時的key已經過期,就會直接刪除,不會返回任何東西。當然,內存中這還會存大量過期的的key,我們還可以使用內存淘汰機制。
  • 列舉內存淘汰機制
volatile-lru 				從已設置過期時間的數據集中挑選最近最少使用的數據淘汰(默認)
volatile-ttl					從已設置過期時間的數據集中挑選將要過期的數據淘汰
volatile-random 		從已設置過期時間的數據集中任意選擇數據淘汰
allkeys-lru					從數據集中挑選最近最少使用的數據淘汰(最常用的)
allkeys-random		從數據集中任意選擇數據淘汰
no-enviction				禁止驅逐數據
  • mysql裏有兩千萬數據,redis中只存二十萬的數據,如何保證 Redis 中都是熱點數據:redis 內存數據集大小上升到一定大小的時候,就會實施數據淘汰策略。可參考上一題理解着回答。
  • 寫代碼,基於redis的列表實現先進先出、後進先出隊列和優先級隊列
# 先進先出
import redis
'''
可以使用lpush和rpop或rpush和lpop
'''
pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('employees', 'thanlon')
conn.lpush('employees', 'kiku')
conn.lpush('employees', 'maria')
conn.lpush('employees', 'jack')
conn.lpush('employees', 'michael')
conn.lpush('employees', 'angle')
print(conn.lrange('employees', 0, -1))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
print(conn.rpop('employees'))
'''
[b'angle', b'michael', b'jack', b'maria', b'kiku', b'thanlon']
b'thanlon'
b'kiku'
b'maria'
b'jack'
b'michael'
b'angle'
'''
# 後進先出
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
conn.lpush('employees', 'thanlon')
conn.lpush('employees', 'kiku')
conn.lpush('employees', 'maria')
conn.lpush('employees', 'jack')
conn.lpush('employees', 'michael')
conn.lpush('employees', 'angle')
print(conn.lrange('employees', 0, -1))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
print(conn.lpop('employees'))
'''
[b'angle', b'michael', b'jack', b'maria', b'kiku', b'thanlon']
b'angle'
b'michael'
b'jack'
b'maria'
b'kiku'
b'thanlon'
'''
# 優先級隊列,採用任務入隊的時候設置權值
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
'''
只執行一次添加元素
'''
# conn.lpush('bosses', 'thanlon')
# conn.set('bosses_score_thanlon', 2)
# conn.lpush('bosses', 'kiku')
# conn.set('bosses_score_kiku', 3)
# conn.lpush('bosses', 'tom')
# conn.set('bosses_score_tom', -1)

# 原來的隊列
print(conn.lrange('bosses', 0, -1))  # [b'tom', b'kiku', b'thanlon']
# 排序後的任務隊列
print(conn.sort('bosses', by='bosses_score_*'))  # [b'tom', b'thanlon', b'kiku']
# 取出優先級最高的任務
high_work = conn.sort('bosses', start=0, num=1, by='bosses_score_*', desc=True)
print(high_work)  # [b'kiku']
# 移除這個任務
conn.lrem('bosses', 0, high_work[0].decode('utf-8'))
'''
# 第一次
[b'tom', b'kiku', b'thanlon']
[b'tom', b'thanlon', b'kiku']
[b'kiku']第一優先級任務
# 第二次
[b'tom', b'thanlon']
[b'tom', b'thanlon']
[b'thanlon']第二優先級任務
[b'tom']
[b'tom']
[b'tom']第三優先級任務
'''
  • 如何基於redis實現消息隊列:使用lpush向list的左端推送數據(發送消息),使用rpop從list的右端接收數據(接收消息)。
  • 如何基於redis實現發佈和訂閱:使用publish來發布消息,使用subscribe來接收訂閱,獲取訂閱消息。
  • 消息隊列和發佈訂閱的區別:“發佈/訂閱”模式包含兩種角色,分別是發佈者和訂閱者。訂閱者可以訂閱一個或若干個頻道(channel),而發佈者可以向指定的頻道發送消息,所有訂閱此頻道的訂閱者都會收到此消息。【 區別一:前者通過key隊列方式實現,取出就刪掉了,其他進程也取不到,阻塞進程。訂閱發佈可以支持多客戶端獲取同一個頻道發佈的消息。區別二:前者消息不處理會緩存在列表,後者不處理的話消息就丟失了。】
  • 什麼是codis及其作用:codis是一個分佈式redis解決方案,可以用於redis的擴容、支持在線數據遷移,可以自動進行數據分配。codis比較適合那種數據庫比較大,但併發量不是特別高的系統。
  • 什麼是twemproxy及其作用:twemproxy是一種代理分片機制,可接受來自多個程序的訪問,按照路由規則,轉發給後臺的各個Redis服務器,再原路返回。可以解決了單個Redis實例承載能力的問題,可用來擴張redis,Twemproxy需要更多的硬件資源和在redis性能有一定的損失(twitter測試約20%),但是能夠提高整個系統的高可用(HA)也還是不錯的。回答的時候說類似於nginx,是一種代理的存在。[twemproxy是 Twtter 開源的一個 Redis 和 Memcache 代理服務器,主要用於管理 Redis 和 Memcached 集羣,減少與Cache 服務器直接連接的數量。]
  • 寫代碼實現redis事務操作
import redis

pool = redis.ConnectionPool(host='106.12.115.136', port=6390, password='redis6390')
conn = redis.Redis(connection_pool=pool)
pipe = conn.pipeline(transaction=True)
pipe.set('name', 'thanlon')
pipe.set('age', 23)
pipe.execute()
  • redis中的watch命令的作用:watch( watch key[key...])命令用於在進行事務操作的最後一步(也就是在執行exec 之前)對某個key進行監視。如果這個被監視的key被改動,那麼事務就被取消,否則事務正常執行。一般在mulit 命令前就用watch命令對某個key進行監控,如果想讓key取消被監控,可以用unwatch命令。【當某個事務需要按條件執行時,就要使用這個命令將給定的鍵設置爲受監控的】
  • 基於redis如何實現商城商品數量計數器:使用redis的Incr自增和desr自減命令可以實現商城商品數量計數器。
  • 簡述redis分佈式鎖redlock的實現機制:互斥,任何時刻只能有一個client獲取鎖。釋放死鎖,即使鎖定資源的服務崩潰或者分區,仍然能釋放鎖。容錯性,只要多數redis節點(一半以上)在使用,client就可以獲取和釋放鎖。
  • 什麼是一致性哈希,Python中是否有相應模塊:一致性哈希簡而言之就是不僅僅數據做哈希,機器也做哈希;python中有相應的模塊,即:hashlib模塊。
  • 如何高效的找到redis中所有以某某開頭的key:使用keys命令的話,如果數據量比較大,可能會卡頓,不適用於生產環境,應該使用基於遊標的迭代器來做。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章