好的工具的產(chǎn)生使開發(fā)與部署變得十分容易惹想,作為一個曾經(jīng)的云服務從業(yè)人員,鼓勵大家擁抱云服務莽鸭。擁抱這些現(xiàn)成的技術(shù)棧沥曹。
這是我在 stephenmann.io 上看到的一篇文章险掀,對于 Web 應用程序架構(gòu)演進的過程講解的十分通俗易懂,所以就把它翻譯了出來。
一個合理的生產(chǎn)環(huán)境的 Web 應用程序應該是什么樣子的
原載:stephenmann.io
譯者:展小白
一個產(chǎn)品的規(guī)劃可能會是迎合最普遍的需求,但是很多情況客戶希望解決具體的問題瘾晃,這些問題可能將程序變得無限復雜,就必須提出有效的解決方案幻妓。
在過去的經(jīng)驗教訓中蹦误,一些工程師傾向于深入了解各項技術(shù),足以解決任何問題肉津。對于有著良好溝通的團隊强胰,這是非常好的。這些綜合的知識有效的填補了團隊個人的薄弱點妹沙。但對于行業(yè)或者經(jīng)驗不足的工程師團隊哪廓,這些幾乎是不可能的。
如果你是在一個薄弱的技術(shù)團隊初烘,然后從頭開始構(gòu)建和部署整個 Web 應用程序,你可能很快意識到要深入了解每項技術(shù)分俯,是很難的一件事情肾筐。
業(yè)界其實已經(jīng)提供了很多旨在解決這些問題的方案:Web 托管服務(Beanstalk,AppEngine 等)缸剪,容器管理服務(Kubernetes, ECS 等)以及其它很多解決方案吗铐。一旦你啟動并運行它們,便可以很好的正常進行工作杏节,這種解決方案非常好唬渗,因為它規(guī)避了啟動和運行 Web 程序過程中大量復雜的操作典阵,而且最終目的是為了使程序正常工作。
這里可能需要下功夫的是镊逝,在你決定用哪種方案時壮啊,你需要更多的了解這些解決方案。
在這篇文章中撑蒜,將介紹一個不靠譜的系統(tǒng)到具有合理可靠性的系統(tǒng)的過程歹啼。這里不會介紹每一部分的具體細節(jié),而是通過演進的過程座菠,讓你擁有在何時應該采用哪些決策的良好背景狸眼。
入門
最基本的你需要購買一臺服務器,比如可以從亞馬遜購買中配的服務器浴滴。
你知道你的程序需要用戶登錄拓萌,你需要存儲用戶信息。因此你需要一個數(shù)據(jù)庫升略。由于預算有限微王,直接在你的服務器上進行創(chuàng)建。最終得到的架構(gòu)如下:
這應該足夠了降宅,事實上骂远,使用這個架構(gòu),可以保障你的程序運行很長時間而沒有瓶頸腰根。此時激才,你可能每天只需要處理 10 次訪問請求。其實一個最低配的服務器已經(jīng)足夠了额嘿,但是你的公司可能對業(yè)務持增長態(tài)度瘸恼,所以選擇了中配的服務器。
現(xiàn)在册养,你將有價值的業(yè)務數(shù)據(jù)存儲在實例中的數(shù)據(jù)庫中东帅,如果服務器發(fā)生故障,或者實例被刪除球拦,很可能導致數(shù)據(jù)丟失靠闭,這是很可怕的。你應該確保數(shù)據(jù)備份到外部存儲坎炼。比如:S3 服務愧膀。所以讓我們設置它。你應該通過每隔一段時間恢復一次備份的方式來確保它正常運行谣光。
你的架構(gòu)應該如下所示:
你已經(jīng)提高了數(shù)據(jù)庫的可靠性檩淋,那么你決定通過對服務器進行負載測試來檢驗是否可以應對大規(guī)模的流量訪問。一切似乎進展順利萄金,直到 500 錯誤出現(xiàn)蟀悦,繼而是 404媚朦,所以你要排查是什么原因造成的。
但實際上日戈,你并不知道是什么原因?qū)е碌难牛驗槟惆讶罩緦懙搅丝刂婆_,并沒有寫入到日志文件中涎拉。你看到該進程并沒有運行瑞侮,因此你假設是這個原因?qū)е铝?404。
你可以通過創(chuàng)建 systemd
運行 Web 服務器服務來解決自動啟動的問題鼓拧,并解決你的日志記錄問題半火。然后再進行新一輪的負載測試,以確保解決了所有的問題季俩。
再一次钮糖,你看到了 500 錯誤,慶幸的是沒有 404酌住,你檢查日志看是哪里出錯了店归。你發(fā)現(xiàn)數(shù)據(jù)庫的連接池已經(jīng)飽和,該連接池設置了 10 個連接的限制酪我。你更新了限制消痛,重啟數(shù)據(jù)庫,然后再次運行負載測試都哭。一切順利秩伞。所以你決定對你的網(wǎng)站進行推廣。
發(fā)布日
哇欺矫!你的服務很受歡迎纱新,在 30 分鐘內(nèi)就獲得了 5000 次的點擊,你看到有評論進來穆趴。他們怎么說脸爱?
我訪問 404 了,于是我檢查我存儲的地址是否正確未妹,竟然換地址了簿废,如果有人需要,這是新的鏈接:……
……
什么也沒有顯示络它,也許是因為我禁用了 JavaScript捏鱼,但是,誰會需要 2MB 那么大的 JS 文件 ……
……
你們的主頁需要 4s 才能加載酪耕,而且訪問到的是離我很遠的一個地區(qū)的地址,另外轨淌,為什么要加載 2MB 的 JS 文件迂烁?
于是你拼命的進行了優(yōu)化看尼,你在服務器通過 Nginx 設置了跳轉(zhuǎn)你應用程序的反向代理,你將靜態(tài)文件進行了剝離盟步,上傳到了 S3藏斩,這是很有效的,你可以通過 CDN 幫助加速你網(wǎng)站在不同地區(qū)的訪問却盘。
現(xiàn)在狰域,你已經(jīng)解決了當前的問題,那么你可以通過訪問服務器查看日志黄橘。你發(fā)現(xiàn) SSH 連接非常慢兆览,經(jīng)過一番檢查,你發(fā)現(xiàn)你的日志文件已經(jīng)耗盡了你的磁盤空間塞关,這會使你的進程崩潰并阻止它再次啟動抬探。你創(chuàng)建更大的磁盤存儲日志,并且設置 logrotate
防止日志文件再次變得如此巨大帆赢。
性能問題
幾個月過去了小压,你的用戶數(shù)持續(xù)增長,你的網(wǎng)站開始變得很慢椰于。你在監(jiān)控中注意到怠益,這種情況似乎只發(fā)生在午夜到中午之間。由于變慢開始和結(jié)束的時間比較固定瘾婿,你猜測應該是服務器上的定時任務造成的蜻牢。你檢查 crontab 意識到你在午夜安排了備份任務。果然憋他,你的備份過程需要持續(xù) 12 個小時孩饼,并且導致數(shù)據(jù)庫超載,導致了站點訪問明顯拖慢竹挡。
你覺得應該在從庫進行數(shù)據(jù)庫的備份镀娶,但是你記得,你并沒有創(chuàng)建從庫揪罕,所以你需要創(chuàng)建一個梯码。在同一臺服務器運行從庫沒有太大的意義,因此好啰,你決定對服務器進行擴展轩娶,創(chuàng)建了兩個新的服務器:一個用于 master 數(shù)據(jù)庫,另一個用于 slave 數(shù)據(jù)庫框往。你將備份改為依據(jù)從庫運行鳄抒。
發(fā)展團隊
一切都很平穩(wěn),運行了一段時間。幾個月過去了许溅。你擴充了開發(fā)團隊瓤鼻,其中一位新的開發(fā)人員為了檢查一個錯誤,導致了生產(chǎn)服務器的故障贤重〔绲唬客戶把錯誤歸咎到了你沒有對生產(chǎn)測試環(huán)境進行區(qū)分。你覺得說的有道理并蝗,你是個虛心學習并且有追求的人祭犯,你把這次故障看做是一次學習的機會。
現(xiàn)在是到了構(gòu)建規(guī)范的開發(fā)部署流程的時候了:分期開發(fā)滚停,測試沃粗,然后部署。幸運的是铐刘,一開始你建立了良好的基礎架構(gòu)陪每,因此這變得很容易。因為你從第一天起镰吵,就良好的踐行了持續(xù)交付檩禾,你可以輕松的在一個新的分支進行構(gòu)建。
業(yè)務部門希望推出 2.0 版本疤祭,但并沒有具體的業(yè)務需求盼产,但是你還是去做了。你覺得是時候進行一次性能的改造勺馆。你的 Web 服務器的運行現(xiàn)在已經(jīng)接近峰值的利用率戏售,因此你決定對流量進行負載均衡。而亞馬遜 ELB 使你很容易上手草穆。與此同時你覺得你的架構(gòu)圖應該是這樣的:
另外還可以通過 Redis 等做一些緩存策略灌灾。相信你的優(yōu)化能夠承擔更大的負載,所以你再次對你的網(wǎng)站進行了大力推廣悲柱,不出所料锋喜,流量飆升,但運行很穩(wěn)定豌鸡。
一切看起來都那么好嘿般,直到你需要去檢查日志。這花費了你一個小時涯冠,因為要檢查 12 臺服務器(每個環(huán)境有 4 臺服務器)炉奴。那是一件麻煩事,幸運的是蛇更,你現(xiàn)在已經(jīng)賺了足夠的錢可以實現(xiàn) ELK 堆棧(ElasticSearch瞻赶,LogStash赛糟,Kibana)。新的架構(gòu)圖:
現(xiàn)在砸逊,你可以再次閱讀你的日志了虑灰,你發(fā)現(xiàn)了一些奇怪的情況。里面充滿了:
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
GET /wp-login.php HTTP/1.1" 404 169 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1
你并沒有運行 PHP 或 WordPress痹兜,所以很令人擔憂。你在數(shù)據(jù)庫服務器上注意到類似的可疑日志颤诀,你想怎么把他們暴露在公網(wǎng)上了字旭。所以是時候進行公網(wǎng)和本地訪問的隔離了。
再次崖叫,你檢查了日志遗淳,雖然仍然可能被黑客攻擊,但是僅限于負載均衡服務器上的 80 端口心傀,而你的應用服務器屈暗,數(shù)據(jù)服務器和 ELK 堆棧不再暴露在公網(wǎng)上。你可以輕松許多了脂男。
雖然對日志進行了集中式的記錄管理养叛,但是還不得不手動檢查日志。這時候使用服務器提供商的監(jiān)控宰翅,設置磁盤弃甥、CPU 和 網(wǎng)絡報警,以便在達到 80% 的使用率時通過郵件等途徑通知你汁讼,是個不錯的選擇淆攻。
一帆風順
開玩笑,沒有哪個程序的運行是一帆風順的嘿架,總有事情會發(fā)生瓶珊,幸運的是,你有很多工具可以處理這些問題耸彪。
現(xiàn)在伞芹,我們已經(jīng)構(gòu)建了一個可擴展的 Web 應用程序,包括備份搜囱,回滾丑瞧,集中式日志記錄管理,監(jiān)控和警報蜀肘“硇冢可以告一段落了,因為下面的改變往往取決于特定應用的需求扮宠。
業(yè)界提供了許多托管選項西乖,可以為你處理大部分內(nèi)容狐榔。你可以依靠 Beanstalk,AppEngine获雕,GKE薄腻,ECS 等而不是自己構(gòu)建所有這些服務。大多數(shù)這些服務都會自動設置合理的權(quán)限届案,負載均衡庵楷,子網(wǎng)等¢沟撸可以確保你的站點可以長時間運行尽纽。
了解這些平臺提供的功能以及什么時候使用它們是非常有用的,這樣童漩,你可以根據(jù)你的需要輕松選擇平臺弄贿。一旦你在相關平臺上運行了你的程序,你應該了解這些工具的工作原理矫膨,這是很重要的差凹,有助于在遇到問題時,快速解決問題侧馅。
結(jié)尾
這篇文章省略了很多細節(jié)危尿,不包括如何自動創(chuàng)建基礎架構(gòu),如何配置服務器施禾。不包括任何開發(fā)環(huán)境的創(chuàng)建脚线,如何實踐持續(xù)交付,如何執(zhí)行部署和回滾弥搞。不包括網(wǎng)絡安全邮绿,私密共享或最小權(quán)限原則。它不涵蓋不可變基礎架構(gòu)攀例,無狀態(tài)服務以及遷移的重要性船逮。其實每個主題都可以獨立開辟一篇文章。
本文的主要目的是提供一個合理的生產(chǎn)環(huán)境的 Web 應用程序應該是什么樣子的粤铭。
感謝你的閱讀挖胃!
關注公眾號「展白說」,獲取更多有價值的信息梆惯。