使用 HAProxy, PHP, Redis 和 MySQL 輕鬆構建每周上億請求Web網站

來源:互聯網
上載者:User

標籤:blog   http   io   ar   os   使用   sp   for   strong   

英文原文:The Easy Way Of Building A Growing Startup Architecture Using HAProxy, PHP, Redis And MySQL To Ha...

案例是由Antoni Orfin寫的客座文章,他是Octivi的聯合創始人和軟體架構師

在文章中,我將向您展示我們開發的基於HAProxy,PHP,Redis和MySQL的非常簡單的架構的方法,它可以無縫地處理約每周十億次的請求。文章中還列舉了進一步擴充它的可能途徑,並指出了針對於該項目的不常見的模式。

資料:
  • 伺服器:

    • 3x 應用節點

    • 2x MySQL + 1x 用於備份

    • 2x Redis

  • 應用程式:

    • 應用程式每周處理1,000,000,000請求

    • 單一Symfony2執行個體達到700req/s(工作日平均550req/s)

    • 平均回應時間 - 30 毫秒

    • Varnish - 高於12,000 req/s (在壓力測試中達到)

  • 資料存放區:

    • Redis - 160,000,000記錄, 100 GB 的資料 (我們主要的資料存放區庫!),

    • MySQL - 300,000,000記錄 - 300 GB (第三層緩衝)

平台:
  • 監控:

    • Icinga

    • Collectd

  • 應用程式:

    • HAProxy with Keepalived

    • Varnish

    • PHP (PHP-FPM) with Symfony2 Framework

  • 資料存放區:

    • MySQL (master-master) with HAProxy load balancing

    • Redis (master-slave)

    • 背景

      差不多一年前,我們的朋友帶著一個難以解決的問題來到我們的辦公室。他們正在運行一個快速增長的電子商務新興公司,當時他們希望將其擴充到國際水平。

      因為他們仍然是一個新興的公司,提出的解決方案必須是高性價比的,而不是在下一個伺服器上將錢用完。遺留系統一直採用標準的LAMP架構搭建,他們已經有一個強大的PHPTeam Dev。新技術的引進必須要精巧,不能是過於複雜的架構,並且能讓他們現有工作人員進一步維護此平台。

      系統體繫結構必須被設計為可擴充的方式,來實現擴充到下一個市場的計劃。所以我們只好來了,檢查他們的基礎設施...

        

    • 以前的系統是以整體方式設計的。具體來說是一些獨立的基於PHP的Web應用程式(在新興公司有很多所謂的前端網站)。他們中的大多數都使用單一的資料庫,他們共用一些常見的代碼來處理商務邏輯。

      進一步維護這樣的應用可能是一個噩夢。由於部分代碼已經被複製,更改一個網站,可能會導致商務邏輯的不一致 - 他們總是需要在所有的web應用程式中進行相同的更改。

      此外,從專案管理的觀點來看這也是一個問題 - 誰應該負責被分散在多個程式碼程式庫的“那一部分”代碼呢?

    • 根據這一觀察,我們的第一步是提取核心的關鍵業務功能到一個單獨的服務中(這是本文的範圍)。它是面向服務的架構模式。在整個系統範圍內考慮“關注點分離”的原則。該服務是保持一種邏輯的,具體的更進階別的業務功能。給你一個真實的例子 - 服務可以是一個搜尋引擎,銷售系統等。

      前端網站通過一個REST API來和服務進行通訊。響應是基於JSON格式的。我們選擇它的原因是簡單性,相反SOAP始終對開發人員來說比較困難(沒有人喜歡分析XMLS...;-))

      提取的服務並不處理如身分識別驗證和會話管理之類的東西。這是必須的,這些事情是在一個更高的層次來處理的。前端網站負責這一點,因為只有他們才能確定他們的使用者。這樣,我們將服務更簡化 - 在進一步擴充的問題和代碼的東西上。沒有什麼不好的,因為它有不同的任務來處理。 

    • 優點:

      - 不同的子系統(服務)可以很容易被完全不同的Team Dev開發。開發人員之間可以互不干涉。

      - 不用處理使用者授權和訪問問題,因此就不存在常見的等級問題了。

      - 在一個地方維護商務邏輯-不同的前端網站之間不存在冗餘的功能。

      - 易於該服務被福士所接受

      缺點:

      - 系統管理者的工作量更大- 因為服務是基於其自身的架構體系,所以系統管理員就需要對該架構增加關注。

      - 保持向後相容性-在一年的維護中,API 方法的改變多的會不計其數。 問題是這些改變千萬不能破壞向後相容性,不然每個前端網站的代碼都需要修改,而且同時部署所有網站時會增加程式員工作...一年之後,所有的方法仍然能夠與第一版的文檔相容。

    • 應用程式層

      根據請求流,第一層是應用程式層,應用程式層裡麵包括HAProxy負載平衡器,Varnish和Symfony2 網路應用。來自前端網站的請求首先到達HAProxy,然後通過HAProxy分發到應用節點中。

      應用節點配置
      • Xeon [email protected], 64GB RAM, SATA

      • Varnish

      • Apache2

      • PHP 5.4.X running as PHP-FPM, with APC bytecode cache

      我們已經擁有三個這樣的應用伺服器。它是雙活模式下的N+1模式 - ”備份“伺服器主動處理請求。

      保持Varnish在每個節點中的獨立性使得快取命中率更低,但是這種方式下我們就不存在SPOF問題(一個節點失效,全部系統停止運轉)。我們這樣做的目的是考慮可用性高於效能(在我們的案例中效能不是問題)。

      我們選擇Apache2,它也被用在前端網站伺服器中。避免混合進許多技術使得系統管理員的維護更加容易。

    • Symfony2 應用

      應用本身是建立在Symfony2的頂層之上。它是一個完全PHP的棧架構,提供豐富的有用組件,這些組件能夠加速開發的進程。將典型的REST服務建立在一個複雜的架構之上可能對某些人來說不可思議,讓我對其中的原因進行說明:

      • 易於PHP/Symfony開發人員接受 - 客戶的IT團隊包括PHP開發人員。引入新技術(比如Node.js)就意味著需要僱傭新的能夠更好的維護系統的開發人員。

      • 清晰的項目結構 - Symfony2並沒有利用非常複雜的項目結構,但它預設的項目結構非常清晰。招聘新的開發人員進入工程是非常簡單的,因為Symfony2的代碼對他們來講非常熟悉。

      • 現成的組件 - 遵循DRY理念... 沒有人想去重新構造,所以我們也不想。我們廣泛使用Symfony2的控制組件,該組件對於產生CLI命令、製作應用(調試工具列)效能分析工具以及記錄器等是一個非常棒的架構。

      在使用之前,我們做了效能測試以確保其能夠處理設定好的任務量。我們開發了概念驗證模型並使用它運行JMeter。結果令人印象深刻-700req/s的回應時間最高50ms。這是我們確信,在我們的這個項目中可以使用這一複雜結構。

    • 應用分析與監控

      我們使用了Symfony2的工具來監控我們的應用。Symfony2有一個非常棒的效能分析組件,可以用來收集特定方法的執行時間,尤其是那些與第三方服務有關的方法。這樣我們就可以找出潛在的弱點以及應用中最耗時的部分。

      詳細的日誌是必須的。為此,我們使用PHP的Monolog庫,它允許我們產生友好的、完全能夠被開發人員和系統管理者理解的格式化日誌記錄。必須時常謹記的是日誌中要儘可能的增加細節,我們發現日誌越詳細越好。我們使用了不同的記錄層級:

      • 調試 - 一些將要產生的資訊 - 比如在調用外部網路服務之前的請求資訊;一些已經發生的資訊-從API請求返回的響應;

      • 錯誤 - 出現了錯誤但是請求流還沒有停止(比如從第三方API返回的錯誤響應);

      • 危險 - 哎呦… 應用崩潰了。

      在產品環境下,你能夠看到Error層級日誌,以及它下面的Critical層級日誌。在開發/測試環境中,還有Debug日誌可以看到。

      我們將日誌分成不同的文檔(在Monolog庫中他們被稱為“通道”)。主記錄檔用於儲存所有應用範圍的錯誤資訊以及特定通道中的短日誌資訊。我們將來自不同通道中的詳細日誌資訊儲存在不同的檔案中。

    • 可擴充性

      擴充平台上的應用程式層級並不是件難事。 HAProxy的效能並不會被常時間的消耗,我們只需要考慮避免單點故障(SPoF) 所需的冗餘。

      在此模式下只需要增加其他應用節點即可。

      資料層

      我們使用Redis和MySQL儲存所有的資料。當Redis做為主要資料儲存時,MySQL則用於第三層的緩衝儲存。

    • Redis

      當設計我們的系統時,我們需要考慮選擇一個能夠滿足我們設定要求的資料庫:

      • 儲存大量資料時(約2.5億記錄)不能降低效能

      • 主要使用基於特定資源標識符的簡單GETs(沒有尋找或複雜的SELECTs)

      • 能夠在單個請求中擷取大量的資源以最小化延遲

      經過一些調查,我們決定使用Redis。

      • 我們進行的所有操作的複雜度為 O(1) 或 O(N),N代表我們檢索的主鍵數目。這意味著主鍵空間的大小不會影響到效能。

      • 一次檢索的主鍵數目大於100時我們大多使用MGET命令,與在一次迴路中使用多個GETs相比,那樣可以忽略網路延遲。

      最近我們在主從複製模式下運行了兩台Redis伺服器。每個的配置為: Xeon [email protected], 128GB, SSD. 記憶體限制在100GB...記憶體經常被佔滿 :-)

    • 由於應用並沒有完全耗盡單一Redis伺服器的所有效能,因此從屬伺服器主要用於備份以及保持(系統)高可用性。一旦主伺服器宕機,我們可以輕鬆地將應用轉換到從屬伺服器上。進行維護工作或者遷移伺服器時,複製也是很便利的-伺服器的切換非常簡單。

      你可能疑惑為什麼我們的Redis經常處於最大記憶體狀態中。大多數的主鍵是永久類型的-大約佔主鍵空間的90%。而其餘的主鍵則完全是緩衝,我們可以設定他們為TTL(譯者註:Time-To-Live)到期。現在,主鍵空間被分為了兩大部分:一部分是擁有TTL設定的(緩衝)和另一部分沒有TTL設定的(永久資料)。幸虧Redis設定的最大記憶體策略為“volatile-lru"(譯者註:Redis的六種記憶體策略之一,表示只對設定了到期時間的key進行lru),那些最少使用的緩衝主鍵(也只有這些設定了到期)將被自動刪除。(譯者註:應該是the least recently used...)

      那樣的話,我們就可以將單個Redis執行個體既可以當主要儲存使用,也可以當典型緩衝使用。

    • 使用這一模型時,必須謹記的是要監測“到期”主鍵的數量。(譯者註:以下為命令列查看部分)

      db.redis1:6379> info keyspace

      # Keyspace

      db0:keys=16XXXXXXX,expires=11XXXXXX,avg_ttl=0

      當你發現(“到期”主鍵)數量接近危險值0時,就需要啟動切分或者提高記憶體了;-)

      我們如何監視它呢?Icinga檢查能夠監視”到期“數量是否達到了崩潰點。我們也使用Redis曲線實現”失去主鍵“比的可視化。

      一年之後,我可以說我們已經完全融入了Redis。從這個項目開始,Redis就沒有讓我們失望過——沒有過停機也沒有其他事件。

    • MySQL

      除了Redis,我們還使用了傳統的MySQL資料庫。不同的是,我們只用它來做為第三方的緩衝層。我們用它來儲存哪些會佔用Redis太多記憶體的,在近期不會使用的內容,這樣我們就可以把它放在其他的硬碟上。這並不是什麼新奇的技術,我們希望能夠保持堆棧越簡單越好,以便於維護。

      我們有兩個以上的MySQL伺服器,配置為: Xeon [email protected], 64GB RAM, SSD。其中有本機非同步主-主複製。以及一台單獨的從節點用於備份。

    • MySQL的高可用性

      從物理結構圖上你可以看出,在每個MySQL框上有HAProxy,並實現了熱備。通過HAProxy實現與MySQL的串連。

      在每個資料庫伺服器上安裝HAProxy的模式可以確保棧的高可靠性,並且不用為了負載平衡再則更加一台伺服器。

      HAProxy採用主動-被動模式(同一時間只有一個運行)運行。熱備機制可以控制他們的可用性。在熱備的控制下有一個浮點IP(VIP),它可以檢查主負載平衡節點的可用性。當主節點崩潰時,第二(從屬)HAProxy節點就會接管這個IP。

    • 可擴充性

      資料庫通常是一個應用中最大的瓶頸。一般地,沒有必要進行向外擴充操作——此次,我們通過增大Redis和MySQL空間來進行縱向擴充。雖然Redis運行在擁有128GB記憶體的伺服器上,還有剩餘空間——(但是)將他們遷移到擁有256GB記憶體的節點上是可行的。當然大容量也會給一些操作帶來不便,比如快照或者運行伺服器——啟動Redis伺服器將花費更長的時間。

      縱向擴充之後,我們進行(橫向)外部擴充。可喜的是,我們已經為我們的資料準備好了簡單的分割結構。

      Redis中我們有4”重“記錄類型。記錄可以根據資料類型被分到四個伺服器中。我們不想根據雜湊進行分割,而更樂於根據記錄的類型進行分割。這種方式使得我們仍然可以使用通常對一類主鍵表現良好的MGET。

      在MySQL中,資料表採用便於向不同伺服器遷移的結構進行儲存——這些資料表也是基於記錄類型(儲存的)。

      在分析完根據資料類型分割資料的優勢後, 我們來看看雜湊。

    • 經驗教訓
      • 不要共用你的資料庫  - 曾經,有一個前端網站想要將其會話處理轉換到Redis。他們就串連到了我們的資料庫上。這使得我們的Redis緩衝空間被用盡,我們的應用也被拒絕儲存緩衝主鍵。所有的緩衝開始只儲存到MySQL伺服器上,這導致MySQL伺服器的系統開銷過大。

      • 要有詳細的日誌 - 當沒有足夠的日誌資訊時,你就不能很快的調試出哪裡出了問題。有一次,由於缺少某個資訊,我們找不到產生這個問題的原因,不得不等該問題再一次出現(在增加了需要的日誌資訊後)。

      • 使用複雜架構並不意味著會“降低網站(速度)” - 有些人可能會對使用全棧架構來處理每秒如此數量的請求感到驚訝。這全在於你(如何)巧妙地使用你擁有的那些工具——即使在Node.js上你也能啟動並執行很慢。選擇一個能夠提供良好開發環境的技術,而不是去對著不友好的工具進行抱怨(降低開發計程車氣)。

 

誰是背後的應用程式

通過波蘭的軟體公司Octivi設計的平台。 我們專心於可伸縮的結構體系,把焦點集中於效能和實用性。我們還要致謝來自用戶端側的IT部門。

相關文章
  • 使用Symfony2在一周內處理一億個請求 - 我們的整個應用程式的概述

  • 推到極致 - Symfony2滿足高效能需求 - Symfony2軟體架構的細節特點描述


使用 HAProxy, PHP, Redis 和 MySQL 輕鬆構建每周上億請求Web網站

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.