自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

單KEY業(yè)務(wù),數(shù)據(jù)庫水平切分架構(gòu)實踐

開發(fā) 開發(fā)工具
將以“用戶中心”為典型的“單KEY”類業(yè)務(wù),水平切分的架構(gòu)點,本文做了這樣一些介紹。

本文將以“用戶中心”為例,介紹“單KEY”類業(yè)務(wù),隨著數(shù)據(jù)量的逐步增大,數(shù)據(jù)庫性能顯著降低,數(shù)據(jù)庫水平切分相關(guān)的架構(gòu)實踐:

  • 如何來實施水平切分
  • 水平切分后常見的問題
  • 典型問題的優(yōu)化思路及實踐

一、用戶中心

用戶中心是一個非常常見的業(yè)務(wù),主要提供用戶注冊、登錄、信息查詢與修改的服務(wù),其核心元數(shù)據(jù)為:

  1. User(uid, login_name, passwd, sex, age, nickname, …) 

其中:

  • uid為用戶ID,主鍵
  • login_name, passwd, sex, age, nickname, …等用戶屬性

數(shù)據(jù)庫設(shè)計上,一般來說在業(yè)務(wù)初期,單庫單表就能夠搞定這個需求,典型的架構(gòu)設(shè)計為:

單庫單表

  • user-center:用戶中心服務(wù),對調(diào)用者提供友好的RPC接口
  • user-db:對用戶進(jìn)行數(shù)據(jù)存儲

二、用戶中心水平切分方法

當(dāng)數(shù)據(jù)量越來越大時,需要對數(shù)據(jù)庫進(jìn)行水平切分,常見的水平切分算法有“范圍法”和“哈希法”。

范圍法,以用戶中心的業(yè)務(wù)主鍵uid為劃分依據(jù),將數(shù)據(jù)水平切分到兩個數(shù)據(jù)庫實例上去:

平切分算法“范圍法”

  • user-db1:存儲0到1千萬的uid數(shù)據(jù)
  • user-db2:存儲1到2千萬的uid數(shù)據(jù)

范圍法的優(yōu)點是:

  • 切分策略簡單,根據(jù)uid,按照范圍,user- center很快能夠定位到數(shù)據(jù)在哪個庫上
  • 擴(kuò)容簡單,如果容量不夠,只要增加user-db3即可

范圍法的不足是:

  • uid必須要滿足遞增的特性
  • 數(shù)據(jù)量不均,新增的user-db3,在初期的數(shù)據(jù)會比較少
  • 請求量不均,一般來說,新注冊的用戶活躍度會比較高,故user-db2往往會比user-db1負(fù)載要高,導(dǎo)致服務(wù)器利用率不平衡

哈希法,也是以用戶中心的業(yè)務(wù)主鍵uid為劃分依據(jù),將數(shù)據(jù)水平切分到兩個數(shù)據(jù)庫實例上去:

哈希法

  • user-db1:存儲uid取模得1的uid數(shù)據(jù)
  • user-db2:存儲uid取模得0的uid數(shù)據(jù)

哈希法的優(yōu)點是:

  • 切分策略簡單,根據(jù)uid,按照hash,user-center很快能夠定位到數(shù)據(jù)在哪個庫上
  • 數(shù)據(jù)量均衡,只要uid是均勻的,數(shù)據(jù)在各個庫上的分布一定是均衡的
  • 請求量均衡,只要uid是均勻的,負(fù)載在各個庫上的分布一定是均衡的

哈希法的不足是:

  • 擴(kuò)容麻煩,如果容量不夠,要增加一個庫,重新hash可能會導(dǎo)致數(shù)據(jù)遷移,如何平滑的進(jìn)行數(shù)據(jù)遷移,是一個需要解決的問題

三、用戶中心水平切分后帶來的問題

使用uid來進(jìn)行水平切分之后,整個用戶中心的業(yè)務(wù)訪問會遇到什么問題呢?

對于uid屬性上的查詢可以直接路由到庫,假設(shè)訪問uid=124的數(shù)據(jù),取模后能夠直接定位db-user1:

對于uid屬性上的查詢可以直接路由到庫

對于非uid屬性上的查詢,例如login_name屬性上的查詢,就悲劇了:

對于非uid屬性上的查詢,例如login_name屬性上的查詢,就悲劇了

假設(shè)訪問login_name=shenjian的數(shù)據(jù),由于不知道數(shù)據(jù)落在哪個庫上,往往需要遍歷所有庫,當(dāng)分庫數(shù)量多起來,性能會顯著降低。

如何解決分庫后,非uid屬性上的查詢問題,是后文要重點討論的內(nèi)容。

四、用戶中心非uid屬性查詢需求分析

任何脫離業(yè)務(wù)的架構(gòu)設(shè)計都是耍流氓,在進(jìn)行架構(gòu)討論之前,先來對業(yè)務(wù)進(jìn)行簡要分析,看非uid屬性上有哪些查詢需求。

根據(jù)樓主這些年的架構(gòu)經(jīng)驗,用戶中心非uid屬性上經(jīng)常有兩類業(yè)務(wù)需求:

(1)用戶側(cè),前臺訪問,最典型的有兩類需求

  • 用戶登錄:通過login_name/phone/email查詢用戶的實體,1%請求屬于這種類型
  • 用戶信息查詢:登錄之后,通過uid來查詢用戶的實例,99%請求屬這種類型

用戶側(cè)的查詢基本上是單條記錄的查詢,訪問量較大,服務(wù)需要高可用,并且對一致性的要求較高。

(2)運(yùn)營側(cè),后臺訪問,根據(jù)產(chǎn)品、運(yùn)營需求,訪問模式各異,按照年齡、性別、頭像、登陸時間、注冊時間來進(jìn)行查詢。

運(yùn)營側(cè)的查詢基本上是批量分頁的查詢,由于是內(nèi)部系統(tǒng),訪問量很低,對可用性的要求不高,對一致性的要求也沒這么嚴(yán)格。

這兩類不同的業(yè)務(wù)需求,應(yīng)該使用什么樣的架構(gòu)方案來解決呢?

五、用戶中心水平切分架構(gòu)思路

用戶中心在數(shù)據(jù)量較大的情況下,使用uid進(jìn)行水平切分,對于非uid屬性上的查詢需求,架構(gòu)設(shè)計的核心思路為:

  • 針對用戶側(cè),應(yīng)該采用“建立非uid屬性到uid的映射關(guān)系”的架構(gòu)方案
  • 針對運(yùn)營側(cè),應(yīng)該采用“前臺與后臺分離”的架構(gòu)方案

六、用戶中心-用戶側(cè)最佳實踐

【索引表法】

思路:uid能直接定位到庫,login_name不能直接定位到庫,如果通過login_name能查詢到uid,問題解決

解決方案:

  • 建立一個索引表記錄login_name->uid的映射關(guān)系
  • 用login_name來訪問時,先通過索引表查詢到uid,再定位相應(yīng)的庫
  • 索引表屬性較少,可以容納非常多數(shù)據(jù),一般不需要分庫
  • 如果數(shù)據(jù)量過大,可以通過login_name來分庫

潛在不足:多一次數(shù)據(jù)庫查詢,性能下降一倍

【緩存映射法】

思路:訪問索引表性能較低,把映射關(guān)系放在緩存里性能更佳

解決方案:

  • login_name查詢先到cache中查詢uid,再根據(jù)uid定位數(shù)據(jù)庫
  • 假設(shè)cache miss,采用掃全庫法獲取login_name對應(yīng)的uid,放入cache
  • login_name到uid的映射關(guān)系不會變化,映射關(guān)系一旦放入緩存,不會更改,無需淘汰,緩存命中率超高
  • 如果數(shù)據(jù)量過大,可以通過login_name進(jìn)行cache水平切分

潛在不足:多一次cache查詢

【login_name生成uid】

思路:不進(jìn)行遠(yuǎn)程查詢,由login_name直接得到uid

解決方案:

  • 在用戶注冊時,設(shè)計函數(shù)login_name生成uid,uid=f(login_name),按uid分庫插入數(shù)據(jù)
  • 用login_name來訪問時,先通過函數(shù)計算出uid,即uid=f(login_name)再來一遍,由uid路由到對應(yīng)庫

潛在不足:該函數(shù)設(shè)計需要非常講究技巧,有uid生成沖突風(fēng)險

【login_name基因融入uid】

思路:不能用login_name生成uid,可以從login_name抽取“基因”,融入uid中

假設(shè)分8庫,采用uid%8路由,潛臺詞是,uid的最后3個bit決定這條數(shù)據(jù)落在哪個庫上,這3個bit就是所謂的“基因”。

解決方案:

  • 在用戶注冊時,設(shè)計函數(shù)login_name生成3bit基因,login_name_gene=f(login_name),如上圖粉色部分
  • 同時,生成61bit的全局唯一id,作為用戶的標(biāo)識,如上圖綠色部分
  • 接著把3bit的login_name_gene也作為uid的一部分,如上圖屎黃色部分
  • 生成64bit的uid,由id和login_name_gene拼裝而成,并按照uid分庫插入數(shù)據(jù)
  • 用login_name來訪問時,先通過函數(shù)由login_name再次復(fù)原3bit基因,login_name_gene=f(login_name),通過login_name_gene%8直接定位到庫

七、用戶中心-運(yùn)營側(cè)最佳實踐

前臺用戶側(cè),業(yè)務(wù)需求基本都是單行記錄的訪問,只要建立非uid屬性 login_name / phone / email 到uid的映射關(guān)系,就能解決問題。

后臺運(yùn)營側(cè),業(yè)務(wù)需求各異,基本是批量分頁的訪問,這類訪問計算量較大,返回數(shù)據(jù)量較大,比較消耗數(shù)據(jù)庫性能。

如果此時前臺業(yè)務(wù)和后臺業(yè)務(wù)公用一批服務(wù)和一個數(shù)據(jù)庫,有可能導(dǎo)致,由于后臺的“少數(shù)幾個請求”的“批量查詢”的“低效”訪問,導(dǎo)致數(shù)據(jù)庫的cpu偶爾瞬時100%,影響前臺正常用戶的訪問(例如,登錄超時)。

而且,為了滿足后臺業(yè)務(wù)各類“奇形怪狀”的需求,往往會在數(shù)據(jù)庫上建立各種索引,這些索引占用大量內(nèi)存,會使得用戶側(cè)前臺業(yè)務(wù)uid/login_name上的查詢性能與寫入性能大幅度降低,處理時間增長。

對于這一類業(yè)務(wù),應(yīng)該采用“前臺與后臺分離”的架構(gòu)方案:

用戶側(cè)前臺業(yè)務(wù)需求架構(gòu)依然不變,產(chǎn)品運(yùn)營側(cè)后臺業(yè)務(wù)需求則抽取獨立的web / service / db 來支持,解除系統(tǒng)之間的耦合,對于“業(yè)務(wù)復(fù)雜”“并發(fā)量低”“無需高可用”“能接受一定延時”的后臺業(yè)務(wù):

  • 可以去掉service層,在運(yùn)營后臺web層通過dao直接訪問db
  • 不需要反向代理,不需要集群冗余
  • 不需要訪問實時庫,可以通過MQ或者線下異步同步數(shù)據(jù)
  • 在數(shù)據(jù)庫非常大的情況下,可以使用更契合大量數(shù)據(jù)允許接受更高延時的“索引外置”或者“HIVE”的設(shè)計方案

八、總結(jié)

將以“用戶中心”為典型的“單KEY”類業(yè)務(wù),水平切分的架構(gòu)點,本文做了這樣一些介紹。

水平切分方式:

  • 范圍法
  • 哈希法

水平切分后碰到的問題:

  • 通過uid屬性查詢能直接定位到庫,通過非uid屬性查詢不能定位到庫

非uid屬性查詢的典型業(yè)務(wù):

  • 用戶側(cè),前臺訪問,單條記錄的查詢,訪問量較大,服務(wù)需要高可用,并且對一致性的要求較高
  • 運(yùn)營側(cè),后臺訪問,根據(jù)產(chǎn)品、運(yùn)營需求,訪問模式各異,基本上是批量分頁的查詢,由于是內(nèi)部系統(tǒng),訪問量很低,對可用性的要求不高,對一致性的要求也沒這么嚴(yán)格

這兩類業(yè)務(wù)的架構(gòu)設(shè)計思路:

  • 針對用戶側(cè),應(yīng)該采用“建立非uid屬性到uid的映射關(guān)系”的架構(gòu)方案
  • 針對運(yùn)營側(cè),應(yīng)該采用“前臺與后臺分離”的架構(gòu)方案

用戶前臺側(cè),“建立非uid屬性到uid的映射關(guān)系”最佳實踐:

  • 索引表法:數(shù)據(jù)庫中記錄login_name->uid的映射關(guān)系
  • 緩存映射法:緩存中記錄login_name->uid的映射關(guān)系
  • login_name生成uid
  • login_name基因融入uid

運(yùn)營后臺側(cè),“前臺與后臺分離”最佳實踐:

  • 前臺、后臺系統(tǒng)web/service/db分離解耦,避免后臺低效查詢引發(fā)前臺查詢抖動
  • 可以采用數(shù)據(jù)冗余的設(shè)計方式
  • 可以采用“外置索引”(例如ES搜索系統(tǒng))或者“大數(shù)據(jù)處理”(例如HIVE)來滿足后臺變態(tài)的查詢需求

【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者】

戳這里,看該作者更多好文

責(zé)任編輯:趙寧寧 來源: 51CTO專欄
相關(guān)推薦

2017-08-11 13:55:13

數(shù)據(jù)庫水平切分架構(gòu)

2017-07-11 16:44:04

數(shù)據(jù)庫水平切分架構(gòu)

2011-08-11 18:54:01

數(shù)據(jù)庫分頁查詢

2018-01-24 09:35:12

高并發(fā)數(shù)據(jù)庫設(shè)計水平切分

2018-01-29 09:50:16

數(shù)據(jù)庫設(shè)計水平切分

2017-06-10 11:13:39

數(shù)據(jù)庫架構(gòu)數(shù)據(jù)庫集群

2017-07-03 18:24:39

MySQL數(shù)據(jù)冗余

2023-11-27 07:23:39

2017-06-08 11:06:03

數(shù)據(jù)庫架構(gòu)分組

2021-04-09 08:21:25

數(shù)據(jù)庫索引數(shù)據(jù)

2019-03-06 14:42:01

數(shù)據(jù)庫分庫分表

2022-01-07 14:00:35

分庫分表業(yè)務(wù)量

2024-05-28 00:00:30

Golang數(shù)據(jù)庫

2017-06-22 16:00:07

數(shù)據(jù)庫NoSQL遷移實踐

2022-02-10 10:51:35

數(shù)據(jù)庫

2013-10-08 09:54:41

數(shù)據(jù)庫安全數(shù)據(jù)庫管理

2022-12-23 19:22:47

前端單測

2015-09-10 09:24:58

2017-11-22 09:20:41

數(shù)據(jù)庫在線數(shù)據(jù)遷移Subscriptio
點贊
收藏

51CTO技術(shù)棧公眾號