PHP+MySQL 千萬級資料處理案例(一)

huxiaobai_001發表於2020-04-12

廢話少說 直接進入場景
一個金融公司有500w投資使用者,每天充值投資50w筆,那麼該公司每年將近有1億條充值記錄,那麼我們改如何處理這個充值訂單表的資料呢?難不成都放一張表裡面,那萬一哪天我讓你去統計滿足某個需求的記錄,1億條資料裡面檢索你會累死mysql的!今天我們就來講述一下如何去處理這種情況。

mysql分散式之分表思路
分表不是隨隨便便就分表,必須要結合專案的實際情況,比如我們的專案的瓶頸在哪裡,區區幾千幾萬幾十萬或者幾百萬的資料用分表那就是高射炮打蚊子了,不要盲目的分表!必須要達到一定的數量級,並且影響了我們的使用者的訪問速度,效能下降的情況下才能考慮去做分表處理!
我們來畫個簡單的不能再簡單的圖吧,我喜歡畫圖

分表的思路就是如此簡單,藉助中介軟體可以根據不同省份的訂單插入到不同省份對應的表當中去,當然實際當中還得要結合自身的業務來尋找製作這個中介軟體,不要照搬人家的邏輯思路!
就比如12306當年總是奔潰一樣,全國這麼多條鐵路線路,在早上八點同時放出搶票,幾億人去搶,再牛逼的技術也很難抵擋,當然阿里很牛逼哈,當時就很多人為他們出謀劃策,提供各種方案,說什麼人家淘寶天貓京東都這麼搞的,他媽的又不瞭解人家12306的實際業務很多人瞎逼逼,後來12306不也是採用分發的這種形式,錯峰釋出各個鐵路班線的搶票,緩解了大流量帶來的巨大沖擊,所以一定要結合自身實際的業務去做各種方案,就跟這裡的中介軟體一樣!不廢話了!

mysql分散式之分表實戰(插入總表分然後取模分發到分表)

//虛擬碼
//假設使用者資料入庫 定為每天50w的資料量入庫
//我們建立一張使用者主表+兩張使用者分表  使用者分表user0 使用者分表user1
//首先所有使用者資料入使用者主表
$sql = insert into users(a,b,c) values($a,$b,$c);
$res = $model->query($sql);
if($res){
    //獲取user主表插入的最後一條sql的id
    $insert_id = $model->getLastInsId();
    //對剛才入庫成功的記錄的id取模 如果你是兩種使用者分表那麼就%2如果是200張那麼就%200
    $d = $insert_id%2;
    //取模之後 獲取到最後的模 任何數對2取模那麼不是0就是1 任何數對200取模那麼模就是0到200之間
    //插入到不同的使用者分表當中去
    $_sql = insert into user{$d} (a,b,c) values($a,$b,$c);
    $ru = $model->query($_sql);
}

其實我們是利用了取模的形式做了一箇中介軟體的功能,根據模的數值去往不同的user0還有user1當中插入資料,達到了分發的效果
整個過程user主表一定是先插入資料的,然後根據模再去往不同的分表裡面插資料;
需要強調的是user分表裡面的user_id主鍵一定不是自增的,一定是根據user主表裡面的id來插入的,必須保證和主表裡面的主鍵id保持一致!
需要強調的是user主表和user0 user1分表一定是欄位屬性相同的直接複製即可,只是把資料分發到不同的表裡面去了,這也叫水平分表!

在做mysql的水平分表的時候要記住,潛規則,預設的新增的時候我們插入到user主表然後根據取模插入到不同的分表裡面去,但是刪除,修改,檢視,都和主表沒關係了,主表只有在新增的時候往裡面寫入資料根據id取模再分發到不同的分表裡面去!當然主表也可以做一些其他方面的統計。

mysql分散式之分表實戰(修改檢視刪除分表資料)
上邊我們講過,修改刪除查詢的時候直接操作的是分表,不再去動主表

//虛擬碼
$id = $_POST['id'];
//對主鍵id取模從而來判斷操作哪張分表
$d = $id%2;
$sql = update user{$d} set username='{$username}',age='{$age}' where id = $id;
$model->query($sql);

修改刪除也是根據主鍵id對其取模確定下來針對哪張分表進行修改或者刪除
但是我們刪除或者修改了那麼主表裡面的資料也就和分表裡面的不一致了啊,如何保證主表和從表資料一致呢?
很多人會想在操作完分表之後立馬去操作主表做修改操作不得了,也行啊!但是不感覺浪費嗎?如果你學會了協程那麼可以起一個協程去操作主表即可,或者起一個非同步task任務去操作主表也可以,都是非同步執行不影響程式的執行,這是非常好的做法,前提是你得懂什麼是協程以及swoole裡面的task非同步任務,之前部落格裡面有講,可以去翻翻我的部落格。
另外還有一種老套的方式就是利用佇列的形式,不,不,不,不,不叫佇列,redis裡面的list,充其量叫列表,redis5才新增了一種新的型別stream型別那才是真正的佇列,是相當於乞丐版的kafka,利用redis裡面的list型別,將修改分表的sql語句改成修改主表的sql,條件一直 id一直 只是操作的表為主表即可,然後塞到list列表裡面去 lpush 然後弄個定時任務rpop去更新主表即可!這種方法很笨哦,但是也管用!

剛開始就說了一定要結合實際的業務需求,我們上邊講到的是按照主鍵id進行的資料的分發到不同的分表當中,所以不管是查詢修改還是刪除都要結合主鍵id去確定要操作的分表才行,有一定的侷限性,但是我們的實際業務就是這麼設計的,所以還是那句嘮嘮叨叨的話,一定要結合自己的實際業務需求;

分表並不是最優的解決方案,並且在實際的應用當中使用不不是很廣泛,存在就有道理,主要還是看你的業務需求啦哦!

本作品採用《CC 協議》,轉載必須註明作者和本文連結

胡軍

相關文章