新聞中心
Redis穿透:有效解決方案

近年來,Redis已成為了很多互聯(lián)網(wǎng)公司的首選緩存數(shù)據(jù)庫之一。然而,Redis在承載大量數(shù)據(jù)時,很容易遇到一種被稱為“Redis穿透”問題。這種問題會引起Redis服務(wù)器的崩潰,給系統(tǒng)帶來不小的損失。本文將為大家介紹一些有效的解決Redis穿透問題的方案。
Redis穿透問題背景
在使用Redis時,我們通常會將一些重量級的操作緩存在Redis中,比如數(shù)據(jù)庫查詢結(jié)果或其他第三方服務(wù)的響應(yīng)結(jié)果。這些操作的結(jié)果是經(jīng)過計算和處理的,并且不會隨著時間的推移而發(fā)生變化。這種類型的操作結(jié)果使用Redis緩存常常能夠帶來較大的性能提升,同時也能減輕其他數(shù)據(jù)庫的壓力。
但是,在大量數(shù)據(jù)的情況下,如果沒有采取足夠的對策,在某些它不應(yīng)該獲取的數(shù)據(jù)的情況下,Redis可能會無法承受大量的查詢請求壓力,從而崩潰。
我們假設(shè)你有一個查詢某個商品詳細(xì)信息的接口,可以通過將請求的商品ID作為參數(shù)傳遞給后臺服務(wù)來獲取信息。如果黑客向你的服務(wù)器發(fā)送一個查詢不存在的商品ID的請求,由于Redis緩存中沒有相應(yīng)數(shù)據(jù),系統(tǒng)將不得不去數(shù)據(jù)庫查詢。當(dāng)攻擊者重復(fù)發(fā)送此類請求時,即產(chǎn)生了“Redis穿透”問題,將會在短時間內(nèi)導(dǎo)致大量的緩存不中命中,最終導(dǎo)致內(nèi)存和CPU資源不斷增長,最終將Redis服務(wù)器消耗完。
解決方案
1. 布隆過濾器
布隆過濾器是一種經(jīng)典的利用概率算法來解決Redis穿透問題的解決方案。它可以幫助我們快速確定是否一個請求的ID值是否存在于緩存之中。這種解決方法主要是通過將所有存在的請求ID以及HASH值放進(jìn)一個超大的比特數(shù)組中,判斷的時候通過比特數(shù)組查詢是否有一段位置被置位,若被置位,則說明該ID已經(jīng)處理過。這種方法雖然效率很高,但有一定的誤差率。
以下是一個實(shí)現(xiàn)布隆過濾器的Python 代碼示例:
“`python
import redis
import collections
import hashlib
class BloomFilter(object):
def __init__(self, capacity=10000, error_rate=0.01):
”’
初始化Bloom Filter
”’
self.key = ‘bloomfilter’
self.capacity = capacity
self.error_rate = error_rate
self.pool = redis.ConnectionPool(host=’localhost’, port=6379, db=0)
self.r = redis.Redis(connection_pool=self.pool)
self.hash_count, self.bit_count = self.get_optimal_para()
def get_optimal_para(self):
m = -1 * (self.capacity * math.log(self.error_rate)) / (math.log(2) ** 2)
k = (m / self.capacity) * math.log(2)
return int(math.ceil(k)), int(math.ceil(m))
def is_exists(self, value):
if not value:
return False
exist = True
hash_values = self.generate_hash(value)
for offset in hash_values:
v = self.r.getbit(self.key, offset)
if v == 0:
exist = False
self.r.setbit(self.key, offset, 1)
return exist
def generate_hash(self, value):
offset_list = []
murmur = hashlib.md5()
murmur.update(value.encode())
seed = int(murmur.hexdigest(), 16)
m, k = self.bit_count, self.hash_count
for i in range(k):
offset = hash(‘{}{}’.format(seed, i)) % m
offset_list.append(offset)
return offset_list
2. 緩存空對象
另一種解決Redis穿透問題的方法是當(dāng)你從數(shù)據(jù)庫中查詢出了一個不存在的數(shù)據(jù)時,你應(yīng)該將這個結(jié)果加到Redis緩存當(dāng)中,只不過這個結(jié)果的值應(yīng)該是空對象,也就是說返回的結(jié)果可以不是null或者類似的空集合(array,list),而是一個特殊的標(biāo)記——一個表示不存在的空對象。這種空對象可以是一個字符串、數(shù)字或其他類型的數(shù)據(jù),只要確保它不會被返回給客戶端就可以了。
以下是一個PHP的示例代碼:
```php
function get_user($id)
{
$user_info = $redis->get(sprintf('user:%d', $id));
if (!$user_info || $user_info == 'null') {
$user = $db->get_user($id);
if (!$user) {
$redis->setex(sprintf('user:%s', $id), 300, 'null');
} else {
$redis->setex(sprintf('user:%s', $user['id']), 300, json_encode($user));
}
} else if ($user_info == 'null') {
return NULL;
}
return json_decode($user_info, true);
}
?>
總結(jié)
Redis穿透問題是一個相對比較麻煩的問題。如果我們不采取相應(yīng)的措施,其將會帶來很多影響,甚至被攻擊的請求會導(dǎo)致Redis服務(wù)器崩潰。我們在使用Redis緩存數(shù)據(jù)庫時一定要注意處理這種情況。布隆過濾器是一種相對有效的方法,即使它有一定的誤差率,并且可以使用空對象緩存解決Redis穿透問題。使用這些方法可以幫助提高Redis服務(wù)器的處理效率,并減輕服務(wù)器的負(fù)擔(dān)。
成都創(chuàng)新互聯(lián)建站主營:成都網(wǎng)站建設(shè)、網(wǎng)站維護(hù)、網(wǎng)站改版的網(wǎng)站建設(shè)公司,提供成都網(wǎng)站制作、成都網(wǎng)站建設(shè)、成都網(wǎng)站推廣、成都網(wǎng)站優(yōu)化seo、響應(yīng)式移動網(wǎng)站開發(fā)制作等網(wǎng)站服務(wù)。
新聞名稱:Redis穿透有效解決方案(redis穿透解決辦法)
文章路徑:http://m.fisionsoft.com.cn/article/ccssjod.html


咨詢
建站咨詢
