您好,登錄后才能下訂單哦!
Redis(Remote Dictionary Server)遠程字典數(shù)據(jù)服務(wù)的縮寫,由意大利
人開發(fā)的是一款內(nèi)存高速緩存數(shù)據(jù)庫。使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)
存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API并提供多種語言
的 API的非關(guān)系型數(shù)據(jù)庫。
Redis和Memcache對比?
set 'a' '123'
? string 類型 是二進制安全的??梢园魏螖?shù)據(jù)(eg: jpg 圖片或者序列化的對象)。
從內(nèi)部實現(xiàn)來看其實 string 可以看作 byte 數(shù)組,最大上限是 1G 字節(jié)。
? hash類型 是一個 string 類型的 field 和 value 的映射表.它的添加、刪除操作都是
O(1)(平均)。
? list類型 是一個 string 類型的雙向鏈表。最大長度是(2 32 )。
? set 類型 是 string 類型的通過 hash table 實現(xiàn)的無序集合。添加、刪除和查找的復
雜度都是 O(1)。最大長度是(2 32 )。
Redis內(nèi)置指令: http://doc.redisfans.com/
Redis應(yīng)用場景
Redis 是一個內(nèi)存數(shù)據(jù)庫,與傳統(tǒng)的MySQL,Oracle等關(guān)系型數(shù)據(jù)庫直接將內(nèi)容保存到硬盤
中相比,內(nèi)存數(shù)據(jù)庫的讀寫效率比傳統(tǒng)數(shù)據(jù)庫要快的多(內(nèi)存的讀寫效率遠遠大于硬盤的讀寫
效率)。但是保存在內(nèi)存中也隨之帶來了一個缺點,一旦斷電或者宕機,那么內(nèi)存數(shù)據(jù)庫中的
數(shù)據(jù)將會全部丟失。
目標: 持久化就是把內(nèi)存的數(shù)據(jù)寫到磁盤中去,防止服務(wù)宕機了內(nèi)存數(shù)據(jù)丟失。
Redis 提供了兩種持久化方式:RDB(默認) 和AOF
Redis持久化: RDB
RDB是Redis用來進行持久化的一種方式,是把當前內(nèi)存中的數(shù)據(jù)集快照寫入
磁盤,也就是 Snapshot 快照(數(shù)據(jù)庫中所有鍵值對數(shù)據(jù))。恢復時是將快
照文件直接讀到內(nèi)存里。
我們可以配置 redis在 n 秒內(nèi)如果超過 m 個 key 被修改就自動做快照,下面是默認的快照保
存配置:
dbfilename dump.rdb
save 900 1
save 300 10
#持久化存儲文件名為 dump.rdb
#900 秒內(nèi)如果超過 1 個 key 被修改,則發(fā)起快照保存
#300 秒內(nèi)容如超過 10 個 key 被修改,則發(fā)起快照保
存
save 60 10000 # 600 秒內(nèi)容如超過 10000 個 key 被修改,則發(fā)起快照保存
Redis持久化: AOF
? RDB 持久化存是一定時間內(nèi)做一次備份,如果
redis意外down掉的話,就會丟失最后一次快照后
的所有修改(數(shù)據(jù)有丟失)。
? 工作原理: 當 redis 重啟時會通過重新執(zhí)行文件中
保存的寫命令來在內(nèi)存中重建整個數(shù)據(jù)庫的內(nèi)容。
通過配置文件告訴 redis 我們想要通過 fsync 函數(shù)強制 os 寫入到磁盤的時機。有三
種方式如下(默認是:每秒 fsync 一次), 通過BGREWRITEAOF指令壓縮/優(yōu)化命令
//啟用 aof 持久化方式
appendonly yes
//收到寫命令就立即寫入磁盤,最慢,但是保證完全的持久化
#appendfsync always
//每秒鐘寫入磁盤一次,在性能和持久化方面做了很好的折中
appendfsync everysec
//完全依賴 os,性能最好,持久化沒保證
#appendfsync no
配置:修改redis配置文件
vim /etc/redis/6379.conf
appendonly yes #修改appendonly為yes
cd /var/lib/redis/6379/ #進入目錄生成aof文件
ls
appendonly.aof dump.rdb
python批量插入數(shù)據(jù)發(fā)現(xiàn)appendonly.aof文件大小發(fā)生變化
import redis
redis_client = redis.StrictRedis(host='localhost',port=6379)
redis_client.mset({'name':'westos','age':10})
name = redis_client.get('name').decode('utf-8')
name_len = redis_client.strlen('name')
print('用戶名稱:',name,'用戶名長度:',name_len)
age_add = redis_client.incr('age')
for i in range(1000):
redis_client.incr('age')
單機版
特點:簡單
問題:1、內(nèi)存容量有限 2、處理能力有限 3、無法高可用。
主從復制
主從復制
Redis 的復制(replication)功能允許用戶根據(jù)一個 Redis 服務(wù)器來創(chuàng)建任意多個該
服務(wù)器的復制品,其中被復制的服務(wù)器為主服務(wù)器(master),而通過復制創(chuàng)建出來
的服務(wù)器復制品則為從服務(wù)器(slave)。 只要主從服務(wù)器之間的網(wǎng)絡(luò)連接正常,主從
服務(wù)器兩者會具有相同的數(shù)據(jù),主服務(wù)器就會一直將發(fā)生在自己身上的數(shù)據(jù)更新同步 給
從服務(wù)器,從而一直保證主從服務(wù)器的數(shù)據(jù)相同。
特點:
1、master/slave 角色
2、master/slave 數(shù)據(jù)相同
3、降低 master 讀壓力在轉(zhuǎn)交從庫
問題:
"""
import redis
redis_client = redis.StrictRedis(host='172.25.254.18', port=6379)
#對于字符串的操作
"""
get
mget
set
mset
incr
incrby
decr
decrby
strlen
"""
redis_client.mset({'name':'westos', 'age':10})
name = redis_client.get('name').decode('utf-8')
name_len = redis_client.strlen('name')
print("用戶名稱: ", name, "用戶名稱長度: ", name_len)
age_add = redis_client.incr('age')
print("當前年齡為: ", redis_client.get('age'))
for i in range(10000):
redis_client.incr('age')
限制某段時間內(nèi)的訪問次數(shù),就比如我們登錄的功能可以用手機獲取驗證碼登錄,但是我們發(fā)送驗證碼使用的第三方,是多少錢多少條的,
肯定不能讓他一直點,一直發(fā)短信,就算前端js做了校驗,若有些人用fiddler攔截繞過前臺就麻煩了,
這時候可以用redis的incr命令和expire結(jié)合起來做一個解決方案
import time
def send_msg(phone):
"""模擬給手機發(fā)送驗證碼"""
import string
import random
#['4', '1', '5', '9']
nums_list = random.sample(string.digits, 4)
nums_code = "".join(nums_list)
print("%s驗證碼:%s[公司]" %(phone, nums_code))
return nums_code
def phone_code(phone):
"""
電話驗證碼模擬, 3秒之后可以再次發(fā)送驗證碼
:param phone:
:return:
"""
import redis
client = redis.StrictRedis()
#可以從緩存中查詢驗證碼已經(jīng)發(fā)送。
if client.get(phone):
print("驗證碼發(fā)送頻繁, 請稍后再試")
return False
else:
code = send_msg(phone)
client.set(phone, code, 3)
print("發(fā)送驗證碼成功")
if __name__ == '__main__':
print("第一次發(fā)送")
phone_code('110')
print("第二次發(fā)送")
phone_code('110')
time.sleep(4)
print("第三次發(fā)送")
phone_code('110')"""
IP限制頻繁訪問:
如果你運行 HTTP 服務(wù),并且希望限制 HTTP 的訪問頻率,那么你可以借助一些比較穩(wěn)定的工具,
例如: github.com/didip/tollbooth。不過如果你構(gòu)建的應(yīng)用比較簡單,也可以自己來實現(xiàn)。
IP限制的規(guī)則:
每分鐘訪問次數(shù)不能超過60次。
"""
def ip_limit(IP):
"""
每分鐘訪問次數(shù)不能超過60次。
key: value = IP:count
:param IP:
:return:
"""
import redis
client = redis.StrictRedis()
#1). 判斷是否訪問過本服務(wù)器;
if client.exists(IP):
count = client.get(IP).decode('utf-8')
if int(count) >= 60:
print("%s訪問頻繁" %(IP))
else:
client.incr(IP)
print("訪問+1")
else:
client.set(IP, 1, 60)
print("%s第一次訪問" %(IP))
if __name__ == '__main__':
ip_limit('127.0.0.1')
for i in range(100):
ip_limit('172.25.254.197')
"""
Redis: 內(nèi)存緩存數(shù)據(jù)庫, 消息隊列(kafka、RabbitMQ)
#如何實現(xiàn)高并發(fā)場景下?lián)尲t包的設(shè)計。
import queue
class RedisQueue(object):
"""左邊為隊頭, 右邊為隊尾的消息隊列"""
def __init__(self, name, **conf):
import redis
self.__client = redis.Redis(**conf)
self.key = name
def qsize(self):
return self.__client.llen(self.key)
def put(self, item):
"""入隊操作"""
self.__client.rpush(self.key, item)
def get(self, timeout=5):
"""獲取對頭, 如果沒有到, 等待時間為timeout"""
item = self.__client.blpop(self.key, timeout=timeout)
return item
def get_nowait(self):
item = self.__client.blpop(self.key)
return item
if __name__ == '__main__':
q = RedisQueue('scores', host='172.25.254.18', port=6380)
for i in range(10):
q.put(i)
while True:
result = q.get(timeout=100)
print(result)
if not result:
break
項目實戰(zhàn): 分布式緩存服務(wù)實踐: Redis實現(xiàn)排行榜功能
在網(wǎng)頁和APP中常常需要用到榜單的功能,對某個key-value的列表進行降序顯示。當操作和查詢并發(fā)大的時候,
使用傳統(tǒng)數(shù)據(jù)庫就會遇到性能瓶頸,造成較大的時延。使用分布式緩存服務(wù)Redis,可以實現(xiàn)一個
商品熱銷排行榜的功能。它的優(yōu)勢在于:
- 數(shù)據(jù)保存在緩存中,讀寫速度非???。
- 提供字符串(String)、鏈表(List)、集合(Set)、哈希(Hash)等多種數(shù)據(jù)結(jié)構(gòu)類型的存儲。
"""
import random
def productSalesRankDemo():
import redis
import uuid
PRODUCT_KINDS = 30
host = "127.0.0.1"
port = 6379
password = ''
key = "商品熱銷排行榜"
client = redis.StrictRedis(host=host, port=port, password=password)
if not client.exists(key):
products = {}
for count in range(PRODUCT_KINDS):
product_name = 'product-' + str(uuid.uuid4())
product_sale = random.randint(1000, 20000)
products[product_name] = product_sale
client.zadd(key, products)
productSalesRankDemo()"""
import redis
redis_client = redis.StrictRedis(host='172.25.254.18', port=6380)
pipe = redis_client.pipeline()
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.execute()
"""
#設(shè)置服務(wù)器,用戶名、口令以及郵箱的后綴
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
smtp_server = "smtp.163.com"
from_username = '技術(shù)中心'
mail_user = "xc@163.com"
#是開啟smtp的授權(quán)嗎不是真實的密碼。
mail_password = "westos123"
#郵件主題的前綴
mail_prefix = "[運維開發(fā)部]-"
def send_email(to_addrs, subject, msg):
try:
# 將要發(fā)送的文本信息做MIME封裝
msg = MIMEText(msg)
#格式化發(fā)件人名稱
msg['From'] = formataddr([from_username, mail_user])
msg['To'] = to_addrs
msg['Subject'] = mail_prefix + subject
#1. 實例化smtp對象
server = smtplib.SMTP()
#2. 連接郵件服務(wù)器
server.connect(smtp_server)
#3. 登錄
server.login(mail_user, mail_password)
#4. 發(fā)送郵件內(nèi)容
server.sendmail(mail_user, to_addrs, msg.as_string())
#5. 關(guān)閉連接
server.quit()
except Exception as e:
print(str(e))
return False
else:
return True
if __name__ == '__main__':
send_email('976131@qq.com','寒假作業(yè)', '請與3月2日之前提交')
print("發(fā)送成功.....")
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。