国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數(shù)據(jù)庫 > Redis > 正文

如何使用Redis實(shí)現(xiàn)SQL伸縮

2020-02-17 14:54:42
字體:
供稿:網(wǎng)友

為了能夠讓大家更好的學(xué)習(xí)Redis,今天武林技術(shù)頻道的小編就教各位如何使用Redis實(shí)現(xiàn)SQL伸縮,在本文里還包括講到了鎖和時(shí)間序列等方面來提升傳統(tǒng)數(shù)據(jù)庫的性能,很值得收藏,需要的朋友趕緊來參考參考吧。

緩解行競(jìng)爭(zhēng)

我們?cè)赟entry開發(fā)的早起采用的是sentry.buffers。 這是一個(gè)簡(jiǎn)單的系統(tǒng),它允許我們以簡(jiǎn)單的Last Write Wins策略來實(shí)現(xiàn)非常有效的緩沖計(jì)數(shù)器。 重要的是,我們借助它完全消除了任何形式的耐久性 (這是Sentry工作的一個(gè)非常可接受的方式)。

操作非常簡(jiǎn)單,每當(dāng)一個(gè)更新進(jìn)來我們就做如下幾步:

  • ??? 創(chuàng)建一個(gè)綁定到傳入實(shí)體的哈希鍵(hash key)
  • ??? 使用HINCRBY使計(jì)數(shù)器值增加
  • ??? HSET所有的LWW數(shù)據(jù)(比如 "最后一次見到的")
  • ??? 用當(dāng)前時(shí)間戳ZADD哈希鍵(hash key)到一個(gè)"掛起" set

現(xiàn)在每一個(gè)時(shí)間刻度 (在Sentry中為10秒鐘) 我們要轉(zhuǎn)儲(chǔ)(dump)這些緩沖區(qū)并且扇出寫道(fanout the writes)。 看起來像下面這樣:

  • ??? 使用ZRANGE獲取所有的key
  • ??? 為每一個(gè)掛起的key發(fā)起一個(gè)作業(yè)到RabbitMQ

?

現(xiàn)在RabbitMQ作業(yè)將能夠讀取和清除哈希表,和“懸而未決”更新已經(jīng)彈出了一套。有幾件事情需要注意:

  • ??? 在下面我們想要只彈出一個(gè)設(shè)置的數(shù)量的例子中我們將使用一組排序(舉例來說我們需要那100個(gè)舊集合)。
  • ??? 假使我們?yōu)榱颂幚硪粋€(gè)鍵值來結(jié)束多道排序的作業(yè),這個(gè)人會(huì)得到no-oped由于另一個(gè)已經(jīng)存在的處理和清空哈希的過程。
  • ??? 該系統(tǒng)能夠在許多Redis節(jié)點(diǎn)上不斷擴(kuò)展下去僅僅是通過在每個(gè)節(jié)點(diǎn)上安置把一個(gè)'懸置'主鍵來實(shí)現(xiàn)。

我們有了這個(gè)處理問題的模型之后,能夠確保“大部分情況下”每次在SQL中只有一行能夠被馬上更新,而這樣的處理方式減輕了我們能夠預(yù)見到的鎖問題。考慮到將會(huì)處理一個(gè)突然產(chǎn)生且所有最終組合在一起進(jìn)入同一個(gè)計(jì)數(shù)器的數(shù)據(jù)的場(chǎng)景,這種策略對(duì)Sentry用處很多。

速度限制

出于哨兵的局限性,我們必須終結(jié)持續(xù)的拒絕服務(wù)攻擊。我們通過限制連接速度來應(yīng)對(duì)這種問題,其中一項(xiàng)是通過Redis支持的。這無疑是在sentry.quotas范圍內(nèi)更直接的實(shí)現(xiàn)。

它的邏輯相當(dāng)直接,如同下面展示的那般:

?

def incr_and_check_limit(user_id, limit):  key = '{user_id}:{epoch}'.format(user_id, int(time() / 60))   pipe = redis.pipeline()  pipe.incr(key)  pipe.expire(key, 60)  current_rate, _ = pipe.execute()   return int(current_rate) > limit

我們所闡明的限制速率的方法是 Redis在高速緩存服務(wù)上最基本的功能之一:增加空的鍵字。在高速緩存服務(wù)中實(shí)現(xiàn)同樣的行為可能最終使用這種方法:
?

def incr_and_check_limit_memcache(user_id, limit):  key = '{user_id}:{epoch}'.format(user_id, int(time() / 60))   if cache.add(key, 0, 60):    return False   current_rate = cache.incr(key)   return current_rate > limit

事實(shí)上我們最終采取這種策略可以使哨兵追蹤不同事件的短期數(shù)據(jù)。在這種情況下,我們通常對(duì)用戶數(shù)據(jù)進(jìn)行排序以便可以在最短的時(shí)間內(nèi)找到最活躍用戶的數(shù)據(jù)。

基本鎖

雖然Redis的是可用性不高,我們的用例鎖,使其成為工作的好工具。我們沒有使用這些在哨兵的核心了,但一個(gè)示例用例是,我們希望盡量減少并發(fā)性和簡(jiǎn)單無操作的操作,如果事情似乎是已經(jīng)在運(yùn)行。這對(duì)于可能需要執(zhí)行每隔一段時(shí)間類似cron任務(wù)非常有用,但不具備較強(qiáng)的協(xié)調(diào)。
在Redis的這樣使用SETNX操作是相當(dāng)簡(jiǎn)單的:
?

from contextlib import contextmanagerr = Redis()@contextmanagerdef lock(key, nowait=True):  while not r.setnx(key, '1'):    if nowait:      raise Locked('try again soon!')    sleep(0.01)   # limit lock time to 10 seconds  r.expire(key, 10)   # do something crazy  yield   # explicitly unlock  r.delete(key)

而鎖()內(nèi)的哨兵利用的memcached的,但絕對(duì)沒有理由我們不能在其切換到Redis。

時(shí)間序列數(shù)據(jù)

近來我們創(chuàng)造一個(gè)新的機(jī)制在Sentry(包含在sentry.tsdb中)存儲(chǔ)時(shí)間序列數(shù)據(jù)。這是受RRD模型啟發(fā),特別是Graphite。我們期望一個(gè)快速簡(jiǎn)單的方式存儲(chǔ)短期(比如一個(gè)月)時(shí)間序列數(shù),以便于處理高速寫入數(shù)據(jù),特別是在極端情況下計(jì)算潛在的短期速率。盡管這是第一個(gè)模型,我們依舊期望在Redis存儲(chǔ)數(shù)據(jù),它也是使用計(jì)數(shù)器的簡(jiǎn)單范例。

在目前的模型中,我們使用單一的hash map來存儲(chǔ)全部時(shí)間序列數(shù)據(jù)。例如,這意味所有數(shù)據(jù)項(xiàng)在都將同一個(gè)哈希鍵擁有一個(gè)數(shù)據(jù)類型和1秒的生命周期。如下所示:

?

復(fù)制代碼 代碼如下:

{
??? "::": {
??????? "":
??? }}

?


因此在這種狀況,我們需要追蹤事件的數(shù)目。事件類型映射到枚舉類型"1".該判斷的時(shí)間是1s,因此我們的處理時(shí)間需要以秒計(jì)。散列最終看起來是這樣的:

復(fù)制代碼 代碼如下:
?
{
??? "1:1399958363:0": {
??????? "1": 53,
??????? "2": 72,
??? }}

?

一個(gè)可修改模型可能僅使用簡(jiǎn)單的鍵并且僅在存儲(chǔ)區(qū)上增加一些增量寄存器。

??

復(fù)制代碼 代碼如下:
"1:1399958363:0:1": 53

?

我們選擇哈希映射模型基于以下兩個(gè)原因:

  1. ??? 我們可以將所有的鍵設(shè)為一次性的(這也可能產(chǎn)生負(fù)面影響,但是目前為止是穩(wěn)定的)
  2. ??? 大幅壓縮鍵值,這是相當(dāng)重要的處理

此外,離散的數(shù)字鍵允許我們?cè)趯⑻摂M的離散鍵值映射到固定數(shù)目的鍵值上,并在此分配單一存儲(chǔ)區(qū)(我們可以使用64,映射到32個(gè)物理結(jié)點(diǎn)上)


現(xiàn)在通過使用 Nydus和它的map()(依賴于一個(gè)工作區(qū))(),數(shù)據(jù)查詢已經(jīng)完成。這次操作的代碼是相當(dāng)健壯的,但幸好它并不龐大。

?

def get_range(self, model, keys, start, end, rollup=None):  """  To get a range of data for group ID=[1, 2, 3]:  Start and end are both inclusive.  >>> now = timezone.now()  >>> get_keys(tsdb.models.group, [1, 2, 3],  >>>     start=now - timedelta(days=1),  >>>     end=now)  """  normalize_to_epoch = self.normalize_to_epoch  normalize_to_rollup = self.normalize_to_rollup  make_key = self.make_key   if rollup is None:    rollup = self.get_optimal_rollup(start, end)   results = []  timestamp = end  with self.conn.map() as conn:    while timestamp >= start:      real_epoch = normalize_to_epoch(timestamp, rollup)      norm_epoch = normalize_to_rollup(timestamp, rollup)       for key in keys:        model_key = self.get_model_key(key)        hash_key = make_key(model, norm_epoch, model_key)        results.append((real_epoch, key, conn.hget(hash_key, model_key)))       timestamp = timestamp - timedelta(seconds=rollup)   results_by_key = defaultdict(dict)  for epoch, key, count in results:    results_by_key[key][epoch] = int(count or 0)   for key, points in results_by_key.iteritems():    results_by_key[key] = sorted(points.items())  return dict(results_by_key)

歸結(jié)如下:

  • ??? 生成所必須的鍵。
  • ??? 使用工作區(qū),提取所有連接操作的最小結(jié)果集(Nydus負(fù)責(zé)這些)。
  • ??? 給出結(jié)果,并且基于指定的時(shí)間間隔內(nèi)和給定的鍵值將它們映射到當(dāng)前的存儲(chǔ)區(qū)內(nèi)。

簡(jiǎn)單的選擇

我是一個(gè)喜歡用簡(jiǎn)單的方案解決問題的人,在這個(gè)范疇里使用Redis無疑是很適合的。它的文檔是那樣讓人驚訝,那是因?yàn)椋ㄩ喿x)其文檔的門檻非常的低。雖然他也有折衷(主要是如果你使用持久化),但是他們工作地很好并且比較直觀。

那么Redis為您解決什么問題呢?如果大家想了解更多相關(guān)內(nèi)容,請(qǐng)持續(xù)關(guān)注本站,本站小編將在第一時(shí)間為大家?guī)砀玫慕?jīng)典內(nèi)容。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 天长市| 华宁县| 加查县| 新和县| 专栏| 南开区| 绥江县| 林口县| 蒙山县| 张掖市| 多伦县| 泌阳县| 桐乡市| 柳州市| 潼南县| 宁晋县| 巩留县| 湘乡市| 邢台县| 沂源县| 永寿县| 巴彦县| 巴南区| 浙江省| 建德市| 齐齐哈尔市| 繁昌县| 宜昌市| 韶山市| 卫辉市| 彭山县| 山东| 普兰县| 荣成市| 宁武县| 信宜市| 泸水县| 博乐市| 门头沟区| 遂川县| 固原市|