国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > PHP > 正文

PHP Opcode緩存加速組件:APC模塊安裝使用

2024-05-04 21:50:13
字體:
來源:轉載
供稿:網友

什么是opcode

也許你曾經嘗試過用C/C++編寫動態內容,雖然開發過程極其繁瑣,但為了獲得性能提升,這樣做或許是值得的,它們可以將動態內容編譯成二進制可執行文件,也就是目標代碼,由操作系統進程直接裝載運行。如今已經很少有人使用C/C++編寫動態內容了,絕大多數的Web開發人員享受著當下的幸福時光,很多優秀的腳本語言可供選擇,比如PHP,Ruby,Python,它們都屬于解釋型語言,所以用它們編寫的動態內容都需要依賴響應的解釋器程序來運行。

解釋器程序也是一個二進制可執行文件,比如/bin/ruby,它同樣可以直接在進程中運行,在運行過程中,解釋器程序需要對輸入的腳本代碼進行分析,領會它們的旨意,然后執行它們。比如下面我們調用PHP的解釋器,讓它執行一段簡單的腳本代碼:

~ zfs$ php -r 'print 1+1;'

很好,它很快的輸出了正確的結果,也許你覺的1+1的計算太小兒科,的確,在人類的大腦中計算1+1是很簡單,幾乎不用思考,但解釋器的工作方式可不是你想象的那樣,1+1和100+1000對它來說幾乎沒有什么區別,因為解釋器核心引擎根本看不懂這些腳本代碼,無法直接執行,所以需要進行一系列的代碼分析工作,當解釋器完成對腳本代碼的分析后,便將它們生成可以直接運行的中間代碼,也稱為操作碼(Operate Code,opcode)。

從程序代碼到中間代碼的這個過程,我們稱為解釋(parse),它由解釋器來完成。如此相似的是,編譯型語言中的編譯器(如C語言的編譯器gcc),也要將程序代碼生成中間代碼,這個過程我們稱為編譯(compile)。編譯器和解釋器的一個本質不同在于,解釋器在生成中間代碼后,便直接執行它,所以運行時的控制權在解釋器;而編譯器則將中間代碼進一步優化,生成可以直接運行的目標程序,但不執行它,用戶可以在隨后的任意時間執行它,這時的控制權在目標程序,和編譯器沒有任何關系。

事實上,就解釋和編譯本身而言,它們的原理是相似的,都包括詞法分析,語法分析,語義分析等,所以,有些時候將解釋型語言中生成opcode的過程也稱為"編譯",需要你根據上下文來理解。

那么,opcode究竟是什么樣的呢? 它又是如何解釋生成的呢? 我們以PHP為例,來尋找這些答案。

PHP解釋器的核心引擎為Zend Engine,可以很容易的查看它的版本:

  1. ~ zfs$ php -v 
  2. PHP 5.5.14 (cli) (built: Sep  9 2014 19:09:25)  
  3. Copyright (c) 1997-2014 The PHP Group 
  4. Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies 

還記得前面我們曾經用PHP計算1+1的腳本代碼嗎? 我們來看看這段代碼的opcode。在此之前,需要安裝PHP的Parsekit擴展,它是一個用C編寫的二進制擴展,由PECL來維護。有了Parsekit擴展后,我們就可以通過它提供的運行時API來查看任何PHP文件或者代碼段的opcode。我們直接在命令行中調用parsekit_compile_string(),如下所示:

/usr/local/php/bin/php -r "var_dump(parsekit_compile_string('print 1+1;'));"

這樣一來,我們便獲得了這段代碼的opcode,返回的是數組形式,結果如下所示:

  1. array(20) { 
  2.   ["type"]=> 
  3.   int(4) 
  4.   ["type_name"]=> 
  5.   string(14) "ZEND_EVAL_CODE" 
  6.   ["fn_flags"]=> 
  7.   int(0) 
  8.   ["num_args"]=> 
  9.   int(0) 
  10.   ["required_num_args"]=> 
  11.   int(0) 
  12.   ["pass_rest_by_reference"]=> 
  13.   bool(false) 
  14.   ["uses_this"]=> 
  15.   bool(false) 
  16.   ["line_start"]=> 
  17.   int(0) 
  18.   ["line_end"]=> 
  19.   int(0) 
  20.   ["return_reference"]=> 
  21.   bool(false) 
  22.   ["refcount"]=> 
  23.   int(1) 
  24.   ["last"]=> 
  25.   int(5) 
  26.   ["size"]=> 
  27.   int(5) 
  28.   ["T"]=> 
  29.   int(2) 
  30.   ["last_brk_cont"]=> 
  31.   int(0) 
  32.   ["current_brk_cont"]=> 
  33.   int(4294967295) 
  34.   ["backpatch_count"]=> 
  35.   int(0) 
  36.   ["done_pass_two"]=> 
  37.   bool(true) 
  38.   ["filename"]=> 
  39.   string(17) "Parsekit Compiler" 
  40.   ["opcodes"]=> 
  41.   array(5) { 
  42.     [0]=> 
  43.     array(8) { 
  44.       ["address"]=> 
  45.       int(33847532) 
  46.       ["opcode"]=> 
  47.       int(1) 
  48.       ["opcode_name"]=> 
  49.       string(8) "ZEND_ADD" 
  50.       ["flags"]=> 
  51.       int(197378) 
  52.       ["result"]=> 
  53.       array(3) { 
  54.         ["type"]=> 
  55.         int(2) 
  56.         ["type_name"]=> 
  57.         string(10) "IS_TMP_VAR" 
  58.         ["var"]=> 
  59.         int(0) 
  60.       } 
  61.       ["op1"]=> 
  62.       array(3) { 
  63.         ["type"]=> 
  64.         int(1) 
  65.         ["type_name"]=> 
  66.         string(8) "IS_CONST" 
  67.         ["constant"]=> 
  68.         &int(1) 
  69.       } 
  70.       ["op2"]=> 
  71.       array(3) { 
  72.         ["type"]=> 
  73.         int(1) 
  74.         ["type_name"]=> 
  75.         string(8) "IS_CONST" 
  76.         ["constant"]=> 
  77.         &int(1) 
  78.       } 
  79.       ["lineno"]=> 
  80.       int(1) 
  81.     } 
  82.     [1]=> 
  83.     array(7) { 
  84.       ["address"]=> 
  85.       int(33847652) 
  86.       ["opcode"]=> 
  87.       int(41) 
  88.       ["opcode_name"]=> 
  89.       string(10) "ZEND_PRINT" 
  90.       ["flags"]=> 
  91.       int(770) 
  92.       ["result"]=> 
  93.       array(3) { 
  94.         ["type"]=> 
  95.         int(2) 
  96.         ["type_name"]=> 
  97.         string(10) "IS_TMP_VAR" 
  98.         ["var"]=> 
  99.         int(1) 
  100.       } 
  101.       ["op1"]=> 
  102.       array(3) { 
  103.         ["type"]=> 
  104.         int(2) 
  105.         ["type_name"]=> 
  106.         string(10) "IS_TMP_VAR" 
  107.         ["var"]=> 
  108.         int(0) 
  109.       } 
  110.       ["lineno"]=> 
  111.       int(1) 
  112.     } 
  113.     [2]=> 
  114.     array(7) { 
  115.       ["address"]=> 
  116.       int(33847772) 
  117.       ["opcode"]=> 
  118.       int(70) 
  119.       ["opcode_name"]=> 
  120.       string(9) "ZEND_FREE" 
  121.       ["flags"]=> 
  122.       int(271104) 
  123.       ["op1"]=> 
  124.       array(4) { 
  125.         ["type"]=> 
  126.         int(2) 
  127.         ["type_name"]=> 
  128.         string(10) "IS_TMP_VAR" 
  129.         ["var"]=> 
  130.         int(1) 
  131.         ["EA.type"]=> 
  132.         int(0) 
  133.       } 
  134.       ["op2"]=> 
  135.       array(3) { 
  136.         ["type"]=> 
  137.         int(8) 
  138.         ["type_name"]=> 
  139.         string(9) "IS_UNUSED" 
  140.         ["opline_num"]=> 
  141.         string(1) "0" 
  142.       } 
  143.       ["lineno"]=> 
  144.       int(1) 
  145.     } 
  146.     [3]=> 
  147.     array(7) { 
  148.       ["address"]=> 
  149.       int(33847892) 
  150.       ["opcode"]=> 
  151.       int(62) 
  152.       ["opcode_name"]=> 
  153.       string(11) "ZEND_RETURN" 
  154.       ["flags"]=> 
  155.       int(16777984) 
  156.       ["op1"]=> 
  157.       array(3) { 
  158.         ["type"]=> 
  159.         int(1) 
  160.         ["type_name"]=> 
  161.         string(8) "IS_CONST" 
  162.         ["constant"]=> 
  163.         &NULL 
  164.       } 
  165.       ["extended_value"]=> 
  166.       int(0) 
  167.       ["lineno"]=> 
  168.       int(1) 
  169.     } 
  170.     [4]=> 
  171.     array(5) { 
  172.       ["address"]=> 
  173.       int(33848012) 
  174.       ["opcode"]=> 
  175.       int(149) 
  176.       ["opcode_name"]=> 
  177.       string(21) "ZEND_HANDLE_EXCEPTION" 
  178.       ["flags"]=> 
  179.       int(0) 
  180.       ["lineno"]=> 
  181.       int(1) 
  182.     } 
  183.   } 

parsekit擴展的安裝請參見這篇文章

系統緩存

它是指APC把PHP文件源碼的編譯結果緩存起來,然后在每次調用時先對比時間標記。如果未過期,則使用緩存的中間代碼運行。默認緩存3600s(一小時)。但是這樣仍會浪費大量CPU時間。因此可以在php.ini中設置system緩存為永不過期(apc.ttl=0)。不過如果這樣設置,改運php代碼后需要重啟WEB服務器。目前使用較多的是指此類緩存。

用戶數據緩存

緩存由用戶在編寫PHP代碼時用apc_store和apc_fetch函數操作讀取、寫入的。如果數據量不大的話,可以一試。如果數據量大,使用類似memcache此類的更加專著的內存緩存方案會更好。

APC模塊的安裝

最簡單的方法是直接使用pecl,在命令行下輸入:/usr/local/php/bin/pecl install apc

然后按照提示一步步完成即可,示例如下:

  1. [root@iZ23bm1tc0pZ ~]# /usr/local/php/bin/pecl install apc 
  2. downloading APC-3.1.13.tgz ... 
  3. Starting to download APC-3.1.13.tgz (171,591 bytes) 
  4. .....................................done: 171,591 bytes 
  5. 55 source files, building 
  6. running: phpize 
  7. Configuring for
  8. PHP Api Version:         20100412 
  9. Zend Module Api No:      20100525 
  10. Zend Extension Api No:   220100525 
  11. Enable internal debugging in APC [no] : no 
  12. Enable per request file info about files used from the APC cache [no] : no 
  13. Enable spin locks (EXPERIMENTAL) [no] : no 
  14. Enable memory protection (EXPERIMENTAL) [no] : no 
  15. Enable pthread mutexes (default) [no] : no 
  16. Enable pthread read/write locks (EXPERIMENTAL) [yes] : yes 

然后重啟服務器即可:

lnmp nginx restart

先看一下沒有使用apc情況下的壓測結果:

  1. [root@iZ23bm1tc0pZ ~]# ab -n1000 -c100 http://Vevb.com/index.php 
  2. This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 
  3. Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://m.survivalescaperooms.com/ 
  4. Licensed to The Apache Software Foundation, http://www.apache.org/ 
  5. Benchmarking zfsphp.cn (be patient) 
  6. Completed 100 requests 
  7. Completed 200 requests 
  8. Completed 300 requests 
  9. Completed 400 requests 
  10. Completed 500 requests 
  11. Completed 600 requests 
  12. Completed 700 requests 
  13. Completed 800 requests 
  14. Completed 900 requests 
  15. Completed 1000 requests 
  16. Finished 1000 requests 
  17. Server Software:        nginx 
  18. Server Hostname:        zfsphp.cn 
  19. Server Port:            80 
  20. Document Path:          /index.php 
  21. Document Length:        14341 bytes 
  22. Concurrency Level:      100 
  23. Time taken for tests:   15.517 seconds 
  24. Complete requests:      1000 
  25. Failed requests:        0 
  26. Total transferred:      14544000 bytes 
  27. HTML transferred:       14341000 bytes 
  28. Requests per second:    64.45 [#/sec] (mean) 
  29. Time per request:       1551.671 [ms] (mean) 
  30. Time per request:       15.517 [ms] (mean, across all concurrent requests) 
  31. Transfer rate:          915.34 [Kbytes/sec] received 
  32. Connection Times (ms) 
  33.               min  mean[+/-sd] median   max 
  34. Connect:        0    2   4.8      0      17 
  35. Processing:    46 1481 277.0   1560    1638 
  36. Waiting:       42 1481 277.1   1560    1638 
  37. Total:         58 1482 272.8   1560    1638 
  38. Percentage of the requests served within a certain time (ms) 
  39.   50%   1560 
  40.   66%   1576 
  41.   75%   1582 
  42.   80%   1587 
  43.   90%   1602 
  44.   95%   1612 
  45.   98%   1622 
  46.   99%   1629 
  47.  100%   1638 (longest request) 

可見最大吞吐率只有64.45reqs/s,然后我們開啟apc,測試結果如下:

  1. [root@iZ23bm1tc0pZ ~]# ab -n1000 -c100 http://Vevb.com/index.php 
  2. This is ApacheBench, Version 2.3 <$Revision: 1706008 $> 
  3. Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://m.survivalescaperooms.com/ 
  4. Licensed to The Apache Software Foundation, http://www.apache.org/ 
  5. Benchmarking zfsphp.cn (be patient) 
  6. Completed 100 requests 
  7. Completed 200 requests 
  8. Completed 300 requests 
  9. Completed 400 requests 
  10. Completed 500 requests 
  11. Completed 600 requests 
  12. Completed 700 requests 
  13. Completed 800 requests 
  14. Completed 900 requests 
  15. Completed 1000 requests 
  16. Finished 1000 requests 
  17. Server Software:        nginx 
  18. Server Hostname:        Vevb.com 
  19. Server Port:            80 
  20. Document Path:          /index.php 
  21. Document Length:        14341 bytes 
  22. Concurrency Level:      100 
  23. Time taken for tests:   7.122 seconds 
  24. Complete requests:      1000 
  25. Failed requests:        0 
  26. Total transferred:      14544000 bytes 
  27. HTML transferred:       14341000 bytes 
  28. Requests per second:    140.41 [#/sec] (mean) 
  29. Time per request:       712.189 [ms] (mean) 
  30. Time per request:       7.122 [ms] (mean, across all concurrent requests) 
  31. Transfer rate:          1994.29 [Kbytes/sec] received 
  32. Connection Times (ms) 
  33.               min  mean[+/-sd] median   max 
  34. Connect:        0    1   2.4      0      10 
  35. Processing:    23  677 125.3    705     775 
  36. Waiting:       22  677 125.4    705     775 
  37. Total:         30  678 123.1    705     775 
  38. Percentage of the requests served within a certain time (ms) 
  39.   50%    705 
  40.   66%    719 
  41.   75%    726 
  42.   80%    730 
  43.   90%    742 
  44.   95%    750 
  45.   98%    760 
  46.   99%    765 
  47.  100%    775 (longest request) 
 可見吞吐率提高了一倍多,達到140.41reqs/s,然后,我們在開啟動態內容緩存(樓主的博客用的是Smarty緩存),測試結果如下:
 [root@iZ23bm1tc0pZ ~]# ab -n1000 -c100 http://Vevb.com/index.php 
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 岗巴县| 青冈县| 塔河县| 漾濞| 黄石市| 虎林市| 八宿县| 崇左市| 合水县| 邢台县| 香港| 永州市| 柏乡县| 紫金县| 文昌市| 维西| 南昌县| 丹寨县| 平山县| 双牌县| 卓尼县| 松江区| 奉节县| 来安县| 西华县| 公安县| 宜城市| 余姚市| 张家口市| 桓台县| 南宁市| 南丰县| 周宁县| 梁河县| 云龙县| 东辽县| 衡南县| 天全县| 尉氏县| 阿拉善左旗| 武定县|