本博客並不是所有原創,實際上是一個知識的概括和彙總,裏面我引用了不少網上、書上的內容。也給出了相關的連接。javascript
本文涉及的知識點比較多,你們能夠根據關鍵字去搜索相關的內容和購買相應的書籍進行系統的學習。不對的地方你們予以批評指正。php
有人給我留言說,億級 PV 就別寫文章了,隨便用幾個開源軟件就能搞定了,只要不犯什麼大錯。我不覺得然,若是你利用了相同的思想,使用了更高性能的基礎服務,也許就能支持更多的流量併發,節約更多的服務器,優化的思路纔是重點。css
本內容的視頻分享見個人直播html
咱們先看一張簡單的 web 架構圖前端
從上到下從用戶的瀏覽器到最後的數據庫,那麼咱們說先前端的優化。java
雅虎軍規:http://www.cnblogs.com/paul-3...
node
把多個JS、CSS在可能的狀況下寫進一個文件,頁面裏直接寫入圖片也是很差的作法,應該寫進CSS裏,小圖拼合後利用 background 來定位。mysql
expires
,cache-control
,last-modified
,etag
http://blog.csdn.net/eroswang...
防止緩存,好比資源更新了,原來的作法是?v=xxxx 如今前端的打包工做能夠能會生成 /v1.2.0/xxx.jslinux
接地氣利用 cdn 存儲前端資源nginx
分爲下面三個部分來
fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 256k;
gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.0; gzip_comp_level 2; gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/json; gzip_vary on; gzip_proxied expired no-cache no-store private auth; gzip_disable "MSIE [1-6]\.";
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; }
http://mailman.nginx.org/pipe...
time wait bucket table overflow
tcp_tw_recycle 快速回收可能致使丟包的問題 https://mengkang.net/1144.html
除了上面的網絡協議配置也是在系統基礎以外,爲了配合nginx本身裏面的設定須要作以下修改
更多詳細的優化配置說明:http://os.51cto.com/art/20140...
注意有不少函數和擴展被廢棄,好比mysql相關的,有風險,作好測試再切換。
php 5.5 以後好像就內置了吧,須要在php.ini裏添加以下配置
opcache.revalidate_freq=60 opcache.validate_timestamps=1 opcache.max_accelerated_files=1000 opcache.memory_consumption=512 opcache.interned_strings_buffer=16 opcache.fast_shutdown=1
這個選項用於設置緩存的過時時間(單位是秒),當這個時間達到後,opcache會檢查你的代碼是否改變,若是改變了PHP會從新編譯它,生成新的opcode,而且更新緩存。
當這個選項被啓用(設置爲1),PHP會在opcache.revalidate_freq設置的時間到達後檢測文件的時間戳(timestamp)。
這個選項用於控制內存中最多能夠緩存多少個PHP文件。
你能夠經過調用opcachegetstatus()來獲取opcache使用的內存的總量
字符串opcache的複用,單位爲MB
開啓快速中止續發事件,依賴於Zend引擎的內存管理模塊
Hugepage 的做用:間接提升虛擬地址和內存地址轉換過程當中查表的TLB緩存命中率
opcache.huge_code_pages=1
鳥哥博客詳細介紹:http://www.laruence.com/2015/...
以thinkphp爲例,它會把框架基礎組件(必須用到的組件)合併壓縮到一個文件中,不只減小了文件目錄查找,文件打開的系統調用。
經過strace
php-fpm子進程,能夠清楚系統調用的過程,在我上面例子中有打開一個文件有12次系統調用(只是舉例,我這裏相對路徑設置的緣由致使多了兩次文件查找)。若是有10個文件,那就是120次,優化的效果可能不是那麼明顯,可是這是一種思路。
順便說下 set_include_path
能不用就不要用,上面的demo的截圖裏面找不到目錄就是證實。
模板把它們自定義的語法,最後轉換成php語法,這樣方便解析。而不是每次都解析一遍。
個人截圖一直上傳不成功,正好社區有這樣的博客,推薦下 https://segmentfault.com/a/11...
好比原來有一個model,叫問答,如今須要開發一個有獎問答,須要支持話題打賞,裏面多了不少功能。這個時候應該利用面向對象的繼承的特性。而不是作下面的開發
<?php class AskModel { public function detail($id){ $info = 從數據庫查詢到該問題的信息; // 邏輯1 // 邏輯2 } }
<?php class AskModel { public function detail($id){ $info = 從數據庫查詢到該問題的信息; // 邏輯1 if($info['type'] == 2){ //... }else{ } // 邏輯2 if($info['type'] == 2){ //... }else{ } } }
這樣邏輯多了,子類型多了,邏輯判斷就很是重複,程序運行起來低效多是一方面,更多的是不可維護性。
業務和架構不分家,架構是創建在對業務的理解之上的。再放下上次直播的PPT (sf故障沒法傳圖,等會補吧)
舉例:
這些都是異步的思想。能分步走就分步走,能不能請求的就不請求。
專題頁面,好比秒殺頁面,爲了應對更大的流量、併發。並且更新起來也比較方便。
好比剛剛上面說的專題頁面,還有必要走整個框架的一套流程嗎?進來引用一大堆的文件,初始化一大堆的東西?是否是特別低效呢?因此須要業務解耦,專題頁面若是真要框架(能夠首次訪問以後生成靜態頁面)也應該是足夠輕量級的。不能與傳統業務混爲一談。
說業務優化,真的不得不提架構方面的東西,業務解耦以後,就有了分佈式和soa,由於這在上次分享中已經都說過了,就很少說了。
只說下 soa 自定義 socket 傳輸協議。
最重要的就是在自定義頭裏面強調body_len
,注意設置爲緊湊型,才能保證跨平臺性 具體說明:https://mengkang.net/586.html
數據索引相關的文章網上不少了,不足的地方你們補充。
如今大多數狀況都會使用innodb類型了。具體緣由是 mysql 專家給的意見。
我本身對 mysql 的優化不瞭解,每個細分領域都是一片汪洋,每一個人的時間精力是有限的,因此你們也不用什麼都非要深刻去研究,每每是一些計算機基礎更爲重要。
參考這份ppt https://static.mengkang.net/u...
舉例:
以前項目裏有些索引是article_id
+ tag_id
聯合作的主鍵,那麼這種狀況下,就是業務了屬性了。主鍵也不是順序遞增,每插入新的數據都有可能致使很大的索引變更(瞭解下數據庫b+索引的原理)
大多數狀況下,索引掃描要比全表掃描更快,性能更好。但也不是絕對的,好比須要查找的數據佔了整個數據表的很大比例,反而使用索引更慢了。
聯合索引「最左前綴」,查詢優化器還會幫你調整條件表達式的順序,以匹配組合索引的要求。
CREATE TABLE `test` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `a` int(10) unsigned NOT NULL, `b` int(10) unsigned NOT NULL, `c` int(10) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `index_abc` (`a`,`b`,`c`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
能使用到索引
explain select * from test where a=1; explain select * from test where a=1 and b=2; explain select * from test where a=1 and b=2 and c=3; explain select * from test where a=1 and b in (2,3) and c=3; explain select * from test where a=1 and b=2 order by c desc;
不能使用索引
explain select * from test where a=1 and b in (2,3) order by c desc; explain select * from test where b=2;
索引更詳細講解 https://mengkang.net/1302.html
explain 搜到一篇不錯的: http://blog.csdn.net/woshiqjs...
很重要的參數type
,key
,extra
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
值 | 說明 |
---|---|
const | 經過索引直接找到一個匹配行,通常主鍵索引的時候 |
ref | 沒有主鍵索引或者惟一索引的條件索引,查詢結果多行,在聯合查詢中很常見 |
index | 利用到了索引,有可能有其它排序,where 或者 group by 等 |
all | 全表掃描,沒有使用到索引 |
若是有Using filesort
或者Using temporary
的話,就必需要優化了
my.ini 配置裏增長
long_query_time=2 log-slow-queries=/data/var/mysql_slow.log
redis 豐富的數據類型,很是適合配合mysql 作一些關係型的查詢。好比一個很是複雜的查詢列表能夠將其插入zset 作排序列表,而後具體的信息,經過zset裏面的紙去mysql 裏面去查詢。
static
變量存儲,好比朋友圈信息流,在一次性獲取20條信息的時候,有可能,點讚的人裏面20條裏面有30我的是重複的,他們點贊你的a圖片也點讚了你的b圖片,因此這時,若是能使用static數組來存放這些用戶的基本信息就高效了些。
請求結束了,下拉更新朋友圈,裏面又出現了上面的一樣的好友,還得從新請求一次。因此本地常駐內存的緩存就更高效了。
在A服務器上已經查詢過了,在下拉更新的時候被分配到B服務器上了,難道一樣的數據再查一次再存到B服務器的本地緩存裏面嗎,弄一個分佈式緩存吧,這樣防止了重複查詢。可是多了網絡請求這一步。
不少時候是三者共存的。
案例分析
用戶積分更新
爲了取數據方便把多個數據源混合緩存了,這種狀況,相比你們可能都見過,這是災難性的設計。
{ id:x, title:x, gift:{ id:x, name:x, img:x, } }
若是須要更新禮物的圖片,那麼全部用到過這個禮物的話題的緩存都要更新。
因爲比較基礎基礎好的老司機就能夠忽略了,新人同窗能夠看下 https://mengkang.net/356.html
圖片id=>uid
的關係數據,用了21g,後來改成水平分割,圖片id 1000 取模,而後將分片的數據存在一個hashse 裏面,這樣最後的內容減小了5g,四分之一基本上。每一段使用一個Hash結構存儲,因爲Hash結構會在單個Hash元素在不足必定數量時進行壓縮存儲,因此能夠大量節約內存。這一點在String結構裏是不存在的。而這個必定數量是由配置文件中的hash-zipmap-max-entries參數來控制的。
下面的內容,只能是讓你們有一個大概的認識,瞭解一個優化的方向,具體的內容須要系統學習不少不少的知識。
多進程有利於 CPU 計算和 I/O 操做的重疊利用。一個進程消耗的絕大部分時間都是在磁盤I/O和網絡I/O中。
若是是單進程時cpu大量的時間都在等待I/O,因此咱們須要使用多進程。
爲了讓全部的進程輪流使用系統資源,進程調度器在必要的時候掛起正在運行的進程,同時恢復之前掛起的某個進程。這個就是咱們常說的「上下文切換」。
關於上下文我以前寫一個簡單筆記 https://mengkang.net/729.html
無限制增長進程數,則會增多 cpu 在各個進程間切換的次數。
若是咱們但願服務器支持較大的併發數,那麼久要儘可能減小上下文切換的次數,好比在nginx服務上nginx的子進程數不要超過cpu的核數。
咱們能夠在壓測的時候經過vmstat
,nmon
來監控系統上下文切換的次數。
# top top - 09:40:40 up 565 days, 5:47, 2 users, load average: 0.03, 0.03, 0.00 Tasks: 121 total, 2 running, 119 sleeping, 0 stopped, 0 zombie Cpu(s): 8.6%us, 0.3%sy, 0.0%ni, 90.7%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
通常狀況下IOwait表明I/O操做的時間佔(I/O操做的時間 + I/O和CPU時間)的比例。
可是也時候也不許,好比nginx來做爲web服務器,當咱們開啓不少nginx子進程,IOwait會很高,當再減小進程數到cpu核數附近時,IOwait會減小,監控網絡流量會發現也增長。
只要是提供socket
服務,就能夠利用多路複用 I/O 模型。
須要補充的知識 https://mengkang.net/726.html
strace 很是方便統計系統調用
# strace -c -p 23374 Process 23374 attached - interrupt to quit ^CProcess 23374 detached % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 30.68 0.000166 0 648 poll 12.01 0.000065 0 228 munmap 11.65 0.000063 0 228 mmap 10.54 0.000057 0 660 recvfrom 10.35 0.000056 0 708 fstat 7.76 0.000042 0 252 open 6.10 0.000033 1 36 write 5.73 0.000031 0 72 24 access 5.18 0.000028 0 72 read 0.00 0.000000 0 276 close 0.00 0.000000 0 13 13 stat 0.00 0.000000 0 269 240 lstat 0.00 0.000000 0 12 rt_sigaction 0.00 0.000000 0 12 rt_sigprocmask 0.00 0.000000 0 12 pwrite 0.00 0.000000 0 48 setitimer 0.00 0.000000 0 12 socket 0.00 0.000000 0 12 connect 0.00 0.000000 0 12 accept 0.00 0.000000 0 168 sendto 0.00 0.000000 0 12 shutdown 0.00 0.000000 0 48 fcntl 0.00 0.000000 0 12 flock 0.00 0.000000 0 156 getcwd 0.00 0.000000 0 24 chdir 0.00 0.000000 0 24 times 0.00 0.000000 0 12 getuid ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000541 4038 277 total
經過strace
查看「系統調用時間」和「調用次數」來定位問題 https://huoding.com/2013/10/0...
要想理解web服務器優化的原理,最好的辦法是瞭解它的前因後果,實踐就是最好的方式,我分爲如下幾個步驟:
上面是個人學習筆記,圖片資源丟失了,你們能夠根據相關關鍵詞去搜搜相關的文章和書籍,更推薦你們去看書。