十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
Redis實(shí)現(xiàn)租戶(hù)自動(dòng)過(guò)濾功能

在分布式系統(tǒng)中,如何實(shí)現(xiàn)租戶(hù)自動(dòng)過(guò)濾功能是一個(gè)比較常見(jiàn)的問(wèn)題,這種情況通常出現(xiàn)在需要共享一個(gè)龐大的數(shù)據(jù)庫(kù)的時(shí)候。當(dāng)多個(gè)租戶(hù)(或者不同的應(yīng)用程序)共享同一數(shù)據(jù)庫(kù)時(shí),需要通過(guò)自動(dòng)過(guò)濾功能來(lái)保障彼此之間的數(shù)據(jù)隔離,防止一個(gè)租戶(hù)能夠看到另外一個(gè)租戶(hù)的數(shù)據(jù),或者誤刪別人的數(shù)據(jù),導(dǎo)致數(shù)據(jù)庫(kù)崩潰的情況。在這種情況下,Redis可以起到很好的作用。本文將介紹在Redis中如何實(shí)現(xiàn)租戶(hù)自動(dòng)過(guò)濾功能。
我們需要一個(gè)代理來(lái)攔截所有的數(shù)據(jù)庫(kù)請(qǐng)求。這個(gè)代理可以是一個(gè)簡(jiǎn)單的RESTful API,也可以是一個(gè)更加復(fù)雜的中間件。無(wú)論采用何種方案,都需要將用戶(hù)請(qǐng)求路由到正確的 Redis 哈希表。考慮到后期維護(hù)的可用性,建議采用一個(gè)獨(dú)立的中間件來(lái)?yè)?dān)任此角色。我們可以稱(chēng)此中間件為“Redis過(guò)濾器”。
在Redis過(guò)濾器中,將數(shù)據(jù)庫(kù)的鍵(key)映射為租戶(hù)標(biāo)識(shí)符(通常為GUID),就可以在Redis哈希表中實(shí)現(xiàn)完全的數(shù)據(jù)隔離。在每次請(qǐng)求之前,過(guò)濾器都需要查詢(xún)到相應(yīng)租戶(hù)的標(biāo)識(shí)符,并將其作為Redis哈希表的前綴,在查詢(xún)或?qū)懭霐?shù)據(jù)庫(kù)時(shí)自動(dòng)添加到所請(qǐng)求的鍵中。由于這個(gè)過(guò)濾器是在數(shù)據(jù)庫(kù)請(qǐng)求之前攔截的,所以用戶(hù)無(wú)法越過(guò)這一層進(jìn)行訪(fǎng)問(wèn)。
這里提供一個(gè)簡(jiǎn)單的Python代碼片段來(lái)顯示這個(gè)過(guò)程:
“`python
import redis
import threading
class RedisFilterMiddleware():
def __init__(self, app):
self.app = app
self.redis_client = redis.Redis(host=’localhost’)
def __call__(self, environ, start_response):
tenant_id = self.__get_tenant_id(environ)
with self.redis_client.pipeline() as pipe:
pipe.hget(‘tenant_map’, tenant_id)
mappings, _ = pipe.execute()
environ[‘tenant_id’] = tenant_id
environ[‘mappings’] = mappings
return self.app(environ, start_response)
def __get_tenant_id(self, environ):
return environ.get(‘HTTP_X_TENANT_ID’, None)
在上面的代碼中,我們創(chuàng)建了一個(gè)中間件類(lèi),其中在init函數(shù)中初始化了Redis客戶(hù)端;在_\_call\_\_函數(shù)中獲取租戶(hù)ID,查詢(xún)租戶(hù)與哈希表的映射表,并將其添加到請(qǐng)求的環(huán)境變量中。
現(xiàn)在我們需要實(shí)現(xiàn)一個(gè)類(lèi)來(lái)支持?jǐn)?shù)據(jù)隔離,并將其映射到Redis哈希表中。這個(gè)類(lèi)必須有相應(yīng)的接口類(lèi),這樣才能在過(guò)濾器中使用。 在Redis數(shù)據(jù)庫(kù)中,哈希表優(yōu)秀的方面之一是其完全支持分段式表格。在此例中,每個(gè)租戶(hù)對(duì)應(yīng)一個(gè)單獨(dú)的哈希表。這些哈希表的名稱(chēng)是基于租戶(hù)ID生成的,并且所有表都被存儲(chǔ)在“租戶(hù)數(shù)據(jù)庫(kù)”之內(nèi),以保持不同租戶(hù)間的數(shù)據(jù)隔離。
在Python中,我們可以使用如下代碼實(shí)現(xiàn):
```python
class RedisTable(object):
def __init__(self, redis_client, tenant_id):
self.redis_client = redis_client
self.table_name = f'table_{tenant_id}'
def get_key(self, key):
return f'{self.table_name}:{key}'
def __getitem__(self, key):
return self.redis_client.get(self.get_key(key))
def __setitem__(self, key, value):
return self.redis_client.set(self.get_key(key), value)
在上面的代碼中,我們創(chuàng)建了一個(gè)Python類(lèi),名為RedisTable。該類(lèi)保存了Redis客戶(hù)端對(duì)象和一個(gè)table_name,用來(lái)作為Redis哈希表的前綴。然后我們創(chuàng)建了一個(gè)get_key函數(shù),用來(lái)返回一個(gè)合適的URL,以便在Redis中查找對(duì)應(yīng)鍵值;同時(shí),還需要 __getitem__ 和 __setitem__ 函數(shù),以便將查詢(xún)和寫(xiě)入操作轉(zhuǎn)換為Redis哈希表。
接下來(lái),在mn函數(shù)中編寫(xiě)以下代碼:
“`python
app = flask.Flask(__name__)
@app.route(‘/action/create’, methods=[‘POST’])
def create():
table = RedisTable(redis.Redis(host=’localhost’), request.environ[‘tenant_id’])
table[request.form[‘key’]] = request.form[‘value’]
return ‘Ok’, 200
@app.route(‘/action/get’, methods=[‘GET’])
def get():
table = RedisTable(redis.Redis(host=’localhost’), request.environ[‘tenant_id’])
value = table[request.args[‘key’]]
return json.dumps(value), 200
if __name__ == ‘__mn__’:
app.wsgi_app = RedisFilterMiddleware(app.wsgi_app)
app.run()
在上面的代碼中,我們使用Flask來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的Web應(yīng)用,其中包含兩個(gè)路由。 /action/create負(fù)責(zé)將添加值到Redis哈希表, /action/get 負(fù)責(zé)查詢(xún)Redis哈希表,并返回該值。在兩個(gè)路由中,我們都使用了RedisTable類(lèi)來(lái)完成對(duì)Redis哈希表的操作,并使用tenant_id來(lái)實(shí)現(xiàn)數(shù)據(jù)隔離。
在Redis客戶(hù)端中,我們需要設(shè)置一個(gè)名為“tenant_map”的哈希表,用以存儲(chǔ)哈希表的映射關(guān)系。當(dāng)我們需要為新的租戶(hù)創(chuàng)建一個(gè)哈希表時(shí),只需將其ID添加到此哈希表中即可:
redis-cli
> hset tenant_map 004 ridis_004
OK
在這個(gè)例子中,我們創(chuàng)建了名為004的租戶(hù),并將其哈希表命名為ridis_004。這個(gè)命名方式可以為我們?cè)赗edis中清晰地找到相應(yīng)租戶(hù)的哈希表。
結(jié)論
在這篇文章中,我們介紹了如何使用Redis來(lái)實(shí)現(xiàn)租戶(hù)自動(dòng)過(guò)濾功能。我們使用了一個(gè)中間件來(lái)攔截所有的數(shù)據(jù)庫(kù)請(qǐng)求,并通過(guò)查詢(xún)租戶(hù)ID的方式將數(shù)據(jù)隔離開(kāi)來(lái)。我們還使用Redis哈希表來(lái)實(shí)現(xiàn)完全數(shù)據(jù)隔離,并將租戶(hù)ID作為哈希表的前綴。通過(guò)這種方式,每個(gè)租戶(hù)都能夠獨(dú)立地使用數(shù)據(jù)庫(kù),而不必?fù)?dān)心數(shù)據(jù)泄露或誤刪。
創(chuàng)新互聯(lián)【028-86922220】值得信賴(lài)的成都網(wǎng)站建設(shè)公司。多年持續(xù)為眾多企業(yè)提供成都網(wǎng)站建設(shè),成都品牌網(wǎng)站設(shè)計(jì),成都高端網(wǎng)站制作開(kāi)發(fā),SEO優(yōu)化排名推廣服務(wù),全網(wǎng)營(yíng)銷(xiāo)讓企業(yè)網(wǎng)站產(chǎn)生價(jià)值。