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

jopen 10年前發布 | 41K 次閱讀 PHP Redis MySQL 軟件架構 HAproxy

案例是由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 (第三層緩存)

平臺:

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

  • 監控:

    • Icinga

    • Collectd

  • 應用程序:

    • HAProxy with Keepalived

    • Varnish

    • PHP (PHP-FPM) with Symfony2 Framework

  • 數據存儲:

    • MySQL (master-master) with HAProxy load balancing

    • Redis (master-slave)

案例是由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 (第三層緩存)

平臺:

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

  • 監控:

    • Icinga

    • Collectd

  • 應用程序:

    • HAProxy with Keepalived

    • Varnish

    • PHP (PHP-FPM) with Symfony2 Framework

  • 數據存儲:

    • MySQL (master-master) with HAProxy load balancing

    • Redis (master-slave)

案例是由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 (第三層緩存)

平臺:

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

  • 監控:

    • Icinga

    • Collectd

  • 應用程序:

    • HAProxy with Keepalived

    • Varnish

    • PHP (PHP-FPM) with Symfony2 Framework

  • 數據存儲:

    • MySQL (master-master) with HAProxy load balancing

    • Redis (master-slave)

背景

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

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

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

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

背景

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

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

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

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

背景

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

優點:

- 不同的子系統(服務)可以很容易被完全不同的開發團隊開發。開發者之間可以互不干涉。

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

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

- 易于該服務被大眾所接受

缺點:

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

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

優點:

- 不同的子系統(服務)可以很容易被完全不同的開發團隊開發。開發者之間可以互不干涉。

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

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

- 易于該服務被大眾所接受

缺點:

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

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

優點:

- 不同的子系統(服務)可以很容易被完全不同的開發團隊開發。開發者之間可以互不干涉。

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

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

- 易于該服務被大眾所接受

缺點:

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

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

應用層

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

根據請求流,第一層是應用層,應用層里面包括HAProxy負載均衡器,VarnishSymfony2 網絡應用。來自前端網站的請求首先到達HAProxy,然后通過HAProxy分發到應用節點中。

應用節點配置

  • Xeon E5-1620@3.60GHz, 64GB RAM, SATA

  • Varnish

  • Apache2

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

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

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

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

應用層

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

根據請求流,第一層是應用層,應用層里面包括HAProxy負載均衡器,VarnishSymfony2 網絡應用。來自前端網站的請求首先到達HAProxy,然后通過HAProxy分發到應用節點中。

應用節點配置

  • Xeon E5-1620@3.60GHz, 64GB RAM, SATA

  • Varnish

  • Apache2

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

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

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

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

應用層

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

根據請求流,第一層是應用層,應用層里面包括HAProxy負載均衡器,VarnishSymfony2 網絡應用。來自前端網站的請求首先到達HAProxy,然后通過HAProxy分發到應用節點中。

應用節點配置

  • Xeon E5-1620@3.60GHz, 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的棧框架,提供豐富的有用組件,這些組件能夠加速開發的進程。將典型的REST服務建立在一個復雜的框架之上可能對某些人來說不可思議,讓我對其中的原因進行說明:

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

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

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

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

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庫中他們被稱為“通道”)。主日志文件用于存儲所有應用范圍的錯誤信息以及特定通道中的短日志信息。我們將來自不同通道中的詳細日志信息保存在不同的文件中。

應用分析與監控

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

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

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

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

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

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

我們將日志分成不同的文檔(在Monolog庫中他們被稱為“通道”)。主日志文件用于存儲所有應用范圍的錯誤信息以及特定通道中的短日志信息。我們將來自不同通道中的詳細日志信息保存在不同的文件中。

應用分析與監控

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

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

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

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

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

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

我們將日志分成不同的文檔(在Monolog庫中他們被稱為“通道”)。主日志文件用于存儲所有應用范圍的錯誤信息以及特定通道中的短日志信息。我們將來自不同通道中的詳細日志信息保存在不同的文件中。

可擴展性

擴展平臺上的應用層級并不是件難事。 HAProxy的性能并不會被常時間的消耗,我們只需要考慮避免單點故障(SPoF) 所需的冗余。

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

數據層

我們使用Redis和MySQL存儲所有的數據。當Redis做為主數據存儲時,MySQL則用于第三層的緩存存儲。

可擴展性

擴展平臺上的應用層級并不是件難事。 HAProxy的性能并不會被常時間的消耗,我們只需要考慮避免單點故障(SPoF) 所需的冗余。

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

數據層

我們使用Redis和MySQL存儲所有的數據。當Redis做為主數據存儲時,MySQL則用于第三層的緩存存儲。

可擴展性

擴展平臺上的應用層級并不是件難事。 HAProxy的性能并不會被常時間的消耗,我們只需要考慮避免單點故障(SPoF) 所需的冗余。

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

數據層

我們使用Redis和MySQL存儲所有的數據。當Redis做為主數據存儲時,MySQL則用于第三層的緩存存儲。

Redis

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

  • 存儲大量數據時(約2.5億記錄)不能降低性能

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

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

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

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

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

最近我們在主從復制模式下運行了兩臺Redis服務器。每個的配置為: Xeon E5-2650v2@2.60GHz, 128GB, SSD. 內存限制在100GB...內存經常被占滿 :-)

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

Redis

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

  • 存儲大量數據時(約2.5億記錄)不能降低性能

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

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

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

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

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

最近我們在主從復制模式下運行了兩臺Redis服務器。每個的配置為: Xeon E5-2650v2@2.60GHz, 128GB, SSD. 內存限制在100GB...內存經常被占滿 :-)

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

Redis

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

  • 存儲大量數據時(約2.5億記錄)不能降低性能

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

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

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

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

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

最近我們在主從復制模式下運行了兩臺Redis服務器。每個的配置為: Xeon E5-2650v2@2.60GHz, 128GB, SSD. 內存限制在100GB...內存經常被占滿 :-)

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

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

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

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

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

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

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

由于應用并沒有完全耗盡單一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-expires.png

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

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

db.redis1:6379> info keyspace

# Keyspace

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

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

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

redis-expires.png

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

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

db.redis1:6379> info keyspace

# Keyspace

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

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

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

redis-expires.png

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

MySQL

除了Redis,我們還使用了傳統的MySQL數據庫。不同的是,我們只用它來做為第三方的緩存層。我們用它來存儲哪些會占用Redis太多內存 的,在近期不會使用的內容,這樣我們就可以把它放在其他的硬盤上。這并不是什么新奇的技術,我們希望能夠保持堆棧越簡單越好,以便于維護。

我們有兩個以上的MySQL服務器,配置為: Xeon E5-1620@3.60GHz, 64GB RAM, SSD。其中有本機異步主-主復制。以及一臺單獨的從節點用于備份。

MySQL

除了Redis,我們還使用了傳統的MySQL數據庫。不同的是,我們只用它來做為第三方的緩存層。我們用它來存儲哪些會占用Redis太多內存 的,在近期不會使用的內容,這樣我們就可以把它放在其他的硬盤上。這并不是什么新奇的技術,我們希望能夠保持堆棧越簡單越好,以便于維護。

我們有兩個以上的MySQL服務器,配置為: Xeon E5-1620@3.60GHz, 64GB RAM, SSD。其中有本機異步主-主復制。以及一臺單獨的從節點用于備份。

MySQL

除了Redis,我們還使用了傳統的MySQL數據庫。不同的是,我們只用它來做為第三方的緩存層。我們用它來存儲哪些會占用Redis太多內存 的,在近期不會使用的內容,這樣我們就可以把它放在其他的硬盤上。這并不是什么新奇的技術,我們希望能夠保持堆棧越簡單越好,以便于維護。

我們有兩個以上的MySQL服務器,配置為: Xeon E5-1620@3.60GHz, 64GB RAM, SSD。其中有本機異步主-主復制。以及一臺單獨的從節點用于備份。

MySQL的高可用性

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

在每個數據庫服務器上安裝HAProxy的模式可以確保棧的高可靠性,并且不用為了負載均衡再則更加一臺服務器。

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

MySQL的高可用性

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

在每個數據庫服務器上安裝HAProxy的模式可以確保棧的高可靠性,并且不用為了負載均衡再則更加一臺服務器。

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

MySQL的高可用性

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

在每個數據庫服務器上安裝HAProxy的模式可以確保棧的高可靠性,并且不用為了負載均衡再則更加一臺服務器。

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

可擴展性

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

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

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

在MySQL中,數據表采用便于向不同服務器遷移的結構進行村粗——這些數據表也是基于記錄類型(存儲的)。

在分析完根據數據類型分割數據的優勢后, 我們來看看哈希。

可擴展性

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

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

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

在MySQL中,數據表采用便于向不同服務器遷移的結構進行村粗——這些數據表也是基于記錄類型(存儲的)。

在分析完根據數據類型分割數據的優勢后, 我們來看看哈希。

可擴展性

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

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

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

在MySQL中,數據表采用便于向不同服務器遷移的結構進行村粗——這些數據表也是基于記錄類型(存儲的)。

在分析完根據數據類型分割數據的優勢后, 我們來看看哈希。

經驗教訓

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

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

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

經驗教訓

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

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

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

經驗教訓

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

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

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

誰是背后的應用程序

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

相關文章

誰是背后的應用程序

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

相關文章

誰是背后的應用程序

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

相關文章

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!