sales2@gdinyan.com
86-20-86379008

别再吐槽12306了,有本事你來寫架構

  • 發布時間: 2015-04-26 20:45:11
  • 浏覽次數: 1599

4090_1

我曾在淘寶寫過一(yī)段時間代碼,2012年(nián)在一(yī)家百強民企做(zuò)電商副總,當時在極為(wèi)艱苦的(de)條件下帶隊開發了一(yī)個B2C網站,走支付寶和(hé)銀聯支付通道(dào),年(nián)營業額千萬級(當然實在太少了,我隻是說這個網站投入了實際的(de)運營)。

也就在那個時候,我對12306嗤之以鼻,覺得他們做(zuò)得太爛了,認為(wèi)自(zì)己能帶隊花幾百萬半年(nián)時間做(zuò)個好的(de)出來。于是我狂妄地(dì)想做(zuò)一(yī)個開源的(de)訂票(piào)系統給他們。我花了一(yī)個星期時間思考建立數據模型,思考到庫存這一(yī)步的(de)時候,我才發現,12306的(de)庫存複雜性比淘寶、京東高(gāo)很多倍,運算量也大很多倍。傳統的(de)分布式數據庫、緩存、負載均衡技術并不能恰好滿足12306的(de)需求。

在平時,12306也就是個正常的(de)電商網站。但一(yī)到黃金周,12306就是一(yī)個全站所有商品都秒殺,所有SKU都是動态庫存的(de)變态。

即使不考慮線下既有的(de)電話、代售點等渠道(dào),要實現一(yī)個12306,最少最少也是千萬級别的(de)硬件投入(這是當時的(de)估算,沒有精算,可(kě)能與實際相差較大,總之,我說得不一(yī)定對,12306的(de)業務也許沒我說的(de)那麽複雜,但也絕不是某些人噴的(de)那麽簡單),軟件和(hé)人力另算。那些叫嚣隻要40台服務器、隻要2個架構師4個程序員、大談分庫分表和(hé)前端CDN的(de)人們,隻是紙上談兵(bīng)罷了。所謂初生牛犢不怕虎,做(zuò)了三年(nián)CMS和(hé)BBS,就以這個經驗來噴12306,未免太天真了。

媒體人噴12306,是他們不懂技術,沒有能力和(hé)耐心來分析背後的(de)難度。技術人員噴,則是因為(wèi)大部分的(de)技術人員在短(duǎn)時間思考時,容易陷入過于樂(yuè)觀的(de)誤區,經典的(de)例子(zǐ)就是估算工作量,程序員們往往容易估算出一(yī)個超短(duǎn)的(de)工期,把寫程序的(de)工作樂(yuè)觀地(dì)想象成了打字員照稿敲鍵盤的(de)工作。

知乎那篇文章(zhāng),我覺得不是洗地(dì)。排名第一(yī)和(hé)第二的(de)答案都說得很客觀。淘寶技術是比12306強大很多倍,淘寶現在的(de)系統也是花了10倍于12306的(de)錢、時間和(hé)人才做(zuò)起來的(de)。根本原因還是鐵路運力不能滿足春運需求,淘寶也解決不了這個問題。

12306這一(yī)年(nián)來進步非常大。從前段動畫驗證碼、分時段搶票(piào),到後端去(qù)小型機、虛拟化、內(nèi)存數據庫的(de)運用。可(kě)以說,12306是中國政府機關做(zuò)的(de)最強大的(de)網站(電商系統),能在短(duǎn)短(duǎn)一(yī)兩年(nián)內(nèi)做(zuò)出這樣的(de)改變,幾乎是個奇迹,就連一(yī)些市場化的(de)民企都望塵莫及,甚至一(yī)些上市公司都比不上它!(比如(rú)51job和(hé)ctrip)。

事非經過不知難,在網上批判12306的(de)人,大部分還是形成了【國企 = 壟斷 + 腐敗 + 低(dī)效 】的(de)思維定勢。小部分是真的(de)輕視(shì)了它的(de)難度。

至于12306一(yī)期工程3個億(含硬件)貴不貴我不評價,我隻提供一(yī)個數字供參考,百度一(yī)年(nián)的(de)研發費用(不含硬件)是10億,這個數字來自(zì)百度财報。網上能查到。3億看起來好大一(yī)個數字,真用到超大型的(de)電商系統、搜索引擎系統裏面,其實也不算什麽天文數字了。

再解釋一(yī)下,為(wèi)什麽秒殺壓力大,以及為(wèi)什麽12306的(de)動态庫存很複雜。

秒殺

2013年(nián)12月25日前後,天貓搞了一(yī)個聖誕季積分兌換活動,持續幾天。25号上午10點12分,放出了15000個天貓魔盒(淘寶集市有人賣,大概190-230塊),從成交記錄上看,是19秒內(nèi)全部搶完。

實際上,我也參加秒殺了,那天的(de)題目特别簡單(請輸入xxx漢字的(de)拼音首字母),我應該是5秒內(nèi)答題完成并提交訂單,結果告訴我排隊的(de)人太多,擠不進去(qù),并提示14秒以後重試。人太多就是因為(wèi)題目太簡單了,門檻越低(dī),5秒內(nèi)擠進去(qù)的(de)人也越多嘛,如(rú)果題目換成【2克濃度為(wèi)3%的(de)U235在大亞灣核電站能發多少KW的(de)電】,5分鍾之內(nèi)也不會有1萬5千人跟我競争。

我想,14秒以後哪還有我的(de)事情呀,于是重新答題秒殺,結果出現了服務器錯誤的(de)頁面。反複刷新幾次,就告訴秒殺結束了。

在群裏問了一(yī)下同事,有不到10個人回答我,都說沒秒到(也可(kě)能秒到的(de)人悶聲發大财,不回複我)。

淘寶是什麽技術水平呢(ne),淘寶有至少4000技術人員,至少4萬台服務器(這都是兩年(nián)前的(de)公開數據了,按規定可(kě)以談論),2013年(nián)11月11日成交額351億,2012年(nián)全年(nián)成交額超過1萬億。

淘寶擁有各種自(zì)主研發團隊:服務器、交換機(網上可(kě)以搜索到淘寶公開的(de)綠色服務器開放标準);操作系統(Linux Kernel taobao版,yunos手機操作系統是阿裏雲的(de),暫時不計入)、Web服務器(Tengine)、Java語言虛拟機(JVM taobao版)、數據庫(MySQL內(nèi)核 taobao版,google和(hé)facebook也有自(zì)己的(de)版本,HBase淘寶版、還有自(zì)己全部從頭開發的(de)OceanBase)、負載均衡器(LVS,LVS始創人就在淘寶,擔任研究員)、Java運行容器(Jboss,其創始人之一(yī),王文彬,也在淘寶,擔任副總裁)。

淘寶還有數不清的(de)開源項目和(hé)中間件,如(rú)高(gāo)性能Java通信中間件HSF、分布式數據庫中間件TDDL、異步消息系統notify等等等等。

以淘寶這樣的(de)技術水平,也不能做(zuò)到秒殺時讓每個用戶都沒有擁擠感,為(wèi)什麽呢(ne)?

一(yī)是要尊重物理(lǐ)原理(lǐ),一(yī)台服務器一(yī)秒鍾能承受的(de)計算量是有極限的(de),任你怎麽優化,采用多高(gāo)效的(de)算法和(hé)編程語言,都突破不了某個極限,比方說汽車發動機驅動的(de)F1賽車至今也不能突破400公裏的(de)時速(超音速推進号那個1千多公裏的(de)時速不能算,那是飛(fēi)機引擎驅動的(de))。再往深了說,就不容易懂了。感興趣的(de)可(kě)以從著名的(de)C10K問題開始看起。

二是要考慮經濟效益,十一(yī)黃金周的(de)時候,北京主城區到八達嶺長(cháng)城的(de)路堵得嚴嚴實實,但不能因為(wèi)黃金周的(de)高(gāo)峰,就把這段路修成長(cháng)安街那樣10車道(dào)的(de)高(gāo)速公路。否則的(de)話,花費天文數字(真的(de)是天文數字,12306那3個億大概隻夠修1-3公裏)。修了一(yī)段路,黃金周是可(kě)以飙到80公裏/小時了,可(kě)平時呢(ne),拿來給兩邊的(de)居民曬谷子(zǐ)?

淘寶目前的(de)硬件和(hé)帶寬數量,已經超出日常運營的(de)需求了,就是留了相當大的(de)餘量給大促銷(衆所周知的(de)是雙十一(yī),雙十二,其實基本每個季度都有大促銷,每個月都有促銷,甚至天天都在促銷——聚劃算)。amazon當年(nián)就是為(wèi)了應對黑色星期五的(de)大促銷購置了大量的(de)服務器,平時訂單量沒那麽大了,amazon就把富餘的(de)服務器拿來搞雲計算了。順便說一(yī)下,阿裏雲是當今中國第一(yī)世界數一(yī)數二的(de)雲計算服務商,和(hé)amazon走的(de)路也有點像。

動态庫存

淘寶秒殺天貓魔盒的(de)時候,隻有一(yī)個商品(行話叫做(zuò)SKU),它的(de)庫存是15000個。有一(yī)個人秒殺到了,庫存就減1,19秒賣完的(de),一(yī)秒要成功産生789個訂單(下訂單的(de)請求可(kě)能是8萬個,隻是可(kě)能啊,非實際數字,也可(kě)能是1萬個,用于說明一(yī)下壯觀程度)。想象一(yī)下,你在廣場上賣火車票(piào),一(yī)秒鍾有8萬人舉着錢對你喊:賣給我!

上過大學(xué)的(de)人都知道(dào),比秒小的(de)時間單位還有毫秒、皮秒、飛(fēi)秒。但交易系統登記一(yī)個交易可(kě)不像電子(zǐ)繞着原子(zǐ)核跑一(yī)圈那麽簡單,它要做(zuò)這些事:檢查是否惡意訪問、取到系統時間、取到顧客默認收貨地(dì)址、核對顧客秒殺資格(當時的(de)規定是天貓T2.T3達人)、生成訂單号、把顧客ID系統時間訂單号收貨地(dì)址寫入訂單系統、扣除顧客天貓積分、商品庫存減一(yī)、給顧客打标記(每人隻能秒一(yī)個,下次不能秒了)等等,這每一(yī)件事都要花費毫秒級别的(de)時間,這些操作加起來的(de)時間可(kě)能是接近1秒級别的(de),但由于淘寶的(de)服務器比較強悍,而且采用了分布式和(hé)集群技術,結果比1秒理(lǐ)想一(yī)點。但即使有1萬台服務器,也不能把這個時間稀釋成萬分之一(yī)秒,因為(wèi),商品隻有一(yī)種,它有15000個庫存,對應的(de)數據庫記錄隻有一(yī)行,所有的(de)交易請求都要到這裏來處理(lǐ)。

能不能把這15000個拆分成5000個商品并分配到5000台服務器上呢(ne)?那樣不就可(kě)以5000台服務器同時處理(lǐ)了嗎?答案是不能,首先,5000個商品,意味着有5000個商品詳情頁,5000個購買按鈕,這對前期的(de)營銷、引流是個災難。基本上就沒法做(zuò)引流入口了,顯然這違背了商業管理(lǐ)原則,人為(wèi)增加了信息混亂程度。其次,天貓魔盒秒殺也不是啥大事,即使按官方标價399元來計算,也就6百萬的(de)交易。如(rú)果6百萬的(de)交易要花費那麽大的(de)配套成本,那就太不劃算了。再次,淘寶有十幾億商品,這十幾億商品的(de)展示交易和(hé)管理(lǐ),本來就是分布到上萬台服務器上去(qù)了。沒有必要再把每個商品按庫存拆成多個商品了。

這789人搶到了,還不一(yī)定會付款(99積分換天貓魔盒還好一(yī)點,不需要去(qù)網銀,成本也極低(dī),大部分是會付款的(de),3999秒殺iPhone 5S就不一(yī)定,有人可(kě)能網銀有問題,有人可(kě)能改變主意不想要了),所以就又帶來訂單取消重新恢複庫存的(de)問題。還有想要的(de)消費者們,會認為(wèi)還有機會,繼續在前台刷一(yī)會兒,最終這個秒殺會被熱情的(de)消費者們猛刷30秒到1分鍾。

商品數據庫

我以北京西到深圳北的(de)G71次高(gāo)鐵為(wèi)例(這裏隻考慮南下的(de)方向,不考慮深圳北到北京西的(de),那是另外一(yī)個車次,叫G72),它有17個站(北京西是01号站,深圳北是17号站),3種座位(商務、一(yī)等、二等)。表面看起來,這不就是3個商品嗎?G71商務座、G71一(yī)等座、G71二等座。大部分輕易噴12306的(de)技術人員(包括某些中等規模公司的(de)專家、CTO)就是在這裏栽第一(yī)個跟頭的(de)。

實際上,G71有136 * 3 = 408種商品(408個SKU),怎麽算來的(de)?請看:

如(rú)果賣北京西始發的(de),有16種賣法(因為(wèi)後面有16個站),北京西到:保定、石家莊、鄭州、武漢、長(cháng)沙、廣州、虎門、深圳……都是一(yī)個獨立的(de)商品,

同理(lǐ),石家莊上車的(de),有15種下車的(de)可(kě)能,以此類推,單以上下車的(de)站來計算,有136種票(piào):16+15+14….+2+1=136。每種票(piào)都有3種座位,一(yī)共是408個商品。

好了,再看出票(piào)時怎麽減庫存,由于商務、一(yī)等、二等三種座位數是獨立的(de),庫存操作也是一(yī)樣的(de),下文我就不再提座位的(de)差别的(de),隻讨論出發與到達站。另外,下文說的(de)是理(lǐ)論世界的(de)模型,不是說12306的(de)數據庫就是這麽設計的(de)。

旅客A買了一(yī)張北京西(01号站)到保定東(02号站)的(de),那【北京西到保定東】這個商品的(de)庫存就要減一(yī),同時,北京西到石家莊、鄭州、武漢、長(cháng)沙、廣州、虎門、深圳等15個站台的(de)商品庫存也要減一(yī),也就是說,出一(yī)張北京到保定東的(de)票(piào),實際上要減16個商品的(de)庫存!

這還不是最複雜的(de),如(rú)果旅客B買了一(yī)張北京西(01号站)到深圳北(17号站)的(de)票(piào),除了【北京西到深圳北】這個商品的(de)庫存要減一(yī),北京西到保定東、石家莊、鄭州、武漢、長(cháng)沙、廣州、虎門等15個站台的(de)商品庫存也要減1,保定東到石家莊、鄭州、武漢、長(cháng)沙、廣州、虎門、深圳北等15個站台的(de)商品庫存要減1。。。總計要減庫存的(de)商品數是16+15+14+。。。。+1=120個。

當然,也不是每一(yī)張票(piào)都的(de)庫存都完全這樣實時計算,可(kě)以根據往年(nián)的(de)運營情況,在黃金周這樣的(de)高(gāo)峰時段,預先對票(piào)做(zuò)一(yī)些分配,比如(rú)北京到武漢的(de)長(cháng)途多一(yī)點,保定到石家莊的(de)短(duǎn)途少一(yī)點。我沒有證據證實鐵道(dào)部這樣做(zuò)了,但我相信,在還沒有12306網站的(de)時候,鐵道(dào)部就有這種人工預分配的(de)策略了。

想象一(yī)下,8萬人舉着錢對你高(gāo)喊:賣給我。你好不容易在錢堆裏找到一(yī)隻手,拿了他的(de)錢,轉身找120個同事,告訴他們減庫存,而這120個同事也和(hé)你一(yī)樣被8萬人圍着;也和(hé)你一(yī)樣,每賣出一(yī)個商品要找幾十個人減庫存。。。這就是12306動态庫存的(de)變态之處。比你平時買東西的(de)任何網站的(de)庫存機制都複雜幾十上百倍。

搶票(piào)插件

機器永遠比人快,當你好不容易從8萬人裏突出重圍,來到了櫃台前,你發現,我操,來了10萬根綁着錢的(de)竹竿,而且當有退票(piào)出來的(de)時候,你要闖過3層人肉才能接近櫃台,竹竿在8個人身後一(yī)伸,錢就到了櫃台前。你低(dī)頭看了一(yī)眼手機,票(piào)就沒了,竹竿卻永遠在那裏伸着,永不低(dī)頭,永不眨眼。如(rú)果沒有這10萬根竹竿,雖然你很可(kě)能還是搶不到票(piào),但不至于沮喪成這樣:我TM為(wèi)什麽總是手最慢的(de)一(yī)個?!!

防機器人搶票(piào),也不是加個圖片驗證碼那麽簡單。我寫過文章(zhāng)系統性分析過,圖片驗證碼有6種機器暴力破解的(de)辦法,搶票(piào)插件用的(de)是我說的(de)第三種,OCR識别。Google采用的(de)Wave波形字母已經能比較好地(dì)防住機器OCR了,ems.com.cn上的(de)驗證碼就是反面教材,機器OCR成功率接近100%,12306的(de)比ems的(de)圖片驗證碼強一(yī)點。不過,驗證碼設置得複雜一(yī)點吧(ba),人們要噴:這隻是便宜大學(xué)生和(hé)辦公室白領,農民工連26個字母都認不齊,怎麽搞?搞動畫驗證碼吧(ba),也有人噴,視(shì)力不好的(de)人怎麽辦?最後驗證碼搞得太簡單了,皆大歡喜了,其實最高(gāo)興的(de)是開發搶票(piào)插件的(de)公司。

就算采用了機器完全不可(kě)能識别的(de)驗證碼,也防不住社會工程學(xué)的(de)破解辦法。招募一(yī)堆網吧(ba)打遊戲的(de)青少年(nián)朋(péng)友,每成功輸入50個驗證碼給1塊錢,或者等值的(de)虛拟貨币、遊戲裝備,我保證想賺這個錢的(de)人數不勝數。這點錢對轉賣車票(piào)的(de)利潤而言,是可(kě)以接受的(de)成本。有沒有什麽技術可(kě)以防住社會工程學(xué)的(de)破解辦法呢(ne)?能防住網吧(ba)青少年(nián)的(de)驗證碼隻有【2克濃度為(wèi)3%的(de)U235在大亞灣核電站能發多少KW的(de)電】。

沒有曆史包袱從零起步的(de)交易系統?

以上讨論隻是把12306當成和(hé)淘寶一(yī)樣沒有曆史包袱從零起步的(de)交易系統,實際上,它不是,它後面的(de)票(piào)池,還有電話售票(piào)、火車站售票(piào)、代售點售票(piào)等多個傳統渠道(dào)要服務。除了客運服務,12306還有全國最大(很可(kě)能也是全球最大)的(de)大宗物資貨運系統。

架空政策(包括定價政策、警方打擊黃牛政策、身份驗證政策)談技術,是不可(kě)能解決春運搶票(piào)困局的(de),要想讓春運的(de)時候每個人在12306搶票(piào)都毫無擁擠感(但不一(yī)定能搶到票(piào),鐵路運力擺在那),那就是逼着12306買一(yī)大堆服務器對付春運,春運過去(qù)後,成為(wèi)跟amazon一(yī)樣牛逼的(de)雲計算服務商。和(hé)逼北京修一(yī)條10車道(dào)的(de)高(gāo)速公路去(qù)八達嶺長(cháng)城一(yī)個道(dào)理(lǐ)。

目前的(de)12306技術上是還有問題,比如(rú),搶票(piào)高(gāo)峰,輸入個身份證号和(hé)圖片驗證碼都卡得要死(本人親測),服務器端繁忙,你浏覽器端卡什麽呀。

但人家在進步。相信2014年(nián)春運的(de)時候,技術已經不再是一(yī)票(piào)難求的(de)主要問題。在鐵路運力不可(kě)能神速增加(孫中山先生計劃的(de)20萬公裏鐵路,土共修了快70年(nián),才修到10萬公裏)的(de)情況下,要做(zuò)到春運更公平地(dì)買票(piào),需要停靠政策調整。

解決方法

下文針對的(de)是春節國慶這種非常暑期。其它時期,大部分線路保持現狀就行了,問題不大,極少部分票(piào)源緊張的(de)線路可(kě)以按春運處理(lǐ):

1.拍賣法,價高(gāo)者得之

當硬座票(piào)拍出飛(fēi)機票(piào)價格的(de)時候,相信票(piào)就不難買了(可(kě)惜就是貴了),也沒有那麽多黃牛了。要說淘寶有什麽能幫12306一(yī)下子(zǐ)搞定技術問題的(de),淘寶的(de)拍賣系統可(kě)以幫忙,浙江省高(gāo)院在淘寶拍賣一(yī)年(nián)多,成交26億。

可(kě)惜這個方法不可(kě)能實行。現在的(de)高(gāo)鐵票(piào)價都被媒體和(hé)意見領袖噴成啥樣了,何況是拍賣。再說,火車票(piào)畢竟是生存之剛需,票(piào)價20年(nián)來不漲本來就有照顧補貼的(de)成分在裏面,全拍賣可(kě)能也是不妥當。

2.抽簽法,運氣好者得之

開車前2個月開放報名,開車前7天抽簽,中途可(kě)取消。預存票(piào)款,抽不中退款。上傳身份證和(hé)正臉自(zì)拍照,機器核對。

這樣的(de)話,攔截黃牛的(de)成功率就高(gāo)很多了,黃牛可(kě)以預存票(piào)款,可(kě)以找到大量真實身份證号,你黃牛再讓每個給你身份證号的(de)人把身份證照片和(hé)臉部自(zì)拍也給你試試?即使有人真想找黃牛,給身份證照片還是會猶豫一(yī)下吧(ba)。而且中間手工操作多了很多,黃牛成本提高(gāo),還不一(yī)定搞得到票(piào)。反正都是碰運氣,我想真正的(de)消費者還是會選擇自(zì)己先去(qù)碰運氣吧(ba)。

這個方法實施難度也大,無論怎麽設計抽簽規則,必然有人大叫“有黑幕,不要相信政府”。

開車前7天出抽簽結果,改變行程的(de)人應該在7天前就能決定改還是不改了。沒抽到的(de)也還有時間想别的(de)辦法。當然不一(yī)定是7天,15天,10天也可(kě)以,具體幾天要有數據模型來算。

3.拍賣 + 抽簽

軟卧、高(gāo)鐵商務座等高(gāo)價位的(de),拍賣,反正買這個的(de)是經濟能力相對較強的(de)。那就拼誰經濟能力更強吧(ba)。

硬座、站票(piào)抽簽。

4.憑身份證進站,車票(piào)跟發票(piào)一(yī)樣,是報銷憑證,不是進站憑證;退票(piào)後錢進入12306賬戶,不可(kě)提現,隻可(kě)該乘客下次乘車用;黃金周期間,個人賬号最多訂購10張票(piào),這個辦法可(kě)以打擊黃牛囤票(piào)再轉賣。運行一(yī)段時間後,按賬戶餘額弄個排行榜就知道(dào)誰是黃牛了,可(kě)惜這個需要車站設備改造配合。