您好,登錄后才能下訂單哦!
Redis(Remote Dictionary Server)遠程字典數據服務的縮寫,由意大利
人開發的是一款內存高速緩存數據庫。使用ANSI C語言編寫、支持網絡、可基于內
存亦可持久化的日志型、Key-Value數據庫,并提供多種語言的API并提供多種語言
的 API的非關系型數據庫。
Redis和Memcache對比?
set 'a' '123'
? string 類型 是二進制安全的。可以包含任何數據(eg: jpg 圖片或者序列化的對象)。
從內部實現來看其實 string 可以看作 byte 數組,最大上限是 1G 字節。
? hash類型 是一個 string 類型的 field 和 value 的映射表.它的添加、刪除操作都是
O(1)(平均)。
? list類型 是一個 string 類型的雙向鏈表。最大長度是(2 32 )。
? set 類型 是 string 類型的通過 hash table 實現的無序集合。添加、刪除和查找的復
雜度都是 O(1)。最大長度是(2 32 )。
Redis內置指令: http://doc.redisfans.com/
Redis應用場景
Redis 是一個內存數據庫,與傳統的MySQL,Oracle等關系型數據庫直接將內容保存到硬盤
中相比,內存數據庫的讀寫效率比傳統數據庫要快的多(內存的讀寫效率遠遠大于硬盤的讀寫
效率)。但是保存在內存中也隨之帶來了一個缺點,一旦斷電或者宕機,那么內存數據庫中的
數據將會全部丟失。
目標: 持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。
Redis 提供了兩種持久化方式:RDB(默認) 和AOF
Redis持久化: RDB
RDB是Redis用來進行持久化的一種方式,是把當前內存中的數據集快照寫入
磁盤,也就是 Snapshot 快照(數據庫中所有鍵值對數據)。恢復時是將快
照文件直接讀到內存里。
我們可以配置 redis在 n 秒內如果超過 m 個 key 被修改就自動做快照,下面是默認的快照保
存配置:
dbfilename dump.rdb
save 900 1
save 300 10
#持久化存儲文件名為 dump.rdb
#900 秒內如果超過 1 個 key 被修改,則發起快照保存
#300 秒內容如超過 10 個 key 被修改,則發起快照保
存
save 60 10000 # 600 秒內容如超過 10000 個 key 被修改,則發起快照保存
Redis持久化: AOF
? RDB 持久化存是一定時間內做一次備份,如果
redis意外down掉的話,就會丟失最后一次快照后
的所有修改(數據有丟失)。
? 工作原理: 當 redis 重啟時會通過重新執行文件中
保存的寫命令來在內存中重建整個數據庫的內容。
通過配置文件告訴 redis 我們想要通過 fsync 函數強制 os 寫入到磁盤的時機。有三
種方式如下(默認是:每秒 fsync 一次), 通過BGREWRITEAOF指令壓縮/優化命令
//啟用 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批量插入數據發現appendonly.aof文件大小發生變化
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、內存容量有限 2、處理能力有限 3、無法高可用。
主從復制
主從復制
Redis 的復制(replication)功能允許用戶根據一個 Redis 服務器來創建任意多個該
服務器的復制品,其中被復制的服務器為主服務器(master),而通過復制創建出來
的服務器復制品則為從服務器(slave)。 只要主從服務器之間的網絡連接正常,主從
服務器兩者會具有相同的數據,主服務器就會一直將發生在自己身上的數據更新同步 給
從服務器,從而一直保證主從服務器的數據相同。
特點:
1、master/slave 角色
2、master/slave 數據相同
3、降低 master 讀壓力在轉交從庫
問題:
"""
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')
限制某段時間內的訪問次數,就比如我們登錄的功能可以用手機獲取驗證碼登錄,但是我們發送驗證碼使用的第三方,是多少錢多少條的,
肯定不能讓他一直點,一直發短信,就算前端js做了校驗,若有些人用fiddler攔截繞過前臺就麻煩了,
這時候可以用redis的incr命令和expire結合起來做一個解決方案
import time
def send_msg(phone):
"""模擬給手機發送驗證碼"""
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秒之后可以再次發送驗證碼
:param phone:
:return:
"""
import redis
client = redis.StrictRedis()
#可以從緩存中查詢驗證碼已經發送。
if client.get(phone):
print("驗證碼發送頻繁, 請稍后再試")
return False
else:
code = send_msg(phone)
client.set(phone, code, 3)
print("發送驗證碼成功")
if __name__ == '__main__':
print("第一次發送")
phone_code('110')
print("第二次發送")
phone_code('110')
time.sleep(4)
print("第三次發送")
phone_code('110')"""
IP限制頻繁訪問:
如果你運行 HTTP 服務,并且希望限制 HTTP 的訪問頻率,那么你可以借助一些比較穩定的工具,
例如: github.com/didip/tollbooth。不過如果你構建的應用比較簡單,也可以自己來實現。
IP限制的規則:
每分鐘訪問次數不能超過60次。
"""
def ip_limit(IP):
"""
每分鐘訪問次數不能超過60次。
key: value = IP:count
:param IP:
:return:
"""
import redis
client = redis.StrictRedis()
#1). 判斷是否訪問過本服務器;
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: 內存緩存數據庫, 消息隊列(kafka、RabbitMQ)
#如何實現高并發場景下搶紅包的設計。
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
項目實戰: 分布式緩存服務實踐: Redis實現排行榜功能
在網頁和APP中常常需要用到榜單的功能,對某個key-value的列表進行降序顯示。當操作和查詢并發大的時候,
使用傳統數據庫就會遇到性能瓶頸,造成較大的時延。使用分布式緩存服務Redis,可以實現一個
商品熱銷排行榜的功能。它的優勢在于:
- 數據保存在緩存中,讀寫速度非常快。
- 提供字符串(String)、鏈表(List)、集合(Set)、哈希(Hash)等多種數據結構類型的存儲。
"""
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()
"""
#設置服務器,用戶名、口令以及郵箱的后綴
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
smtp_server = "smtp.163.com"
from_username = '技術中心'
mail_user = "xc@163.com"
#是開啟smtp的授權嗎不是真實的密碼。
mail_password = "westos123"
#郵件主題的前綴
mail_prefix = "[運維開發部]-"
def send_email(to_addrs, subject, msg):
try:
# 將要發送的文本信息做MIME封裝
msg = MIMEText(msg)
#格式化發件人名稱
msg['From'] = formataddr([from_username, mail_user])
msg['To'] = to_addrs
msg['Subject'] = mail_prefix + subject
#1. 實例化smtp對象
server = smtplib.SMTP()
#2. 連接郵件服務器
server.connect(smtp_server)
#3. 登錄
server.login(mail_user, mail_password)
#4. 發送郵件內容
server.sendmail(mail_user, to_addrs, msg.as_string())
#5. 關閉連接
server.quit()
except Exception as e:
print(str(e))
return False
else:
return True
if __name__ == '__main__':
send_email('976131@qq.com','寒假作業', '請與3月2日之前提交')
print("發送成功.....")
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。