程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> Mysql機能優化案例研討-籠罩索引和SQL_NO_CACHE

Mysql機能優化案例研討-籠罩索引和SQL_NO_CACHE

編輯:MySQL綜合教程

Mysql機能優化案例研討-籠罩索引和SQL_NO_CACHE。本站提示廣大學習愛好者:(Mysql機能優化案例研討-籠罩索引和SQL_NO_CACHE)文章只能為提供參考,不一定能成為您想要的結果。以下是Mysql機能優化案例研討-籠罩索引和SQL_NO_CACHE正文


這篇文章重要引見了應用Redis完成SQL伸縮的辦法,包含講到了鎖和時光序列等方面來晉升傳統數據庫的機能,須要的同伙可以參考下。

減緩行競爭

我們在Sentry開辟的夙興采取的是sentry.buffers。 這是一個簡略的體系,它許可我們以簡略的Last Write Wins戰略來完成異常有用的緩沖計數器。 主要的是,我們借助它完整清除了任何情勢的經久性 (這是Sentry任務的一個異常可接收的方法)。

操作異常簡略,每當一個更新出去我們就做以下幾步:

  • 創立一個綁定到傳入實體的哈希鍵(hash key)
  • 應用HINCRBY使計數器值增長
  • HSET一切的LWW數據(好比 "最初一次見到的")
  • 用以後時光戳ZADD哈希鍵(hash key)到一個"掛起" set

如今每個時光刻度 (在Sentry中為10秒鐘) 我們要轉儲(dump)這些緩沖區而且扇出寫道(fanout the writes)。 看起來像上面如許:

  • 應用ZRANGE獲得一切的key
  • 為每個掛起的key提議一個功課到RabbitMQ

如今RabbitMQ功課將可以或許讀取和消除哈希表,和“懸而未決”更新曾經彈出了一套。有幾件工作須要留意:

  • 鄙人面我們想要只彈出一個設置的數目的例子中我們將應用一組排序(舉例來講我們須要那100個舊聚集)。
  • 借使我們為了處置一個鍵值來停止多道排序的功課,這小我會獲得no-oped因為另外一個曾經存在的處置和清空哈希的進程。
  • 該體系可以或許在很多Redis節點上赓續擴大下去僅僅是經由過程在每一個節點上安頓把一個'懸置'主鍵來完成。

我們有了這個處置成績的模子以後,可以或許確保“年夜部門情形下”每次在SQL中只要一行可以或許被立時更新,而如許的處置方法加重了我們可以或許預感到的鎖成績。斟酌到將會處置一個忽然發生且一切終究組合在一路進入統一個計數器的數據的場景,這類戰略對Sentry用途許多。

速度限制

出於尖兵的局限性,我們必需終結連續的謝絕辦事進擊。我們經由過程限制銜接速度來應對這類成績,個中一項是經由過程Redis支撐的。這無疑是在sentry.quotas規模內更直接的完成。

它的邏輯相當直接,好像上面展現的那般:

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在高速緩存辦事上最根本的功效之一:增長空的鍵字。在高速緩存辦事中完成異樣的行動能夠終究應用這類辦法:

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 

現實上我們終究采用這類戰略可使尖兵追蹤分歧事宜的短時間數據。在這類情形下,我們平日對用戶數據停止排序以即可以在最短的時光內找到最活潑用戶的數據。

根本鎖

固然Redis的是可用性不高,我們的用例鎖,使其成為任務的好對象。我們沒有應用這些在尖兵的焦點了,但一個示例用例是,我們願望盡可能削減並發性和簡略無操作的操作,假如工作仿佛是曾經在運轉。這關於能夠須要履行每隔一段時光相似cron義務異常有效,但不具有較強的調和。

在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) 

而鎖()內的尖兵應用的memcached的,但相對沒有來由我們不克不及在其切換到Redis。
時光序列數據

最近我們發明一個新的機制在Sentry(包括在sentry.tsdb中) 存儲時光序列數據。這是受RRD模子啟示,特殊是Graphite。我們希冀一個疾速簡略的方法存儲短時間(好比一個月)時光序列數,以便於處置高速寫入數據,特殊是在極端情形下盤算潛伏的短時間速度。雖然這是第一個模子,我們照舊希冀在Redis存儲數據,它也是應用計數器的簡略典范。

在今朝的模子中,我們應用單一的hash map來存儲全體時光序列數據。例如,這意味一切數據項在都將統一個哈希鍵具有一個數據類型和1秒的性命周期。以下所示:

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

是以在這類狀態,我們須要追蹤事宜的數量。事宜類型映照到列舉類型"1".該斷定的時光是1s,是以我們的處置時光須要以秒計。散列終究看起來是如許的:

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

一個可修正模子能夠僅應用簡略的鍵而且僅在存儲區上增長一些增量存放器。

"1:1399958363:0:1": 53 

我們選擇哈希映照模子基於以下兩個緣由:

我們可以將一切的鍵設為一次性的(這也能夠發生負面影響,然則今朝為止是穩固的)

年夜幅緊縮鍵值,這是相當主要的處置

另外,團圓的數字鍵許可我們在將虛擬的團圓鍵值映照到固定命目標鍵值上,並在此分派單一存儲區(我們可使用64,映照到32個物理結點上)

如今經由過程應用 Nydus和它的map()(依附於一個任務區)(),數據查詢曾經完成。此次操作的代碼是相當硬朗的,但幸虧它其實不宏大。

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) 

歸結以下:

  • 生成所必需的鍵。
  • 應用任務區,提取一切銜接操作的最小成果集(Nydus擔任這些)。
  • 給出成果,而且基於指定的時光距離內和給定的鍵值將它們映照到以後的存儲區內。

以上就是若何應用Redis完成SQL伸縮的辦法,願望對年夜家的進修有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved