陳哲跟著站起來,目光掃過那群人。 (由於快取原因,請使用者直接瀏覽器訪問 追書認準,.超省心 網站,觀看最快的章節更新)
走在最前麵的是一個三十多歲的白人男性,個子不高,穿一件洗得發白的藍色衛衣,頭髮有點長,紮了個小揪在腦後。他手裡拿著一個保溫杯,杯身上印著紐約的logo,邊緣的漆已經磕掉了好幾塊。
「麥克!」那人走近,伸出手和麥克擊了個掌,「好久不見。」
「群主。」麥克笑著指了指旁邊的陳哲,「這是陳,新來的,我拉進群的。」
群主的目光落在陳哲身上,從上到下掃了一眼,然後伸出手。
「歡迎。叫我本就行。群主是大家開玩笑叫的。」
陳哲握住他的手。本的手掌很厚,指腹有繭,不知道是敲鍵盤留下的還是別的什麼。
「陳哲。」
「中國人?」本問。
「對。」
本點點頭,沒再多問。他轉身朝後麵那群人招了招手:「都過來吧,找個地方坐。」
一群人往長椅那邊移動,有人坐下,有人靠在欄杆上,有人乾脆坐在草坪上。陳哲粗略數了數,加上他和麥克,一共十二個人。
本清了清嗓子。
「今天叫大家出來,沒什麼正事,」他說,「就是最近群裡太安靜了,想讓大家見見麵,聊聊天。都是幹這行的,平時對著螢幕,也該出來透透氣。」
有人笑了一聲。
本從口袋裡掏出一個筆記本,翻了翻。
「先介紹一下自己吧。從我開始。本,做YouTube的,頻道叫『碼農日記』,主要講後端和資料庫。幹了五年,還在乾。」
他把筆記本遞給旁邊的人。
那是個非裔女生,二十多歲,厚嘴唇,戴一副圓框眼鏡,紮著馬尾。她接過筆記本,看了一眼,然後抬起頭。
「萊拉,群裡的『愛來自冒險家協會』,是一家遊戲公司的程式設計師。」
隨後是一個重度近視鏡的華人男子,淡淡地說:「書蟲。」
此外均是一群美國白人。
陳哲的目光也在這群拘謹的成年社畜之間遊移。
美國高階程式設計師中黃種人和白種人的數量大約各占一半,但是在目前這種低端局裡,白人還是占了巨大優勢的,畢竟是本土主要民族。
陳哲看向群組暱稱為書蟲的華人男子,而對方的眼鏡上起著霧,也看不清對方的表情。
現場除了自己和對方,還有那個叫萊拉的黑人女生以外,其他人的手裡都拿著一部高階牌子的膝上型電腦,諸如MacBook Pro、戴爾、ROG、Razer、LG gram係列。
陳哲不動聲色地抖了抖自己的揹包,裡麵那台老式的二手ThinkPad聯想,看上去倒是和這些人有點格格不入了。
不過好在陳哲擁有Lv2的計算機技術。
筆記本繼續傳。
「湯姆,後端,主要寫Go。」
「莎拉,前端,目前在自由職業。」
「戴夫,DevOps,最近在搞K8s。」
……
不久,十二個人介紹完,本拍了拍手。
「行,都認識了。接下來自由活動,想聊技術的聊技術,想聊八卦的聊八卦。十二點的時候我請大家喝咖啡,樓下有家店不錯。」
本說。
人群散開,三三兩兩地聚成幾堆。
陳哲站在原地,目光掃過四周。陽光已經徹底升起來了,河麵上的碎金晃得人眼睛發酸。遠處有幾隻海鷗在盤旋,叫聲尖銳,像是在爭奪什麼。
他注意到那個叫書蟲的華人男子獨自站在欄杆邊,背對著人群,望著河麵。眼鏡上的霧氣已經散了,但他沒有要加入任何一個小團體的意思。
陳哲想了想,沒有走過去。
「陳,對吧?」
一個聲音從旁邊傳來。
陳哲轉頭,看見那個叫湯姆的白人男生走過來,手裡拿著一台MacBook Pro,螢幕還亮著。
「對。」
陳哲整理了一下自己的襯衣,說。
湯姆點了點頭,在他旁邊的欄杆上靠下來。
「我也是社羣大學出來的,」他說,「皇後區的拉瓜迪亞社羣學院。轉了學,最後在紐約城市大學畢的業。」
他頓了頓,笑了笑。
「這條路走得通,就是慢一點。」
陳哲沒說話。
開盒!
陳哲從來沒有透露過自己的身份,但是遇到有心之人,就是直接開了。
「改天得消除一下行蹤了……」
陳哲眸光深思,對於程式設計師來說,想要套取到他人的資訊是一件容易事。就算是那些專精於網際網路人肉搜尋的青少年,在這方麵愛好也敵不過興趣。
就在這時,湯姆的聲音又傳來。
「你現在寫什麼語言?」
「Python。」陳哲答。
湯姆頷首,目光落在河麵上。
「Python挺好入門的,」他說,「不過後端的話,遲早得學Go或者Java。看你以後想走什麼方向。」
陳哲剛要開口,身後傳來本的拍手聲。
「都過來一下!」
人群重新聚攏。本站在中間,手裡不知從哪掏出一塊白板,大概A3紙大小,上麵貼著一張紙,紙上寫著一行字。
陳哲走近了纔看清那行字是什麼。
「設計一個URL短連結服務」
本把白板舉高了點,讓所有人都能看見。
「來,玩個遊戲。」他說,語氣裡帶著一點興奮,「這玩意兒大家都不陌生吧?短連結服務,Bitly那種。給你一個長URL,生成一個短碼,訪問短碼的時候重定向到原地址。」
他頓了頓,目光掃過人群。
「規則很簡單:每個人三分鐘時間,想一下怎麼設計。可以討論,也可以自己想。三分鐘之後,每個人輪流說自己的思路。」
有人笑了一聲:「麵試來了。」
本也笑了:「麵試?沒意思。這是遊戲,隨便聊。誰說得有意思,我請他喝咖啡——不是樓下那種,是正經的第三波咖啡。」
「更何況,這種事我們之前的聚會也做過,不是嗎?」本嘴角上揚。
人群裡響起幾聲口哨。
陳哲站在原地,目光落在那行字上。
URL短連結服務。
簡單來說,URL短連結服務就是一種將冗長的網址(URL)轉換為簡短地址的工具。當使用者點選短連結時,會被自動重定向到原始的長網址。
這東西他見過,用過,但從來沒想過怎麼設計。
三分鐘。
他開始想。
……
最開始想到的是最簡單的,一個資料庫表,兩個欄位,長URL和短碼。使用者提交長URL,生成一個隨機字串,存進去。訪問的時候查一下,重定向。
但這樣太簡單了。隨機字串碰撞怎麼辦?重複的URL要不要復用同一個短碼?訪問量大的時候資料庫扛得住嗎?
過了半分鐘,他想到了雜湊。把長URL用MD5或者SHA256雜湊一下,取前幾位作為短碼。但雜湊衝突怎麼辦?再加個鹽?還是用布隆過濾器先判斷一下?
隨後,陳哲想到了快取。
高頻訪問的短碼可以放Redis裡,不用每次都查資料庫。但快取失效怎麼辦?快取雪崩怎麼辦?
再接著,他想到了分散式。如果服務做大了,單機扛不住,得用分散式ID生成器。雪花演演算法?還是用資料庫自增ID然後取模?
一分鐘,他想到了更多。
短碼過期怎麼辦?自定義短碼怎麼支援?統計點選量怎麼實現?防攻擊怎麼搞?
……
三分鐘到。
本的拍手聲把陳哲從思考裡拉出來。
「行,時間到。」本說,「誰先來?」
人群安靜了一秒。
「我來吧。」
說話的是湯姆。他往前站了一步,清了清嗓子。
「最簡單的設計:一張表,id自增,長URL欄位,短碼欄位。短碼可以用id的62進位表示,0-9a-zA-Z,一共62個字元。id從100000開始,保證至少六位短碼。」
他頓了頓。
「優點是簡單,不會衝突。缺點是自增id容易被遍歷,可以加個隨機偏移量。訪問量大的時候加快取,Redis存熱點資料。如果要做大,分庫分表,按短碼雜湊分片。」
他的語氣中充斥著自信,毫無疑問這是個比較優越的答卷。
本點了點頭,沒評價。
「下一個。」
萊拉站出來。
「我會用雜湊。長URL做MD5,取前六位。如果衝突了,加個鹽重新雜湊,或者用布穀鳥雜湊的思路。優點是短碼隨機,不容易被猜。缺點是要處理衝突,效能稍微差點。」
本還是點了點頭。
「下一個。」
接下來幾個人輪流發言,思路都大同小異——資料庫、雜湊、快取、分片。有人提到了用NoSQL,有人提到了用訊息佇列做非同步統計,有人提到了用CDN加速。
陳哲一直不語。
本的視線最後落在他身上。
「陳,你呢?」
所有人的目光都轉過來。
陳哲沉默了兩秒。
「我想到的跟大家不太一樣。」他說。
本的眉毛挑了一下。
「你可以說來聽聽。」
陳哲往前走了一步,站在白板旁邊。
「大家說的都是儲存和查詢的邏輯,我換個角度——成本。」
他頓了頓。
「短連結服務最燒錢的是什麼?不是伺服器,不是資料庫,是流量。每次訪問都要302重定向,每次重定向都是一次HTTP請求。如果服務做大了,每天幾億次訪問,光是流量錢就能燒破產。」
人群安靜下來。
「所以我會在重定向之前加一層CDN。」陳哲繼續說,「短碼的訪問路徑先走CDN,如果CDN有快取,直接返回重定向響應,不回源。快取時間可以設長一點,比如24小時。這樣99%的流量都被CDN扛住了,源站隻需要處理快取未命中的請求。」
本的眉頭微皺。
陳哲繼續。
「然後是短碼生成。大家說的雜湊和自增id都有問題——雜湊有衝突,自增id太規律。我會用預生成的方式:啟動一個服務,提前生成一批短碼放在佇列裡。使用者來的時候,直接從佇列裡取一個分配出去。」
「這樣生成短碼和分配短碼解耦了。生成服務可以用雪花演演算法保證全域性唯一,分配服務隻需要從佇列裡pop。就算分配服務掛了,佇列裡的短碼還能頂一陣……」
「然後是資料庫。短碼和長URL的對映關係可以存MySQL,但高頻訪問的短碼要放Redis。如果要做大,可以按短碼字首分片,比如0開頭的放一組,1開頭的放另一組。」
「最後是監控。每個短碼的訪問量要統計,但不能影響主流程。可以用訊息佇列,非同步寫日誌,然後離線分析。」
他說完了。
人群安靜了幾秒。
本盯著他,表情有點奇怪。
麥克站在人群後麵,手裡的咖啡杯停在半空中,眼睛瞪得比剛才大了一圈。
「你……」麥克張了張嘴,像是想說什麼,但又嚥了回去。
湯姆第一個開口。
「CDN那層,」他皺著眉,「重定向響應能快取嗎?」
「能。」陳哲說,「302重定向也是HTTP響應,隻要設定Cache-Control頭,CDN就會快取。使用者訪問短碼的時候,CDN直接返回302,連源站都不碰。」
湯姆沉默了兩秒,然後點了點頭。
萊拉在旁邊喃喃自語:「預生成佇列……這個思路倒是第一次聽說。」
本的眉頭舒展開來。
他盯著陳哲看了幾秒,然後笑了。
「有意思。」
他把白板放下,拿起保溫杯喝了一口。
「你在哪家公司實習過?」
「沒實習過。」陳哲說。
本愣了一下。
「那你在哪幹過?」
「無可奉告。」
本的表情有點微妙。他把保溫杯放下,目光在陳哲身上轉了一圈,最後落在那台老舊的ThinkPad上。
沉默了兩秒。
「行。」本說,「我記住了。」
他沒再多說什麼,轉身朝人群揮了揮手:「走吧,喝咖啡去。樓下那家店不錯,我請。」
人群開始往出口移動。有人還在小聲討論剛才那個設計,有人已經開始聊別的話題。
陳哲站在原地,沒動。
麥克走過來,在他旁邊站定。
「小子,你……」麥克的聲音壓得很低,「你從哪學的這些?」
陳哲看了他一眼。
「網上。」
麥克盯著他看了幾秒,然後搖了搖頭。
「我拉你進群的時候還以為你是個萌新,」他低聲說,「結果你他媽是個扮豬吃老虎的。」
陳哲沒說話。
麥克拍了拍他的肩膀。
「走吧,喝咖啡去。」
……
Pier 57樓下有一家叫「Blue Bottle」的咖啡店,藍白相間的招牌,門口排著七八個人。本帶著一群人走過去,直接推門進了店裡——他顯然是熟客,店員看見他,點了點頭,指了指角落裡的幾張空桌子。
十幾個人分散坐下。本去櫃檯點單,回來的時候手裡拿著一遝小票,一張一張分給在座的人。
「自己點的自己拿。」他說。
陳哲拿到的是美式,黑咖啡,不加糖不加奶。他端起來喝了一口,苦的,但能接受。
萊拉坐在他旁邊,手裡拿的是一杯拿鐵,奶泡上麵畫著一顆心。她盯著那顆心看了兩秒,然後用勺背把它攪散了。
「Hello?陳哲。你那個設計,」她忽然開口,「預生成佇列那個思路,是從哪學的?」
陳哲轉頭看她,思索了一會兒:「學校競賽。」
萊拉沉默了兩秒,然後點點頭,沒再追問。
對麵坐著書蟲。
那個華人男子從剛才開始就一直沒說話,隻是坐在角落裡,麵前放著一杯冷萃,冰塊已經化了一半,他沒動。他的眼鏡片上又起了霧,不知道是咖啡的熱氣還是別的什麼。
陳哲的目光落在他身上。
書蟲似乎感覺到了什麼,抬起頭。
兩個人的目光在空中碰了一下。
書蟲沒說話,低下頭,繼續盯著那杯冷萃。
陳哲收回目光。
本端著一杯拿鐵走過來,在陳哲旁邊坐下。
「你那個設計,」他說,語氣比剛才輕鬆了一點,「說實話,有點出乎我意料。」
陳哲沒說話。
「CDN那層,」本繼續說,「一般新人想不到。預生成佇列那個,更不是新手能想到的。」
他頓了頓,喝了一口咖啡。
「你真沒實習過?」
「沒。」
本盯著他看了幾秒,然後笑了。
「行,我不問了。」
他站起來,朝其他人揮了揮手。
「一點鐘我還得去剪視訊,先走了。你們聊。」
他走了。
人群漸漸散開。有人起身去櫃檯續杯,有人走到門外抽菸,有人湊在一起聊技術。陳哲坐在原位,盯著杯子裡黑乎乎的液體,腦子裡不知道在想什麼。
麥克走過來,在他旁邊坐下。
「感覺怎麼樣?」
陳哲想了想。
「還行。」
麥克笑了笑。
「本那人對新人一般不怎麼上心,」他說,「但他剛纔多看了你幾眼。這是好事。」
陳哲點點頭,沒說話。
窗外,陽光照在哈德遜河上,波光粼粼。一艘卡其色觀光船慢悠悠地駛過,船上的人很小,看不清在幹什麼。
「下午有什麼安排?」麥克問。
「回去。」陳哲說,「寫程式碼。」
麥克點點頭,站起來。
「行,那我也不留你了。群裡聊。」
他拍了拍陳哲的肩膀,轉身走了。
陳哲抿了一口咖啡,這咖啡是藍瓶咖啡的一類,以精品單一產地咖啡豆和新鮮烘焙著稱。
陳哲實際上回去是不可能寫程式碼的。
畢竟他其實根本不是程式設計師。
他倒也沒有在這裡留多久,二手ThinkPad放在揹包裡沒拿出來過,回頭換乘了幾次紐約地鐵,就回了布魯克林區。