利用Redis實現(xiàn)SQL伸縮的方法

熱門標簽:天音通信電話機器人 高德地圖標注商家在哪 江西南昌百應電話機器人 400電話從哪里申請濱州 hbuilder地圖標注 隨州營銷電話機器人怎么樣 機器人電話機創(chuàng)意繪畫 400電話申請怎么看 杭州400電話如何申請的

這篇文章主要介紹了利用Redis實現(xiàn)SQL伸縮的方法,包括講到了鎖和時間序列等方面來提升傳統(tǒng)數(shù)據(jù)庫的性能,需要的朋友可以參考下。

緩解行競爭

我們在Sentry開發(fā)的早起采用的是sentry.buffers。 這是一個簡單的系統(tǒng),它允許我們以簡單的Last Write Wins策略來實現(xiàn)非常有效的緩沖計數(shù)器。 重要的是,我們借助它完全消除了任何形式的耐久性 (這是Sentry工作的一個非??山邮艿姆绞?。

操作非常簡單,每當一個更新進來我們就做如下幾步:

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

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

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

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

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

我們有了這個處理問題的模型之后,能夠確?!按蟛糠智闆r下”每次在SQL中只有一行能夠被馬上更新,而這樣的處理方式減輕了我們能夠預見到的鎖問題??紤]到將會處理一個突然產(chǎn)生且所有最終組合在一起進入同一個計數(shù)器的數(shù)據(jù)的場景,這種策略對Sentry用處很多。

速度限制

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

它的邏輯相當直接,如同下面展示的那般:

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在高速緩存服務上最基本的功能之一:增加空的鍵字。在高速緩存服務中實現(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ù)據(jù)。在這種情況下,我們通常對用戶數(shù)據(jù)進行排序以便可以在最短的時間內(nèi)找到最活躍用戶的數(shù)據(jù)。

基本鎖

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

在Redis的這樣使用SETNX操作是相當簡單的:

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的,但絕對沒有理由我們不能在其切換到Redis。
時間序列數(shù)據(jù)

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

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

{ 
 
  "type enum>:epoch>:shard number>": { 
 
    "id>": count> 
 
  }} 

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

 { 
 
  "1:1399958363:0": { 
 
    "1": 53, 
 
    "2": 72, 
 
  }} 

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

"1:1399958363:0:1": 53 

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

我們可以將所有的鍵設為一次性的(這也可能產(chǎn)生負面影響,但是目前為止是穩(wěn)定的)

大幅壓縮鍵值,這是相當重要的處理

此外,離散的數(shù)字鍵允許我們在將虛擬的離散鍵值映射到固定數(shù)目的鍵值上,并在此分配單一存儲區(qū)(我們可以使用64,映射到32個物理結(jié)點上)

現(xiàn)在通過使用 Nydus和它的map()(依賴于一個工作區(qū))(),數(shù)據(jù)查詢已經(jī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負責這些)。
  • 給出結(jié)果,并且基于指定的時間間隔內(nèi)和給定的鍵值將它們映射到當前的存儲區(qū)內(nèi)。

以上就是如何利用Redis實現(xiàn)SQL伸縮的方法,希望對大家的學習有所幫助。

您可能感興趣的文章:
  • 在Ruby on Rails上使用Redis Store的方法
  • python操作redis的方法
  • php-redis中的sort排序函數(shù)總結(jié)
  • Redis sort 排序命令詳解
  • 圖文介紹PHP添加Redis模塊及連接
  • 在Mac下如何安裝phpredis擴展
  • 詳解Redis中的雙鏈表結(jié)構(gòu)
  • Redis中的動態(tài)字符串學習教程
  • Windows下Redis的安裝使用圖解
  • Redis的11種Web應用場景簡介
  • 用Redis實現(xiàn)微博關注關系

標簽:常德 保定 石嘴山 葫蘆島 鶴崗 招商 沈陽 昆明

巨人網(wǎng)絡通訊聲明:本文標題《利用Redis實現(xiàn)SQL伸縮的方法》,本文關鍵詞  利用,Redis,實現(xiàn),SQL,伸縮,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡,涉及言論、版權(quán)與本站無關。
  • 相關文章
  • 下面列出與本文章《利用Redis實現(xiàn)SQL伸縮的方法》相關的同類信息!
  • 本頁收集關于利用Redis實現(xiàn)SQL伸縮的方法的相關信息資訊供網(wǎng)民參考!
  • 推薦文章