前言
最近快到畢業(yè)答辯的時候,我自己的論文也完成了查重涩哟,并且已經(jīng)提交到知網(wǎng)平臺。自己做的是一個電商項目盼玄,基本的功能都已實現(xiàn)染簇。當時為了偷懶,直接是copy的慕課網(wǎng)上Spring電商的一個項目强岸,自己在此基礎(chǔ)改了幾個星期锻弓,真心覺得代碼寫的爛。代碼很多程度上違反了迪米特蝌箍,合成復(fù)用青灼,依賴倒置等原則。整體架構(gòu)距離一致性妓盲,可用性杂拨,容錯性有很大的差距。后期有時間悯衬,我會用Spring Cloud拆分整體模塊弹沽,代碼重構(gòu)。
項目存在的問題
1.20張表都是基礎(chǔ)的CRUD。表與表之間的關(guān)系沒有通過連接或者是嵌套進行關(guān)聯(lián)策橘,而是很大程序依賴去lambda代碼去進行連接炸渡,導(dǎo)致效率很低。
2.使用Timer進行任務(wù)調(diào)度不當(沒有合理設(shè)置initialDelay時間或者是沒有設(shè)置異步)丽已,會造成Eden區(qū)和Survivor區(qū)使用率太高蚌堵,CPU占有率太高,嚴重影響性能沛婴,造成Tomcat響應(yīng)速度很慢吼畏。建議用ScheduledExecutorService代替Timer,另外要注意newScheduledThreadPool的最大線程數(shù)是Integer.MAX_VALUE嘁灯。使用的工作隊列是DelayedWorkQueue泻蚊,它是一個無界隊列,會一直去消耗CPU性能直到殆盡丑婿。如果不了解線程池藕夫,最好手動創(chuàng)建。
3.沒有做前后端分離枯冈,前端路由過度依賴后端Controller的轉(zhuǎn)發(fā)。
4.自定義封裝BaseMyBatisDAO办悟,但是RowBounds分頁功能效率很低尘奏,建議使用通用Mapper和PageHelper進行分頁和排序。
5.沒有統(tǒng)一進行返回碼封裝和對異常的封裝以及處理病蛉。
6.重復(fù)代碼太多炫加,其實20張表的基礎(chǔ)代碼(Service層、Controller層铺然、DAO層)完成可以用自動化框架生成俗孝。沒必要把時間花在這些無意義的事情上,我們需要更關(guān)注于業(yè)務(wù)邏輯魄健。
7.圖片服務(wù)器暫時是用Tomcat赋铝。明顯不是一個好的選擇,應(yīng)該考慮七牛云或者搭建FastDFS沽瘦。
8.使用Redis緩存革骨,無腦瞎B使用。設(shè)置的KEY也沒有設(shè)置緩存失效時間析恋。很多程度上沒有考慮緩存穿透良哲,緩存雪崩,緩存擊穿這些場景助隧,沒有考慮到緩存數(shù)據(jù)和數(shù)據(jù)庫里面的數(shù)據(jù)一致性的問題筑凫。
秒殺業(yè)務(wù)分析
在工作空余時間,也看了慕課網(wǎng)上關(guān)于高并發(fā)秒殺業(yè)務(wù)的解決方案,收貨頗多巍实。
1.商品詳情頁是產(chǎn)生高并發(fā)的一個點滓技。中小型企業(yè)一般采用Nginx+頁面靜態(tài)化就能解決。我們可以把靜態(tài)界面加入到CDN緩存中蔫浆。CDN可以加速用戶獲取數(shù)據(jù)的速度殖属,一般部署再離用戶最近的網(wǎng)絡(luò)節(jié)點上。
2.關(guān)于秒殺操作瓦盛,我們無法去用CDN緩存洗显。后端使用緩存比較困難,存在庫存一致性的問題原环。在熱度商品的秒殺上挠唆,存在一行數(shù)據(jù)競爭的情況。
3.關(guān)于秒殺地址暴露嘱吗,我們也無法去用CDN緩存玄组。適合用Redis進行緩存商品,一致性維護成本低谒麦。Redis和Mysql數(shù)據(jù)一致性維護可以采用超時穿透/主動更新策略俄讹。
4.關(guān)于獲取秒殺時間的獲取,其實不用優(yōu)化绕德。Java訪問一次內(nèi)存是10ns患膛,而1秒等于=10億ns。相當我1s的時間進行1億次的new Date()耻蛇。
5.比較成熟的解決方案: 原子計數(shù)器->Redis踪蹬,記錄行為消息->分布式MQ,消費消息并落地->MySQL臣咖。但是存在數(shù)據(jù)一致性和回滾問題跃捣,冪等性難以保證(會造成重復(fù)秒殺),這種架構(gòu)不適合新手架構(gòu)夺蛇。
6.經(jīng)過Jmeter壓力測試疚漆,一條update商品庫存語句的QPS是4W。一般用戶進行秒殺操作刁赦,會受到網(wǎng)絡(luò)延遲+GC的串行化阻塞愿卸。一般來說用戶執(zhí)行秒殺操作,正常的業(yè)務(wù)來說先執(zhí)行減少商品庫存操作截型,再插入用戶購買明細趴荸。但是update同一行商品記錄會造成行級鎖。行級數(shù)會在commit事務(wù)后之后釋放宦焦。在并發(fā)量集中的秒殺操作发钝,這些操作會造成阻塞顿涣,因此我們優(yōu)化的方向是減少行級鎖持有的時間。我們可以先執(zhí)行插入用戶購買明細操作酝豪,然后更新庫存操作涛碑。因為insert可以并行!
7.關(guān)于秒殺操作孵淘,我們可以把秒殺的業(yè)務(wù)邏輯寫到MySQL端(也就是存儲過程)蒲障,整個事務(wù)在MySQL端完成,優(yōu)化網(wǎng)絡(luò)延遲和GC干擾瘫证。
優(yōu)化總結(jié):
- 1.前端控制:合理暴露秒殺地址揉阎,秒殺按鈕防重復(fù)。
- 2.后端控制:動靜態(tài)數(shù)據(jù)分離背捌,CDN緩存毙籽,后端緩存,行級鎖競爭優(yōu)化毡庆,減少事務(wù)時間坑赡。
尾言
沒有什么比學(xué)習(xí)和成長更為重要的事情了。
電商項目地址:https://github.com/cmazxiaoma/groupon
電商秒殺業(yè)務(wù)項目地址:https://github.com/cmazxiaoma/mallSeckill