當前位置:首頁 » 網頁前端 » web系統大規模並發
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

web系統大規模並發

發布時間: 2022-12-09 06:03:01

❶ web應用高並發導致系統資料庫崩潰一般怎麼解決

1、程序和資料庫部署在同一台伺服器上 2.多學習一些相關的書籍比如:構建高性能Web站點,大規模Web服務開發技術 構建可擴展的Web站點 , Web容量規劃的技術,分布式資料庫系統及其應用。 掌握其原理和結構 。

❷ java web高並發是什麼意思

並發的意思就是有多人同時進行一個操作, 比如你家大門 有兩個人同時進去
這就叫並發了 要是一個人一個人排隊進就不是並發, 要是 幾百上千上萬人同時進大門 就可以稱為高並發了
並發和高並發 其實意思是一樣的 不同的只是並發數量上的區別

web的並發是指 多人同時向一個url發送請求

❸ 如何解決web大流量,高並發的問題

以下是一些總結的方法: 第一,確認伺服器硬體是否足夠支持當前的流量。 普通的P4伺服器一般最多能支持每天10萬獨立IP,如果訪問量比這個還要大,那麼必須首先配置一台更高性能的專用伺服器才能解決問題,否則怎麼優化都不可能徹底解決性能問題。
第二,優化資料庫訪問。 伺服器的負載過大,一個重要的原因是CPU負荷過大,降低伺服器CPU的負荷,才能夠有效打破瓶頸。而使用靜態頁面可以使得CPU的負荷最小化。前台實現完全的靜態化 當然最好,可以完全不用訪問資料庫,不過對於頻繁更新的網站,靜態化往往不能滿足某些功能。 緩存技術 就是另一個解決方案,就是將動態數據存儲到緩存文件中,動態網頁直接調用這些文件,而不必再訪問資料庫,WordPress和Z-Blog都大量使用這種緩存技術 。我自己也寫過一個Z-Blog的計數器插件,也是基於這樣的原理。 如果確實無法避免對資料庫的訪問,那麼可以嘗試優化資料庫的查詢sql.避免使用Select *from這樣的語句,每次查詢只返回自己需要的結果,避免短時間內的大量SQL查詢。
第三,禁止外部的盜鏈。 外部網站的圖片或者文件盜鏈往往會帶來大量的負載壓力,因此應該嚴格限制外部對於自身的圖片或者文件盜鏈,好在目前可以簡單地通過refer來控制盜鏈,Apache自己就可以通過配置來禁止盜鏈,IIS也有一些第三方的ISAPI可以實現同樣的功能。當然,偽造refer也可以通過代碼來實現盜 鏈,不過目前蓄意偽造refer盜鏈的還不多,可以先不去考慮,或者使用非技術手段來解決,比如在圖片上增加水印。
第四,控制大文件的下載。 大文件的下載會佔用很大的流量,並且對於非SCSI硬碟來說,大量文件下載會消耗CPU,使得網站響應能力下降。因此,盡量不要提供超過2M的大 文件下載,如果需要提供,建議將大文件放在另外一台伺服器上。目前有不少免費的Web2.0網站提供圖片分享和文件分享功能,因此可以盡量將圖片和文件上 傳到這些分享網站。
第五,使用不同主機分流主要流量 將文件放在不同的主機上,提供不同的鏡像供用戶下載。比如如果覺得RSS文件佔用流量大,那麼使用FeedBurner或者FeedSky等服務將RSS輸出放在其他主機上,這樣別人訪問的流量壓力就大多集中在FeedBurner的主機上,RSS就不佔用太多資源了。
第六,使用流量分析統計軟體。 在網站上安裝一個流量分析統計軟體,可以即時知道哪些地方耗費了大量流量,哪些頁面需要再進行優化,因此,解決流量問題還需要進行精確的統計分析 才可以。我推薦使用的流量分析統計軟體是GoogleAnalytics(Google分析)。我使用過程中感覺其效果非常不錯,稍後我將詳細介紹一下 GoogleAnalytics的一些使用常識和技巧。 1.分表 2.讀寫分離 3.前端優化。Nginx替換Apache(前端做負載均衡) 個人認為主要還是分布式架構是否到位,mysql和緩存的優化都是有限度的優化,而分布式架構做出來了,PV增長後,只需要堆機器就能擴容。
另附一些優化經驗,首先學會用explain語句分析select語句,優化索引、表結構,其次,合理運用memcache等緩存,降低mysql的負載,最後,如果可能的話,盡量用facebook的hiphop-php把PHP編譯了,提高程序效率。

❹ 如何控制web程序中的並發行為

1、提供HTML靜態訪問

web界面上最快的訪問速度是什麼?當然是最原始的HTML文件訪問,對於其他語言 比如 jsp ,asp,php等等,他們首先要通過伺服器解析成html之後在返回給訪問者,如果我們能提供全部是htm來的頁面,那麼就能大大的降低伺服器和資料庫資源的利用和提高網站的並發,所以我們盡可能使我們的網站上的頁面採用靜態頁面來實現,這個最簡單的方法其實也是最有效的方法。當然實現這種方式大家比較了解的就是信息發布系統CMS,信息發布系統可以實現最簡單的信息錄入自動生成靜態頁面,還能具備頻道管理、許可權管理、自動抓取等功能,對於一個大型網站來說,擁有一套高效、可管理的CMS是必不可少的。
在後續的文章中我們會單獨的使用jsp + servlet實現一個簡單的信息發布系統.
2、使用獨立的圖片伺服器

為什麼要把圖片單獨設置一個伺服器?對於Web伺服器來說,圖片消耗的伺服器資源是最多的,如果能把所有的圖片資源放到一個單獨的圖片伺服器中進行處理的話,可以降低提供頁面訪問請求的伺服器系統壓力,從而能進一步的提高web程序的並發.所以在有條件的情況下最好能把圖片放置到一個單獨的伺服器中.
3、配置多台資料庫伺服器,多個資料庫集群
集群(Cluster)技術是使用特定的連接方式,將價格相對較低的硬體設備結合起來,同時也能提供高性能相當的任務處理能力。
越是大型高並發的應用,資料庫的壓力就會越大,如果資料庫操作很頻繁,資料庫的瓶頸很快就能顯現出來,這時一台資料庫將很快無法滿足應用,於是我們需要使用資料庫集群。
資料庫集群就是使用多個資料庫伺服器分擔請求的壓力,達到快速響應的目的.
4、使用緩存
所謂的緩存就是把數據咱是放置到內存中,前台在請求的時候直接從內存中讀取數據,而不需要去查詢資料庫或者讀取文件等,這樣就能做到最快的響應。網站架構和網站開發中的緩存是非常重要的。
目前有很多開源的緩沖實現方案,APC,File,SQLite,Memcache等等各種類庫實現著不同的緩存方式,只有通過了解他們的實現方式,根據具體應用具體選擇,才會使緩存系統發揮出最大的性能。
對於java開發來說,大名頂頂的 分布式緩存系統Memcache 可能是最好的選擇,他提供一個基於Socket的訪問方式,使得該緩存系統支持遠程讀寫訪問。盡管這個緩存的內容可能是存在內存中,也可能是存在文件內。

❺ C#web開發中出現高並發具體處理方法有哪些

盡量使用緩存,包括用戶緩存,信息緩存等,多花點內存來做緩存,可以大量減少與資料庫的交互,提高性能。
用jprofiler等工具找出性能瓶頸,減少額外的開銷。
優化資料庫查詢語句,減少直接使用hibernate等工具的直接生成語句(僅耗時較長的查詢做優化)。
優化資料庫結構,多做索引,提高查詢效率。
統計的功能盡量做緩存,或按每天一統計或定時統計相關報表,避免需要時進行統計的功能。

能使用靜態頁面的地方盡量使用,減少容器的解析(盡量將動態內容生成靜態html來顯示)。
解決以上問題後,使用伺服器集群來解決單台的瓶頸問題。
基本上以上述問題解決後,達到系統最優。

❻ webservice大並發數量 應該怎麼處理

先學測試吧。不是那種業務功能的測試,是系統的測試。因為要解決大數據量、高並發的問題,我個人的知識與經驗是:1、先用單機測試。用工具產生大並發量去轟擊伺服器,直至伺服器緩慢,甚至接近崩潰;3、找到系統瓶頸後,優化,解決這個瓶頸,然後再循環測試。這時你又會發現新的瓶頸,再解決。循環1 - 3步,直到各方面基本平衡為止。4、當單機無法解決問題的時候,接著開始考慮負載均衡,考慮分布式方案,然後再用 1 - 3 的步驟分析與測試。

❼ 怎麼評估web系統的並發量

你可以使用loadrunner進行測試,然後進行分析數據,測出最大並發數。

❽ 大並發web報表系統 用什麼框架

python的web框架很多 django (大而全,模板,orm都自帶) flask (pocoo出品,比屬精品,自帶jinja2模板,可以替換) web.py (這個我沒用過,作者自殺,白瞎了一個高手) bottle (只有一個文件的框架,需要自己構建整個開發體系) uliweb (中國人開發的,也很不錯) Tornado (非同步框架,適合長連接,比如在線聊天之類的) Python框架雖然說是百花齊放,但仍然有那麼一家是最大的,它就是Django。Django為人所稱道的地方主要有: ①完美的文檔,Django的成功,我覺得很大一部分原因要歸功於Django近乎完美的官方文檔(包括Django book)。 ②全套的解決方案,Django象Rails一樣,提供全套的解決方案(full-stack framework + batteries included),基本要什麼有什麼(比如:cache、session、feed、orm、geo、auth),而且全部Django自己造,開發網 站應手的工具Django基本都給你做好了,因此開發效率是不用說的,出了問題也算好找,不在你的代碼里就在Django的源碼里。 ③強大的URL路由配置,Django讓你可以設計出非常優雅的URL,在Django里你基本可以跟醜陋的GET參數說拜拜。 ④自助管理後台,admin interface是Django里比較吸引眼球的一項contrib,讓你幾乎不用寫一行代碼就擁有一個完整的後台管理界面。

❾ javaWeb如何提高並發數

  1. 對Collection、Map介面的類對象初始化時要先分配合理的空間大小,同時還要按照自已的實際需求選擇合適的對象。

2.優化循環體

循環是比較重復運行的地方,如果循環次數很大,循環體內不好的代碼對效率的影響就會被放大而變的突出。

3.少用new初始化一個實例

盡量少用new來初始化一個類的實例,當一個對象是用new進行初始化時,其構造函數鏈的所有構造函數都被調用到,所以new操作符是很消耗系統資源的,new一個對象耗時往往是局部變數賦值耗時的上千倍。同時,當生成對象後,系統還要花時間進行垃圾回收和處理。當new創建對象不可避免時,注意避免多次的使用new初始化一個對象。盡量在使用時再創建該對象,另外,應該盡量重復使用一個對象,而不是聲明新的同類對象。一個重用對象的方法是改變對象的值,如可以通過setValue之類的方法改變對象的變數達到重用的目的。

4 .選擇合適的方法調用:

在Java中,一切都是對象,如果有方法(Method)調用,處理器先要檢查該方法是屬於哪個對象,該對象是否有效,對象屬於什麼類型,然後選擇合適的方法並調用。可以減少方法的調用,不影響可讀性等情況下,可以把幾個小的方法合成一個大的方法。另外,在方法前加上final,private關鍵字有利於編譯器的優化。

5.異常處理技巧

異常是Java的一種錯誤處理機制,對程序來說是非常有用的,但是異常對性能不利。拋出異常首先要創建一個新的對象,並進行相關的處理,造成系統的開銷,所以異常應該用在錯誤處理的情況,不應該用來控製程序流程,流程盡量用while,if等處理。在不是很影響代碼健壯性的前提下,可以把幾個try/catch塊合成一個。

6 .盡量使用局部變數

盡量使用局部變數,調用方法時傳遞的參數以及在調用中創建的臨時變數都保存在棧(Stack) 中,速度較快。其他變數,如靜態變數、實例變數等,都在堆(Heap)中創建,速度較慢。

7.同步處理技巧

同步主要出現在多線程的情況,為多線程同時運行時提供對象數據安全的機制,多線程是比較復雜話題,應用多線程也是為了獲得性能的提升,應該盡可能減少同步。

另外,如果需要同步的地方,可以減少同步的代碼段,如只同步某個方法或函數,而不是整個代碼。

8 .盡可能的使用Java自身提供的API

Java的API一般都做了性能的考慮,如果完成相同的功能,優先使用API而不是自己寫的代碼,如數組復制。

9 .盡量減少I/O操作

輸入/輸出(I/O)包括很多方面,我們知道,進行I/O操作是很消耗系統資源的。程序中應該盡量少用I/O操作。使用時可以注意: . 合理控制輸出函數System.out.println()對於大多時候是有用的,特別是系統調試的時候,但也會產生大量的信息出現在控制台和日誌上,同時輸出時,有序列化和同步的過程,造成了開銷。

特別是在發行版中,要合理的控制輸出,可以在項目開發時,設計好一個Debug的工具類,在該類中可以實現輸出開關,輸出的級別,根據不同的情況進行不同的輸出的控制。

10 .盡量使用緩存

讀寫內存要比讀寫硬碟上的文件要快很多,應盡可能使用緩沖,以便直接從內存中讀取數據。盡可能使用帶有Buffer的類代替沒有Buffer的類,如可以用BufferedReader 代替Reader,用BufferedWriter代替Writer來進行處理I/O操作。

同樣可以用BufferedInputStream代替InputStream都可以獲得性能的提高

11 .盡量不使用同步:

Servlet是多線程的,以處理不同的請求,基於前面同步的分析,如果有太多的同步就失去了多線程的優勢了。

12.不用保存太多的信息在HttpSession中

很多時候,存儲一些對象在HttpSession中是有必要的,可以加快系統的開發,如網上商店系統會把購物車信息保存在該用戶的Session中,但當存儲大量的信息或是大的對象在會話中時,是有害的,特別是當系統中用戶的訪問量很大,對內存的需求就會很高。具體開發時,在這兩者之間應作好權衡。

13.清除SESSION:

通常情況,當達到設定的超時時間時,同時有些Session沒有了活動,伺服器會釋放這些沒有活動的Session,.. 不過這種情況下,特別是多用戶並訪時,系統內存要維護多個的無效Session。當用戶退出時,應該手動釋放,回收資源,實現如下:..
HttpSession theSession = request.getSession();
// 獲取當前Session
if(theSession != null){
theSession.invalidate(); // 使該Session失效
}

14 .緩存Home介面

EJB庫使用Enterprise Bean 的客戶端通過它的Home介面創建它的實例。客戶端能通過JNDI訪問它。伺服器通過Lookup方法來獲取。
JNDI是個遠程對象,通過RMI方式調用,對它的訪問往往是比較費時的。所以,在設計時可以設計一個類專門用來緩存Home介面,在系統初始化時就獲得需要的Home介面並緩存,以後的引用只要引用緩存即可。

15 .使用快速度的Jdbc驅動

JDBC API包括兩種實現介面形式,一種是純Java實現的驅動,一種利用ODBC驅動和資料庫客戶端實現,具體有四種驅動模式:

第一類:JDBC-ODBC橋,再加上ODBC驅動程序。
JDBC驅動程序是JDBC-ODBC橋再加上一個ODBC驅動程序。建議第一類驅動程序只用於原型開發,而不要用於正式的運行環境。橋接驅動程序由Sun提供,它的目標是支持傳統的資料庫系統。Sun為該軟體提供關鍵問題的補丁,但不為該軟體的最終用戶提供支持。一般地,橋接驅動程序用於已經在ODBC技術上投資的情形,例如已經投資了Windows應用伺服器。
盡管Sun提供了JDBC-ODBC橋接驅動程序,但由於ODBC會在客戶端裝載二進制代碼和資料庫客戶端代碼,這種技術不適用於高事務性的環境。另外,第一類JDBC驅動程序不支持完整的Java命令集,而是局限於ODBC驅動程序的功能,這種驅動方式也叫胖客戶,主要用於低並發請求,大數據量傳輸的應用。

第二類:本機API,部分是Java的驅動程序。
JDBC驅動程序是本機API的部分Java代碼的驅動程序,用於把JDBC調用轉換成主流資料庫API的本機調用。這類驅動程序也存在與第一類驅動程序一樣的性能問題,即客戶端載入二進制代碼的問題,而且它們被綁定了特定的平台。
第二類驅動程序要求編寫面向特定平台的代碼,主流的資料庫廠商,例如Oracle和IBM,都為它們的企業資料庫平台提供了第二類驅動程序,使用這些驅動程序的開發者必須及時跟進不同資料庫廠商針對不同操作系統發行的各個驅動程序版本。
另外,由於第二類驅動程序沒有使用純Java的API,把Java應用連接到數據源時,往往必須執行一些額外的配置工作。很多時候,第二類驅動程序不能在體系結構上與大型主機的數據源兼容;即使做到了兼容,效果也是比較差。

第三類:面向資料庫中間件的純Java驅動程序。
JDBC驅動程序是面向資料庫中間件的純Java驅動程序,JDBC調用被轉換成一種中間件廠商的協議,中間件再把這些調用轉換到資料庫API。第三類JDBC驅動程序的優點是它以伺服器為基礎,也就是不再需要客戶端的本機代碼,這使第三類驅動程序要比第一、二兩類快。另外,開發者還可以利用單一的驅動程序連接到多種資料庫。

第四類:直接面向資料庫的純Java驅動程序。
JDBC驅動程序是直接面向資料庫的純Java驅動程序,即所謂的「瘦」(thin)驅動程序,它把JDBC調用轉換成某種直接可被DBMS使用的網路協議,這樣,客戶機和應用伺服器可以直接調用DBMS伺服器。對於第四類驅動程序,不同DBMS的驅動程序不同。因此,在一個異構計算環境中,驅動程序的數量可能會比較多。但是,由於第四類驅動程序具有較高的性能,能夠直接訪問DBMS,所以這一問題就不那麼突出了, 這種驅動方式,主要用於高並發,低數據量請求的應用中。

16.使用Jdbc鏈接池

為了提高訪問資料庫的性能,我們還可以使用JDBC 2.0的一些規范和特性,JDBC是佔用資源的,在使用資料庫連接時可以使用連接池Connection Pooling,避免頻繁打開、關閉Connection。而我們知道,獲取Connection是比較消耗系統資源的。
Connection緩沖池:當一個應用程序關閉一個資料庫連接時,這個連接並不真正釋放而是被循環利用,建立連接是消耗較大的操作,循環利用連接可以顯著的提高性能,因為可以減少新連接的建立。

一個通過DataSource獲取緩沖池獲得連接,並連接到一個CustomerDB數據源的代碼演示如下:
Context ctx = new InitialContext();
DataSource dataSource = (DataSource) ctx.lookup(「jdbc/CustomerDB」);
Connection conn = dataSource.getConnection(「password」,」username」);

17.緩存DataSorce

一個DataSource對象代表一個實際的數據源。這個數據源可以是從關系資料庫到表格形式的文件,完全依賴於它是怎樣實現的,一個數據源對象注冊到JNDI名字服務後,應用程序就可以從JNDI伺服器上取得該對象,並使用之和數據源建立連接。
通過上面的例子,我們知道DataSource是從連接池獲得連接的一種方式,通過JNDI方式獲得,是佔用資源的。
為了避免再次的JNDI調用,可以系統中緩存要使用的DataSource。

18.即時關閉使用過的資源

互聯網應用系統一般是並發的系統,在每次申請和使用完資源後,應該釋放供別人使用,使用完成後應該保證徹底的釋放。

19 .架構選型

CoreMediaCMS將整個應用分成四成架構,每一層都可以獨立於其他層而正常運行,每一層都可以分布式布署,極大的提高了應用系統的穩定性、可擴展性、支持高並發的要求,每一次之前通過中間件Corba進行穩定的傳輸數據。

20 .開發框架的選型

充分利用開源框架,可以大大提高開發效率。很多初級開發者,都採用DB JavaBean JSP這種初級的開發模式,而現在主要使用Struts、Spring等MVC開發框架。

常用開發框架構選型有:

Struts、Spring、Webwork等。

天極傳媒選擇的開發框架是:Struts Spring iBatis,在這個開發框架里,充分利用了Struts、Spring各自己的優點,可以選擇StutsMVC,也可以選擇Spring MVC。

21.分級存儲

1)資料庫數據分級存儲:

將經常訪問的數據和訪問頻度低的數據,分別存放到不同的分區,甚至存放到不同的資料庫伺服器,以便合進分配硬碟I/O及系統I/O。

2)網站內容發布之後,分級存儲:

任何一個大型的網站,一般都有海量的內容,為了提高訪問效率,應搭建分級存儲體系,根據應用的重要性和訪問並發要求,將這些內容分級存儲,同時將靜態內容中的靜態頁面文件、圖片文件、下載文件分不同的Web伺服器訪問,降低I/O爭用,提高訪問效率,同時讓數據存儲、管理、備份更加清晰。

22 .頁面靜態化

一個大型網站,既有靜態內容,也有動態內容。靜態內容,直接通過Apache或者Squid訪問,效率高,穩定可靠,更多的是受伺服器等硬體設備的I/O吞吐量、網路環境及頁面代碼本身質量限制,不受應用系統及資料庫性能限制,這些內容往往訪問速度和效率不會有較大的問題。

而動態內容,除了受硬體設備I/O、操作系統I/O及內容、網路環境及頁面代碼的影響,還要受應用伺服器和資料庫性能影響,因此,這部份內容,要盡可能作靜態化或者偽靜態,並採用緩存技術,將其緩存,以減少對應用伺服器和資料庫伺服器的操作次數,提高用戶訪問效率和穩定性。

23.緩存策略

對於構建的業務系統,如果有些數據要經常要從資料庫中讀取,同時,這些數據又不經常變化,這些數據就可以在系統中緩存起來,使用時直接讀取緩存,而不用頻繁的訪問資料庫讀取數據。
緩存工作可以在系統初始化時一次性讀取數據,特別是一些只讀的數據,當數據更新時更新資料庫內容,同時更新緩存的數據值。

例如:在CMS2005系統中,我們將很少發生變化的網站節點樹數據,緩存在客戶端,當用戶登錄時,一次性讀入到客戶端緩存起來,以後編輯在使用時,不用再從資料庫中讀取,大大提高了應用系統的訪問速度。

當然,也可以將資料庫中重復訪問的數據緩存在應用伺服器內存中,減少對資料庫的訪問次數,Java常用的緩存技術產品有:MemoryCache、OSCache等。

❿ php怎麼處理高並發

以下內容轉載自徐漢彬大牛的博客億級Web系統搭建——單機到分布式集群

當一個Web系統從日訪問量10萬逐步增長到1000萬,甚至超過1億的過程中,Web系統承受的壓力會越來越大,在這個過程中,我們會遇到很多的問題。為了解決這些性能壓力帶來問題,我們需要在Web系統架構層面搭建多個層次的緩存機制。在不同的壓力階段,我們會遇到不同的問題,通過搭建不同的服務和架構來解決。

Web負載均衡

Web負載均衡(Load Balancing),簡單地說就是給我們的伺服器集群分配「工作任務」,而採用恰當的分配方式,對於保護處於後端的Web伺服器來說,非常重要。

負載均衡的策略有很多,我們從簡單的講起哈。

1.HTTP重定向

當用戶發來請求的時候,Web伺服器通過修改HTTP響應頭中的Location標記來返回一個新的url,然後瀏覽器再繼續請求這個新url,實際上就是頁面重定向。通過重定向,來達到「負載均衡」的目標。例如,我們在下載PHP源碼包的時候,點擊下載鏈接時,為了解決不同國家和地域下載速度的問題,它會返回一個離我們近的下載地址。重定向的HTTP返回碼是302

這個重定向非常容易實現,並且可以自定義各種策略。但是,它在大規模訪問量下,性能不佳。而且,給用戶的體驗也不好,實際請求發生重定向,增加了網路延時。

2. 反向代理負載均衡

反向代理服務的核心工作主要是轉發HTTP請求,扮演了瀏覽器端和後台Web伺服器中轉的角色。因為它工作在HTTP層(應用層),也就是網路七層結構中的第七層,因此也被稱為「七層負載均衡」。可以做反向代理的軟體很多,比較常見的一種是Nginx。

Nginx是一種非常靈活的反向代理軟體,可以自由定製化轉發策略,分配伺服器流量的權重等。反向代理中,常見的一個問題,就是Web伺服器存儲的session數據,因為一般負載均衡的策略都是隨機分配請求的。同一個登錄用戶的請求,無法保證一定分配到相同的Web機器上,會導致無法找到session的問題。

解決方案主要有兩種:

1.配置反向代理的轉發規則,讓同一個用戶的請求一定落到同一台機器上(通過分析cookie),復雜的轉發規則將會消耗更多的CPU,也增加了代理伺服器的負擔。

2.將session這類的信息,專門用某個獨立服務來存儲,例如redis/memchache,這個方案是比較推薦的。

反向代理服務,也是可以開啟緩存的,如果開啟了,會增加反向代理的負擔,需要謹慎使用。這種負載均衡策略實現和部署非常簡單,而且性能表現也比較好。但是,它有「單點故障」的問題,如果掛了,會帶來很多的麻煩。而且,到了後期Web伺服器繼續增加,它本身可能成為系統的瓶頸。

3. IP負載均衡

IP負載均衡服務是工作在網路層(修改IP)和傳輸層(修改埠,第四層),比起工作在應用層(第七層)性能要高出非常多。原理是,他是對IP層的數據包的IP地址和埠信息進行修改,達到負載均衡的目的。這種方式,也被稱為「四層負載均衡」。常見的負載均衡方式,是LVS(Linux Virtual Server,Linux虛擬服務),通過IPVS(IP Virtual Server,IP虛擬服務)來實現。

在負載均衡伺服器收到客戶端的IP包的時候,會修改IP包的目標IP地址或埠,然後原封不動地投遞到內部網路中,數據包會流入到實際Web伺服器。實際伺服器處理完成後,又會將數據包投遞回給負載均衡伺服器,它再修改目標IP地址為用戶IP地址,最終回到客戶端。

上述的方式叫LVS-NAT,除此之外,還有LVS-RD(直接路由),LVS-TUN(IP隧道),三者之間都屬於LVS的方式,但是有一定的區別,篇幅問題,不贅敘。

IP負載均衡的性能要高出Nginx的反向代理很多,它只處理到傳輸層為止的數據包,並不做進一步的組包,然後直接轉發給實際伺服器。不過,它的配置和搭建比較復雜。

4. DNS負載均衡

DNS(Domain Name System)負責域名解析的服務,域名url實際上是伺服器的別名,實際映射是一個IP地址,解析過程,就是DNS完成域名到IP的映射。而一個域名是可以配置成對應多個IP的。因此,DNS也就可以作為負載均衡服務。

這種負載均衡策略,配置簡單,性能極佳。但是,不能自由定義規則,而且,變更被映射的IP或者機器故障時很麻煩,還存在DNS生效延遲的問題。

5. DNS/GSLB負載均衡

我們常用的CDN(Content Delivery Network,內容分發網路)實現方式,其實就是在同一個域名映射為多IP的基礎上更進一步,通過GSLB(Global Server Load Balance,全局負載均衡)按照指定規則映射域名的IP。一般情況下都是按照地理位置,將離用戶近的IP返回給用戶,減少網路傳輸中的路由節點之間的跳躍消耗。

「向上尋找」,實際過程是LDNS(Local DNS)先向根域名服務(Root Name Server)獲取到頂級根的Name Server(例如.com的),然後得到指定域名的授權DNS,然後再獲得實際伺服器IP。

CDN在Web系統中,一般情況下是用來解決大小較大的靜態資源(html/Js/Css/圖片等)的載入問題,讓這些比較依賴網路下載的內容,盡可能離用戶更近,提升用戶體驗。

例如,我訪問了一張imgcache.gtimg.cn上的圖片(騰訊的自建CDN,不使用qq.com域名的原因是防止http請求的時候,帶上了多餘的cookie信息),我獲得的IP是183.60.217.90。

這種方式,和前面的DNS負載均衡一樣,不僅性能極佳,而且支持配置多種策略。但是,搭建和維護成本非常高。互聯網一線公司,會自建CDN服務,中小型公司一般使用第三方提供的CDN。

Web系統的緩存機制的建立和優化

剛剛我們講完了Web系統的外部網路環境,現在我們開始關注我們Web系統自身的性能問題。我們的Web站點隨著訪問量的上升,會遇到很多的挑戰,解決這些問題不僅僅是擴容機器這么簡單,建立和使用合適的緩存機制才是根本。

最開始,我們的Web系統架構可能是這樣的,每個環節,都可能只有1台機器。

我們從最根本的數據存儲開始看哈。

一、 MySQL資料庫內部緩存使用

MySQL的緩存機制,就從先從MySQL內部開始,下面的內容將以最常見的InnoDB存儲引擎為主。

1. 建立恰當的索引

最簡單的是建立索引,索引在表數據比較大的時候,起到快速檢索數據的作用,但是成本也是有的。首先,佔用了一定的磁碟空間,其中組合索引最突出,使用需要謹慎,它產生的索引甚至會比源數據更大。其次,建立索引之後的數據insert/update/delete等操作,因為需要更新原來的索引,耗時會增加。當然,實際上我們的系統從總體來說,是以select查詢操作居多,因此,索引的使用仍然對系統性能有大幅提升的作用。

2. 資料庫連接線程池緩存

如果,每一個資料庫操作請求都需要創建和銷毀連接的話,對資料庫來說,無疑也是一種巨大的開銷。為了減少這類型的開銷,可以在MySQL中配置thread_cache_size來表示保留多少線程用於復用。線程不夠的時候,再創建,空閑過多的時候,則銷毀。

其實,還有更為激進一點的做法,使用pconnect(資料庫長連接),線程一旦創建在很長時間內都保持著。但是,在訪問量比較大,機器比較多的情況下,這種用法很可能會導致「資料庫連接數耗盡」,因為建立連接並不回收,最終達到資料庫的max_connections(最大連接數)。因此,長連接的用法通常需要在CGI和MySQL之間實現一個「連接池」服務,控制CGI機器「盲目」創建連接數。

建立資料庫連接池服務,有很多實現的方式,PHP的話,我推薦使用swoole(PHP的一個網路通訊拓展)來實現。

3. Innodb緩存設置(innodb_buffer_pool_size)

innodb_buffer_pool_size這是個用來保存索引和數據的內存緩存區,如果機器是MySQL獨占的機器,一般推薦為機器物理內存的80%。在取表數據的場景中,它可以減少磁碟IO。一般來說,這個值設置越大,cache命中率會越高。

4. 分庫/分表/分區。

MySQL資料庫表一般承受數據量在百萬級別,再往上增長,各項性能將會出現大幅度下降,因此,當我們預見數據量會超過這個量級的時候,建議進行分庫/分表/分區等操作。最好的做法,是服務在搭建之初就設計為分庫分表的存儲模式,從根本上杜絕中後期的風險。不過,會犧牲一些便利性,例如列表式的查詢,同時,也增加了維護的復雜度。不過,到了數據量千萬級別或者以上的時候,我們會發現,它們都是值得的。

二、 MySQL資料庫多台服務搭建

1台MySQL機器,實際上是高風險的單點,因為如果它掛了,我們Web服務就不可用了。而且,隨著Web系統訪問量繼續增加,終於有一天,我們發現1台MySQL伺服器無法支撐下去,我們開始需要使用更多的MySQL機器。當引入多台MySQL機器的時候,很多新的問題又將產生。

1. 建立MySQL主從,從庫作為備份

這種做法純粹為了解決「單點故障」的問題,在主庫出故障的時候,切換到從庫。不過,這種做法實際上有點浪費資源,因為從庫實際上被閑著了。

2. MySQL讀寫分離,主庫寫,從庫讀。

兩台資料庫做讀寫分離,主庫負責寫入類的操作,從庫負責讀的操作。並且,如果主庫發生故障,仍然不影響讀的操作,同時也可以將全部讀寫都臨時切換到從庫中(需要注意流量,可能會因為流量過大,把從庫也拖垮)。

3. 主主互備。

兩台MySQL之間互為彼此的從庫,同時又是主庫。這種方案,既做到了訪問量的壓力分流,同時也解決了「單點故障」問題。任何一台故障,都還有另外一套可供使用的服務。

不過,這種方案,只能用在兩台機器的場景。如果業務拓展還是很快的話,可以選擇將業務分離,建立多個主主互備。

三、 MySQL資料庫機器之間的數據同步

每當我們解決一個問題,新的問題必然誕生在舊的解決方案上。當我們有多台MySQL,在業務高峰期,很可能出現兩個庫之間的數據有延遲的場景。並且,網路和機器負載等,也會影響數據同步的延遲。我們曾經遇到過,在日訪問量接近1億的特殊場景下,出現,從庫數據需要很多天才能同步追上主庫的數據。這種場景下,從庫基本失去效用了。

於是,解決同步問題,就是我們下一步需要關注的點。

1. MySQL自帶多線程同步

MySQL5.6開始支持主庫和從庫數據同步,走多線程。但是,限制也是比較明顯的,只能以庫為單位。MySQL數據同步是通過binlog日誌,主庫寫入到binlog日誌的操作,是具有順序的,尤其當SQL操作中含有對於表結構的修改等操作,對於後續的SQL語句操作是有影響的。因此,從庫同步數據,必須走單進程。

2. 自己實現解析binlog,多線程寫入。

以資料庫的表為單位,解析binlog多張表同時做數據同步。這樣做的話,的確能夠加快數據同步的效率,但是,如果表和表之間存在結構關系或者數據依賴的話,則同樣存在寫入順序的問題。這種方式,可用於一些比較穩定並且相對獨立的數據表。

國內一線互聯網公司,大部分都是通過這種方式,來加快數據同步效率。還有更為激進的做法,是直接解析binlog,忽略以表為單位,直接寫入。但是這種做法,實現復雜,使用范圍就更受到限制,只能用於一些場景特殊的資料庫中(沒有表結構變更,表和表之間沒有數據依賴等特殊表)。

四、 在Web伺服器和資料庫之間建立緩存

實際上,解決大訪問量的問題,不能僅僅著眼於資料庫層面。根據「二八定律」,80%的請求只關注在20%的熱點數據上。因此,我們應該建立Web伺服器和資料庫之間的緩存機制。這種機制,可以用磁碟作為緩存,也可以用內存緩存的方式。通過它們,將大部分的熱點數據查詢,阻擋在資料庫之前。

1. 頁面靜態化

用戶訪問網站的某個頁面,頁面上的大部分內容在很長一段時間內,可能都是沒有變化的。例如一篇新聞報道,一旦發布幾乎是不會修改內容的。這樣的話,通過CGI生成的靜態html頁面緩存到Web伺服器的磁碟本地。除了第一次,是通過動態CGI查詢資料庫獲取之外,之後都直接將本地磁碟文件返回給用戶。

在Web系統規模比較小的時候,這種做法看似完美。但是,一旦Web系統規模變大,例如當我有100台的Web伺服器的時候。那樣這些磁碟文件,將會有100份,這個是資源浪費,也不好維護。這個時候有人會想,可以集中一台伺服器存起來,呵呵,不如看看下面一種緩存方式吧,它就是這樣做的。

2. 單台內存緩存

通過頁面靜態化的例子中,我們可以知道將「緩存」搭建在Web機器本機是不好維護的,會帶來更多問題(實際上,通過PHP的apc拓展,可通過Key/value操作Web伺服器的本機內存)。因此,我們選擇搭建的內存緩存服務,也必須是一個獨立的服務。

內存緩存的選擇,主要有redis/memcache。從性能上說,兩者差別不大,從功能豐富程度上說,Redis更勝一籌。

3. 內存緩存集群

當我們搭建單台內存緩存完畢,我們又會面臨單點故障的問題,因此,我們必須將它變成一個集群。簡單的做法,是給他增加一個slave作為備份機器。但是,如果請求量真的很多,我們發現cache命中率不高,需要更多的機器內存呢?因此,我們更建議將它配置成一個集群。例如,類似redis cluster。

Redis cluster集群內的Redis互為多組主從,同時每個節點都可以接受請求,在拓展集群的時候比較方便。客戶端可以向任意一個節點發送請求,如果是它的「負責」的內容,則直接返回內容。否則,查找實際負責Redis節點,然後將地址告知客戶端,客戶端重新請求。

對於使用緩存服務的客戶端來說,這一切是透明的。

內存緩存服務在切換的時候,是有一定風險的。從A集群切換到B集群的過程中,必須保證B集群提前做好「預熱」(B集群的內存中的熱點數據,應該盡量與A集群相同,否則,切換的一瞬間大量請求內容,在B集群的內存緩存中查找不到,流量直接沖擊後端的資料庫服務,很可能導致資料庫宕機)。

4. 減少資料庫「寫」

上面的機制,都實現減少資料庫的「讀」的操作,但是,寫的操作也是一個大的壓力。寫的操作,雖然無法減少,但是可以通過合並請求,來起到減輕壓力的效果。這個時候,我們就需要在內存緩存集群和資料庫集群之間,建立一個修改同步機制。

先將修改請求生效在cache中,讓外界查詢顯示正常,然後將這些sql修改放入到一個隊列中存儲起來,隊列滿或者每隔一段時間,合並為一個請求到資料庫中更新資料庫。

除了上述通過改變系統架構的方式提升寫的性能外,MySQL本身也可以通過配置參數innodb_flush_log_at_trx_commit來調整寫入磁碟的策略。如果機器成本允許,從硬體層面解決問題,可以選擇老一點的RAID(Rendant Arrays of independent Disks,磁碟列陣)或者比較新的SSD(Solid State Drives,固態硬碟)。

5. NoSQL存儲

不管資料庫的讀還是寫,當流量再進一步上漲,終會達到「人力有窮時」的場景。繼續加機器的成本比較高,並且不一定可以真正解決問題的時候。這個時候,部分核心數據,就可以考慮使用NoSQL的資料庫。NoSQL存儲,大部分都是採用key-value的方式,這里比較推薦使用上面介紹過Redis,Redis本身是一個內存cache,同時也可以當做一個存儲來使用,讓它直接將數據落地到磁碟。

這樣的話,我們就將資料庫中某些被頻繁讀寫的數據,分離出來,放在我們新搭建的Redis存儲集群中,又進一步減輕原來MySQL資料庫的壓力,同時因為Redis本身是個內存級別的Cache,讀寫的性能都會大幅度提升。

國內一線互聯網公司,架構上採用的解決方案很多是類似於上述方案,不過,使用的cache服務卻不一定是Redis,他們會有更豐富的其他選擇,甚至根據自身業務特點開發出自己的NoSQL服務。

6. 空節點查詢問題

當我們搭建完前面所說的全部服務,認為Web系統已經很強的時候。我們還是那句話,新的問題還是會來的。空節點查詢,是指那些資料庫中根本不存在的數據請求。例如,我請求查詢一個不存在人員信息,系統會從各級緩存逐級查找,最後查到到資料庫本身,然後才得出查找不到的結論,返回給前端。因為各級cache對它無效,這個請求是非常消耗系統資源的,而如果大量的空節點查詢,是可以沖擊到系統服務的。

在我曾經的工作經歷中,曾深受其害。因此,為了維護Web系統的穩定性,設計適當的空節點過濾機制,非常有必要。

我們當時採用的方式,就是設計一張簡單的記錄映射表。將存在的記錄存儲起來,放入到一台內存cache中,這樣的話,如果還有空節點查詢,則在緩存這一層就被阻擋了。

異地部署(地理分布式)

完成了上述架構建設之後,我們的系統是否就已經足夠強大了呢?答案當然是否定的哈,優化是無極限的。Web系統雖然表面上看,似乎比較強大了,但是給予用戶的體驗卻不一定是最好的。因為東北的同學,訪問深圳的一個網站服務,他還是會感到一些網路距離上的慢。這個時候,我們就需要做異地部署,讓Web系統離用戶更近。

一、 核心集中與節點分散

有玩過大型網游的同學都會知道,網游是有很多個區的,一般都是按照地域來分,例如廣東專區,北京專區。如果一個在廣東的玩家,去北京專區玩,那麼他會感覺明顯比在廣東專區卡。實際上,這些大區的名稱就已經說明了,它的伺服器所在地,所以,廣東的玩家去連接地處北京的伺服器,網路當然會比較慢。

當一個系統和服務足夠大的時候,就必須開始考慮異地部署的問題了。讓你的服務,盡可能離用戶更近。我們前面已經提到了Web的靜態資源,可以存放在CDN上,然後通過DNS/GSLB的方式,讓靜態資源的分散「全國各地」。但是,CDN只解決的靜態資源的問題,沒有解決後端龐大的系統服務還只集中在某個固定城市的問題。

這個時候,異地部署就開始了。異地部署一般遵循:核心集中,節點分散。

·核心集中:實際部署過程中,總有一部分的數據和服務存在不可部署多套,或者部署多套成本巨大。而對於這些服務和數據,就仍然維持一套,而部署地點選擇一個地域比較中心的地方,通過網路內部專線來和各個節點通訊。

·節點分散:將一些服務部署為多套,分布在各個城市節點,讓用戶請求盡可能選擇近的節點訪問服務。

例如,我們選擇在上海部署為核心節點,北京,深圳,武漢,上海為分散節點(上海自己本身也是一個分散節點)。我們的服務架構如圖:

需要補充一下的是,上圖中上海節點和核心節點是同處於一個機房的,其他分散節點各自獨立機房。
國內有很多大型網游,都是大致遵循上述架構。它們會把數據量不大的用戶核心賬號等放在核心節點,而大部分的網游數據,例如裝備、任務等數據和服務放在地區節點里。當然,核心節點和地域節點之間,也有緩存機制。

二、 節點容災和過載保護

節點容災是指,某個節點如果發生故障時,我們需要建立一個機制去保證服務仍然可用。毫無疑問,這里比較常見的容災方式,是切換到附近城市節點。假如系統的天津節點發生故障,那麼我們就將網路流量切換到附近的北京節點上。考慮到負載均衡,可能需要同時將流量切換到附近的幾個地域節點。另一方面,核心節點自身也是需要自己做好容災和備份的,核心節點一旦故障,就會影響全國服務。

過載保護,指的是一個節點已經達到最大容量,無法繼續接接受更多請求了,系統必須有一個保護的機制。一個服務已經滿負載,還繼續接受新的請求,結果很可能就是宕機,影響整個節點的服務,為了至少保障大部分用戶的正常使用,過載保護是必要的。

解決過載保護,一般2個方向:

·拒絕服務,檢測到滿負載之後,就不再接受新的連接請求。例如網游登入中的排隊。

·分流到其他節點。這種的話,系統實現更為復雜,又涉及到負載均衡的問題。

小結

Web系統會隨著訪問規模的增長,漸漸地從1台伺服器可以滿足需求,一直成長為「龐然大物」的大集群。而這個Web系統變大的過程,實際上就是我們解決問題的過程。在不同的階段,解決不同的問題,而新的問題又誕生在舊的解決方案之上。

系統的優化是沒有極限的,軟體和系統架構也一直在快速發展,新的方案解決了老的問題,同時也帶來新的挑戰。