Opcode是啥以及如何使用好Opcache

轉載  https://www.zybuluo.com/phper/note/1016714php

 

啥是Opcode?

咱們在平常的PHP開發過程當中,應該常常會聽見Opcache這個詞,那麼啥是Opcode呢?nginx

Opcache 的前生是 Optimizer+ ,它是PHP的官方公司 Zend 開發的一款閉源但能夠無償使用的 PHP 優化加速組件。 Optimizer+ 將PHP代碼預編譯生成的腳本文件 Opcode 緩存在共享內存中供之後反覆使用,從而避免了從磁盤讀取代碼再次編譯的時間消耗。同時,它還應用了一些代碼優化模式,使得代碼執行更快。從而加速PHP的執行。git

Optimizer+ 於 2013年3月中旬更名爲 Opcache。而且在 PHP License 下開源: https://github.com/zendtech/ZendOptimizerPlusgithub

Opcache的生命週期

瞭解了啥是Opcache以及Opcache的做用。如今看一下Opcache的運行圖。web

正常的php代碼的執行過程以下:redis

request請求(nginx,apache,cli等)-->Zend引擎讀取.php文件-->掃描其詞典和表達式 -->解析文件-->建立要執行的計算機代碼(稱爲Opcode)-->最後執行Opcode--> response 返回apache

每一次請求PHP腳本都會執行一遍以上步驟,若是PHP源代碼沒有變化,那麼Opcode也不會變化,顯然沒有必要每次都重行生成Opcode,結合在Web中無所不在的緩存機制,咱們能夠把Opcode緩存下來,之後直接訪問緩存的Opcode豈不是更快,啓用Opcode緩存以後的流程圖以下所示:json

request請求(nginx,apache,cli等)-->Zend引擎讀取.php文件-->讀取Opcode-->執行Opcode--> response 返回數組

Opcache的安裝

實際上,在php5.5之後,Opcache 是默認安裝好了的,已經不須要咱們再手動去安裝了,可是默認是沒有開啓的,若是咱們須要使用,須要手動去開啓:瀏覽器

  1. zend_extension=opcache.so
  2. [opcache]
  3. opcache.enable=1 #容許在web環境使用,默認是開啓的。
  4. opcache.enable_cli=1 #運行在cli環境使用

重啓 fpm 和 nginx

  1. kill -USR2 cat `/usr/local/php/var/run/php-fpm.pid`
  2. nginx -s reload

這樣就可使用opcache了。

推薦的 php.ini 中 Opcache的配置

如下是官網推薦的php.ini中的配置。能夠在生產環境得到更高的性能:

  1. opcache.enable=1
  2. opcache.memory_consumption=128
  3. opcache.interned_strings_buffer=8
  4. opcache.max_accelerated_files=4000
  5. opcache.revalidate_freq=60
  6. opcache.fast_shutdown=1 ;(在PHP 7.2.0中被移除,會自動開啓)
  7. opcache.enable_cli=1

opcache的配置說明。

上面是官方推薦的一些配置,其實它還有一大長條的配置,咱們選擇幾個重要的,會被使用到的,來講下他們的具體含義:

  1. opcache.enable=1 (default "1")
  2. ;OPcache打開/關閉開關。當設置爲Off或者0時,會關閉Opcache, 代碼沒有被優化和緩存。
  3. opcache.enable_cli=1 (default "0")
  4. ;CLI環境下,PHP啓用OPcache。這主要是爲了測試和調試。從 PHP 7.1.2 開始,默認啓用。
  5. opcache.memory_consumption=128 (default "64")
  6. ;OPcache共享內存存儲大小。用於存儲預編譯的opcode(以MB爲單位)。
  7. opcache.interned_strings_buffer=8 (default "4")
  8. ;這是一個頗有用的選項,可是彷佛徹底沒有文檔說明。PHP使用了一種叫作字符串駐留(string interning)的技術來改善性能。例如,若是你在代碼中使用了1000次字符串「foobar」,在PHP內部只會在第一使用這個字符串的時候分配一個不可變的內存區域來存儲這個字符串,其餘的999次使用都會直接指向這個內存區域。這個選項則會把這個特性提高一個層次——默認狀況下這個不可變的內存區域只會存在於單個php-fpm的進程中,若是設置了這個選項,那麼它將會在全部的php-fpm進程中共享。在比較大的應用中,這能夠很是有效地節約內存,提升應用的性能。
  9. 這個選項的值是以兆字節(megabytes)做爲單位,若是把它設置爲16,則表示16MB,默認是4MB,這是一個比較低的值。
  10. opcache.max_accelerated_files (default "2000")
  11. ;這個選項用於控制內存中最多能夠緩存多少個PHP文件。這個選項必須得設置得足夠大,大於你的項目中的全部PHP文件的總和。
  12. 設置值取值範圍最小值是 200,最大值在 PHP 5.5.6 以前是 100000PHP 5.5.6 及以後是 1000000。也就是說在2001000000之間。
  13. 你能夠運行「find . -type f -print | grep php | wc -l」這個命令來快速計算你的代碼庫中的PHP文件數。
  14. opcache.max_wasted_percentage (default "5")
  15. ;計劃從新啓動以前,「浪費」內存的最大百分比。
  16. opcache.use_cwd (default "1")
  17. ;若是啓用,OPcache將在哈希表的腳本鍵以後附加改腳本的工做目錄, 以免同名腳本衝突的問題。禁用此選項能夠提升性能,可是可能會致使應用崩潰
  18. opcache.validate_timestamps (default "1")
  19. ;若是啓用(設置爲1),OPcache會在opcache.revalidate_freq設置的秒數去檢測文件的時間戳(timestamp)檢查腳本是否更新。
  20. 若是這個選項被禁用(設置爲0),opcache.revalidate_freq會被忽略,PHP文件永遠不會被檢查。這意味着若是你修改了你的代碼,而後你把它更新到服務器上,再在瀏覽器上請求更新的代碼對應的功能,你會看不到更新的效果,你必須使用 `opcache_reset()` 或者 `opcache_invalidate()` 函數來手動重置 OPcache。或者重重你的web服務器或者php-fpm 來使文件系統更改生效。
  21. 我強烈建議你在生產環境中設置爲0why?由於當你在更新服務器代碼的時候,若是代碼較多,更新操做是有些延遲的,在這個延遲的過程當中必然出現老代碼和新代碼混合的狀況,這個時候對用戶請求的處理必然存在不肯定性。最後,等全部的代碼更新完畢後,再平滑重啓PHPweb服務器。
  22. opcache.revalidate_freq (default "2")
  23. ;這個選項用於設置緩存的過時時間(單位是秒),當這個時間達到後,opcache會檢查你的代碼是否改變,若是改變了PHP會從新編譯它,生成新的opcode,而且更新緩存。值爲「0」表示每次請求都會檢查你的PHP代碼是否更新(這意味着會增長不少次stat系統調用,譯註:stat系統調用是讀取文件的狀態,這裏主要是獲取最近修改時間,這個系統調用會發生磁盤I/O,因此必然會消耗一些CPU時間,固然系統調用自己也會消耗一些CPU時間)。能夠在開發環境中把它設置爲0,生產環境下不用管。
  24. 若是 `opcache.validate_timestamps` 配置指令設置爲禁用(設置爲0),那麼此設置項將會被忽略。
  25. opcache.revalidate_path (default "0")
  26. ;在include_path優化中啓用或禁用文件搜索
  27. 若是被禁用,而且找到了使用的緩存文件相同的include_path,該文件不被再次搜索。所以,若是一個文件與include_path中的其餘地方相同的名稱出現將不會被發現。若是此優化對此有效,請啓用此指令你的應用程序,這個指令的默認值是禁用的,這意味着該優化是活躍的。
  28. opcache.fast_shutdown(默認「0」)
  29. ;若是啓用,則會使用快速中止續發事件。 所謂快速中止續發事件是指依賴 Zend 引擎的內存管理模塊 一次釋放所有請求變量的內存,而不是依次釋放每個已分配的內存塊。
  30. 該指令已在PHP 7.2.0中被刪除。快速關機序列的一個變種已經被集成到PHP中,而且若是可能的話將被自動使用。

驗證opcache是否生效

當咱們開啓Opcache後,而後也配置好了相關的配置,那麼如何驗證是否已經成功了呢?

寫了簡單的小例子,先把檢查時間設置爲10秒,也就是說10秒內,不會去檢查文件是否有更新,直接用緩存中的opcode:

  1. zend_extension=opcache.so
  2. [opcache]
  3. opcache.enable=1
  4. opcache.memory_consumption=128
  5. opcache.interned_strings_buffer=8
  6. opcache.max_accelerated_files=4000
  7. opcache.revalidate_freq=10
  8. opcache.fast_shutdown=1
  9. opcache.enable_cli=1

而後一個簡單的例子:

  1. //php71.php
  2. <?php
  3. $a = '12';
  4. echo $a;

啓動一個php自帶的web服務:

  1. php -S 127.0.0.1:8088

而後再瀏覽器裏打開:

  1. http://127.0.0.1:8088/php71.php

結果是:12

而後,手動改下:

  1. //php71.php
  2. <?php
  3. $a = '34';
  4. echo $a;

若是你手速快,迅速的去刷新瀏覽器,10次內,你會發現,結果仍是12。不是 34。

說明,Opcache 已經生效了。

再來改一下,把opcache.validate_timestamps=0設置爲0,則表示,永遠不去檢查文件是否更新。

而後,你刷新頁面,數字永遠是12。除非你ctrl+c 關閉web服務,再啓動web服務,纔會生效變成 34。

因此,在通常的公司代碼上線發佈後,都會平滑重啓php或者web服務器

opcache相關的幾個函數

雖然opcahce是php內置的行爲,只要你開啓了,就會生效,不須要像傳統的redis或者memcache須要手動寫代碼才能使用。可是php也提供了若干個opcache相關的函數。

  • opcache_compile_file — 無需運行,便可編譯並緩存 PHP 腳本
  • opcache_get_configuration — 獲取php.ini中的配置信息
  • opcache_get_status — 獲取緩存的狀態信息
  • opcache_invalidate — 廢除腳本緩存
  • opcache_is_script_cached — 一個php文件是否被緩存
  • opcache_reset — 重置狀況全部的緩存內容

咱們來一一看下。

opcache_compile_file

使用此函數,能夠無需運行php腳本,便可編譯並緩存 PHP 腳本。該函數可用於在 Web 服務器重啓以後初始化緩存,俗稱緩存預熱。

注意:文件必須填寫完整全路徑

咱們仍是舉例子說明:

php71.php

  1. $a = '5678';
  2. echo $a;
  3. //是否被緩存
  4. var_dump(opcache_invalidate('/Users/tencent/php/php71.php'));
  5. //查看緩存狀態
  6. var_dump(opcache_get_status());

每次重啓web服務器,第一次刷新瀏覽器這個頁面,查看打印:

  1. 5678
  2. bool(false)
  3. .....
  4. ["hits"]=> int(0)
  5. .....

能夠,看出,第一次進來,是沒有被緩存的,第二次刷新,就被緩存住了。

  1. 5678
  2. bool(true)
  3. .....
  4. ["hits"]=> int(1)
  5. .....

opcache_get_configuration

查看php.ini中的配置項,和php.ini裏的設置同樣,並列出全部的配置,以數組array的形式呈現,用 json_encode 打印出來:

  1. {
  2. "directives": {
  3. "opcache.enable": true,
  4. "opcache.enable_cli": true,
  5. "opcache.use_cwd": true,
  6. "opcache.validate_timestamps": true,
  7. "opcache.validate_permission": false,
  8. "opcache.validate_root": false,
  9. "opcache.inherited_hack": true,
  10. "opcache.dups_fix": false,
  11. "opcache.revalidate_path": false,
  12. "opcache.log_verbosity_level": 1,
  13. "opcache.memory_consumption": 134217728,
  14. "opcache.interned_strings_buffer": 8,
  15. "opcache.max_accelerated_files": 4000,
  16. "opcache.max_wasted_percentage": 0.05,
  17. "opcache.consistency_checks": 0,
  18. "opcache.force_restart_timeout": 180,
  19. "opcache.revalidate_freq": 10,
  20. "opcache.preferred_memory_model": "",
  21. "opcache.blacklist_filename": "",
  22. "opcache.max_file_size": 0,
  23. "opcache.error_log": "",
  24. "opcache.protect_memory": false,
  25. "opcache.save_comments": true,
  26. "opcache.enable_file_override": false,
  27. "opcache.optimization_level": 2147467263,
  28. "opcache.lockfile_path": "/tmp",
  29. "opcache.file_cache": "",
  30. "opcache.file_cache_only": false,
  31. "opcache.file_cache_consistency_checks": true
  32. },
  33. "version": {
  34. "version": "7.2.0",
  35. "opcache_product_name": "Zend OPcache"
  36. },
  37. "blacklist": []
  38. }

opcache_get_status

獲取opcache的緩存狀態以及緩存了哪些文件等信息,能夠說是用的作多的一個腳本了。

打印出來:

  1. {
  2. "opcache_enabled": true,
  3. "cache_full": false,
  4. "restart_pending": false,
  5. "restart_in_progress": false,
  6. "memory_usage": {
  7. "used_memory": 18278720,
  8. "free_memory": 115919680,
  9. "wasted_memory": 19328,
  10. "current_wasted_percentage": 0.014400482177734375
  11. },
  12. "interned_strings_usage": {
  13. "buffer_size": 8388608,
  14. "used_memory": 428056,
  15. "free_memory": 7960552,
  16. "number_of_strings": 9963
  17. },
  18. "opcache_statistics": {
  19. "num_cached_scripts": 1,
  20. "num_cached_keys": 1,
  21. "max_cached_keys": 7963,
  22. "hits": 2,
  23. "start_time": 1516850948,
  24. "last_restart_time": 0,
  25. "oom_restarts": 0,
  26. "hash_restarts": 0,
  27. "manual_restarts": 0,
  28. "misses": 4,
  29. "blacklist_misses": 0,
  30. "blacklist_miss_ratio": 0,
  31. "opcache_hit_rate": 33.33333333333333
  32. },
  33. "scripts": {
  34. "/Users/tencent/php/php71.php": {
  35. "full_path": "/Users/tencent/php/php71.php",
  36. "hits": 0,
  37. "memory_consumption": 6432,
  38. "last_used": "Thu Jan 25 11:32:03 2018",
  39. "last_used_timestamp": 1516851123,
  40. "timestamp": 1516851119
  41. }
  42. }
  43. }

opcache_invalidate

廢除(刪除)一個文件的緩存。能夠針對一個文件的清楚緩存。注意:文件必須填寫完整全路徑

  1. //清楚 php71.php緩存
  2. var_dump(opcache_invalidate('/Users/tencent/php/php71.php')); // bool(true)

opcache_is_script_cached

查看一個文件是否被緩存。注意:文件必須填寫完整全路徑

  1. var_dump(opcache_is_script_cached('/Users/tencent/ams-swoole-framework/php71.php'));
  2. //bool(true)
  3. var_dump(opcache_is_script_cached('/Users/tencent/ams-swoole-framework/php73.php'));
  4. // bool(false)

opcache_reset

重置全部的opcache緩存。注意:這個函數很危險,他會清空當前項目的全部opcache緩存:

  1. var_dump(opcache_reset()); //bool(true)

opcache圖形化管理工具

上面的函數命令用起來可能沒那麼方便,基於上面的這些函數,有2個GUI的圖形化管理工具,還不錯。

1. 擁有漂亮的圖形化界面的項目

https://github.com/PeeHaa/OpCacheGUI

下載後,將config.sample.php 複製一份成爲:config.php。並修改帳戶密碼和時區:

  1. return [
  2. 'username' => 'root',
  3. 'password' => '$2y$10$XIlZ702pFKgRozYUuvaI4uZcumv19bysFo6PnviZIKlN8IvEeXVXu', //root
  4. 'whitelist' => [
  5. 'localhost',
  6. '127.0.0.1',
  7. ],
  8. 'language' => 'en',
  9. 'timezone' => 'Asia/Shanghai',
  10. 'error_reporting' => E_ALL,
  11. 'display_errors' => 'Off',
  12. 'log_errors' => 'On',
  13. 'uri_scheme' => Router::URL_REWRITE
  14. ];

而後在瀏覽器訪問,輸入帳戶密碼:root root:

http://127.0.0.1:8089/index.php

2. 單個PHP文件, 方便部署的項目

https://github.com/rlerdorf/opcache-status

下載後,而後在瀏覽器訪問:

http://127.0.0.1:8089/opcache.php

opcache性能測試

那麼,開啓opcache性能是否有很大的性能提高呢?

相關文章
相關標籤/搜索