uniapp返回上一页_一例万级写入并发,百亿级数据,毫秒级返回架构分享
一交易系統(tǒng),毫秒內(nèi)就會產(chǎn)生一條交易數(shù)據(jù),有付款方,收款方,交易類型,交易符號,分別為from ,to ,type,symbol,前面玩過一下apache?phoenix 來做sql查詢《從phoenix hbase談談研發(fā)管理和技術(shù)選型》,效率還是慢了點兒,還是原生的好
從業(yè)務需求來看主要有幾個點兒:
1:交易記錄實時寫入,實時查詢,支持交易記錄多條件查詢,還能分頁,這里條件剛好比較固定,就username(交易方),type,symbol
2: ?用戶的余額要實時返回,賬目可追溯
3: 海量交易數(shù)據(jù)
這里使用了hbase作為存儲介質(zhì),當然大家也可以嘗試一下tidb
數(shù)據(jù)落地hbase寫入效率還是比較高的,但是太高有時會自動不讓寫入,寫入也是有一些參數(shù)需要優(yōu)化調(diào)整的,多條件的復合查詢對于hbase來說有時真是有點兒XX,所以rowkey的設(shè)計特別關(guān)鍵,但是rowkey并不是萬能的
hbase寫入優(yōu)化:
有很多參數(shù)優(yōu)化的帖子,根據(jù)業(yè)務實際情況動態(tài)調(diào)整,這里就不一一列舉了,這里主要講一下rowkey和數(shù)據(jù)結(jié)構(gòu)設(shè)計:
一:第一回合
String?rowkeyPrefix?=??from+"==="+to+"==="+type+"000$"+symbol+"000"+(MAXID-orderid)hbase里每個rowkey字段位數(shù)需要保持一致,不足的用=或者其他字符補齊,用戶ID?from和to的ID倒轉(zhuǎn),如13567變成76531,便于寫入數(shù)據(jù)散列到多個Region服務器上,還能保證同一個用戶是緊密挨著一起的,最后可以預見的最大訂單ID為999999999999999,具體多少個9根據(jù)你業(yè)務來定位數(shù),MAXID-orderid作為訂單的唯一標記還能按時間,訂單先后順序排序,就用不著LONG.MAX_VALUE-timestamp了,查詢訂單詳情的時候還方便查詢,訂單數(shù)據(jù)都在一張表里
嘩啦啦,開始多線程批量偽造數(shù)據(jù),PC單機每秒可達1500左右,很快數(shù)據(jù)就達到100W,通過username,type,symbol分頁查詢數(shù)據(jù),呼啦啦,還是很快的,很高興,再繼續(xù)打數(shù)據(jù),一千萬的時候,咋開始有點兒慢了,但也還是在一秒左后會返回,繼續(xù)再往后面打數(shù)據(jù)就會越來越慢,達到億級的時候就有點兒卡了,第因為查詢第一頁數(shù)據(jù)的時候是不知道startrow和endrow的,第二頁開始就可以傳startrow了,掃描范圍縮小,速度會快很多
這個時當我們?nèi)ゲ樵儐蝹€訂單詳情的時候,以為訂單唯一數(shù)字id都在rowkey里面,還只是查詢一個數(shù)據(jù)會爆快的,結(jié)果確是慢,原因是唯一id放在了rowkey的最后,hbase會從前往后挨著掃描的,一個訂單的詳情往往是不會改變的,自然是可以加一層緩存的,速度快樂
但是分頁的數(shù)據(jù)在億級的時候,特別是第一頁就慢了,當然第一頁數(shù)據(jù)并不是很多,實時redis緩存第一頁用戶的數(shù)據(jù),速度還是會比較快的,怎么實時更新呢,當新寫入數(shù)據(jù)的時候,把對應redis的第一頁列表數(shù)據(jù)也給更新了;交易詳情的redis 緩存key需要設(shè)置失效時間,不然過多的不用cache key呆內(nèi)存也不是太好的
一般情況下,這樣的第一頁分頁數(shù)據(jù)用redis提供,用戶詳情用緩存提供,第二頁以上的分頁數(shù)據(jù)用startrow提供,機器稍微配置好些,在千萬至億級的數(shù)量級,已經(jīng)夠用了
對于用戶金額的實時寫入更新,使用了redis increment的原子操作,實時自增,并落地到數(shù)據(jù)庫
二:第一回合
但是隨著數(shù)據(jù)量的越來越大,以及業(yè)務場景中用戶對于3,4秒乃至10多秒才能返回數(shù)據(jù)的情況的用戶體驗還是有一定影響的,雖然說第一頁或者用戶進來速度就是嘩嘩的,可以看起來很快,于是開始拆分
原先的一張hbase表拆分成兩張,一張表為order_record_index:rowkey值不變,只記錄訂單自增唯一id,相當于訂單索引ID
另外一張表為訂單詳情表order_detail,rowkey為訂單id
這樣設(shè)計的好處是什么呢,馬上就懂了
當查詢訂單詳情的時候,通過訂單id ,相當于是order_detail中的rowkey,hbase第一大特別,存儲海量大數(shù)據(jù),還有一個非常突出的性能表現(xiàn),那就是通過確定唯一的rowkey取值了,那是相當?shù)目?這個時候獲取訂單詳情的時候就是刷刷的了,當然你要加一個有失效時間的緩存,那也是可以的,毫秒級的返回沒問題了
第二個,通過order_record_index這張表不存儲訂單的全部數(shù)據(jù),只存儲訂單ID,數(shù)據(jù)量一下就下來了,再去查詢速度明顯快了很多,先通過rowkey找到訂單ID,在通過訂單ID批量通過order_detail rowkey獲得 交易數(shù)據(jù)詳情列表,但是這樣的情況下依然不能做到多條件下的分頁高效返回
三:第三回合
這個時候redis的有序集合就用上了,還是以索引ID的思路,hbase的兩張表結(jié)構(gòu)不變,在redis集群中維護用戶的訂單id 列表,由于多條件組合查詢相對固定,zset集合的key值為:
String?cacheKey?=??from+to+type++symbolredis的cachekey就沒有像hbase rowkey那樣補齊了,盡量節(jié)約空間,然后新增訂單數(shù)據(jù)的時候,實時刷新redis cachekey的用戶訂單id
redistemplate.opsforzset.add(cacheKey,Bytes.toBytes(order_id),order_id);這里,value值為bytes,取出來的時候不需要循環(huán)再轉(zhuǎn),直接批量通過hbase查詢,因為hbase的rowkey?是bytes的
分頁的時候怎么辦呢,更好用:
Object?o?=?redisTemplate.opsforzset.zrange(cachekey,(page-1)*pageSize,page*pageSize);有同學會問,數(shù)據(jù)量那么大,redis分頁好用嘛,這個得結(jié)合業(yè)務場景來,總的訂單數(shù)據(jù)量很大,但是每個用戶的訂單數(shù)據(jù)量是有限的,那么根據(jù)單個用戶量去做zrange,效率自然沒問題,redis可以根據(jù)數(shù)據(jù)量做集群或者自己根據(jù)cachekey做hash,理論上是可以無限擴展的,這樣我們拿到該分頁數(shù)據(jù)的rowkey list后,直接去hbase order_detail表中批量抓取,刷的一下就出來了,充分利用了hbase rowkey查詢和redis zset分頁的效果
這個時候是不是就ok了呢,不是,萬一redis掛了怎么辦,你的列表數(shù)據(jù)都在redis里
這個時候會去hbase的order_record_index的索引表里獲取查詢,也就是redis還是輕量級的可持久化的緩存系統(tǒng),數(shù)據(jù)落地還是需要在hbase中
當redis索引失效的時候,可以通過hbase中的索引id列表重建索引,可以單個用戶重建,也可以批量重建,因為是zset集合,批量重建并不會出現(xiàn)數(shù)據(jù)錯誤,訂單增加之類的情況
這樣,一個在海量數(shù)據(jù)的情況下,依然可以做到不到秒級的多條件下數(shù)據(jù)分頁數(shù)據(jù)返回
當然,你還可以嘗試elasticsearch構(gòu)建索引,通過hbase查詢數(shù)據(jù)的方式構(gòu)建
這里面也還有很多細節(jié)參數(shù)可以優(yōu)化,隨著業(yè)務的發(fā)展不斷進化,歡迎留言討論完善
相關(guān)閱讀:
億級(無限級)并發(fā),沒那么難
不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)
如何成為一個騷氣的架構(gòu)師,看這一篇就夠了
關(guān)于高大上的DDD,白話入門篇
后端,你再不懂vue就out了
總結(jié)
以上是生活随笔為你收集整理的uniapp返回上一页_一例万级写入并发,百亿级数据,毫秒级返回架构分享的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win10找不到网络路径如何解决
- 下一篇: Laravel8.5是怎么添加验证码me