CentOS下安裝及配置APC

APC主要有兩個作用,一是將php的編譯緩存保存在共享內存中,簡單理解就是使用了APC以後,省去了需要每次將PHP源代碼編譯爲PHP Opcode的時間,提高了性能,只要下次PHP源代碼沒有任何修改,則就不需要重新編譯了。另一方面的作用是類似Memcached的功能,APC是將數據保存到共享內存中,Memcached也是將數據保存在內存中,不過Memcached支持分佈式,而APC不支持分佈式。

1.安裝APC
從http://pecl.php.net/package/apc找到最新的apc穩定版本
[root@CentOS_Test_Server software]# wget http://pecl.php.net/get/APC-3.0.19.tgz
--17:47:42--  http://pecl.php.net/get/APC-3.0.19.tgz
Resolving pecl.php.net... 216.92.131.66
Connecting to pecl.php.net|216.92.131.66|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 115735 (113K) [application/octet-stream]
Saving to: `APC-3.0.19.tgz'

100%[=====================================================================================>] 115,735     50.1K/s   in 2.3s

17:47:48 (50.1 KB/s) - `APC-3.0.19.tgz' saved [115735/115735]

[root@CentOS_Test_Server software]# tar xzvf APC-3.0.19.tgz
[root@CentOS_Test_Server APC-3.0.19]# cd APC-3.0.19
[root@CentOS_Test_Server APC-3.0.19]# /usr/local/webserver/php/bin/phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519
./configure --enable-apc-mmap --enable-filehits --enable-apc
make
make install

**********************************************
--enable-filehits主要用於函數apc_cache_info中,說明如下
array apc_cache_info ([ string $cache_type [, bool $limited=false ]] )

cache_type
If cache_type is "user", information about the user cache will be returned.

If cache_type is "filehits", information about which files have been served from the bytecode cache for the current request will be returned. This feature must be enabled at compile time using --enable-filehits.

If an invalid or no cache_type is specified, information about the system cache (cached files) will be returned.
**********************************************

[root@CentOS_Test_Server APC-3.0.19]# make install
Installing shared extensions:     /usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/

apc.so文件已經生成
[root@CentOS_Test_Server APC-3.0.19]# ll /usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/
total 4072
-rwxr-xr-x 1 root root  416983 Sep 24 18:00 apc.so
-rwxr-xr-x 1 root root  172209 May 17 19:07 db4.so
-rwxr-xr-x 1 root root  517843 Apr 28 20:55 eaccelerator.so
-rwxr-xr-x 1 root root  748762 Jul 22 03:30 imagick.so
-rwxr-xr-x 1 root root  185627 Apr 28 20:38 memcache.so
-rwxr-xr-x 1 root root  118580 Apr 28 22:23 pdo_mysql.so
-rwxr-xr-x 1 root root 1308827 Jul  8 19:10 xapian.so
-rwxr-xr-x 1 root root  620251 Aug  5 03:41 xdebug.so

2.APC的相關配置
相關配置
---------------------------------
vi /usr/local/webserver/php/etc/php.ini,加入如下的一行
extension = "apc.so"
然後執行php -m | grep apc,發現已經出現apc模塊了,證明apc已經生效了
[root@CentOS_Test_Server APC-3.0.19]# php -m | grep apc
apc

上面只是命令行生效了,爲了讓web服務器也生效,必須要重啓php-fpm(我的環境是Nginx+fastcgi方式執行的php)
[root@CentOS_Test_Server APC-3.0.19]# /usr/local/webserver/php/sbin/php-fpm restart
Shutting down php_fpm . done
Starting php_fpm  done

vi index.php,輸入如下的內容
<?php
phpinfo()
?>
在瀏覽器執行index.php即可看到模塊apc已經生效
下面的輸出是在php.ini中沒有加任何apc的配置時的輸出值

apc
APC Support    enabled
Version    3.0.19
MMAP Support    Enabled
MMAP File Mask    /tmp/apc.wyt8Ah
Locking type    pthread mutex Locks
Revision    $Revision: 3.154.2.5 $
Build Date    Sep 25 2009 02:13:20

Directive Local Value Master Value
apc.cache_by_default    On    On
apc.coredump_unmap    Off    Off
apc.enable_cli    Off    Off
apc.enabled    On    On
apc.file_update_protection    2    2
apc.filters        
apc.gc_ttl    3600    3600
apc.include_once_override    Off    Off
apc.max_file_size    1m    1m
apc.mmap_file_mask    /tmp/apc.wyt8Ah    /tmp/apc.wyt8Ah
apc.num_files_hint    1000    1000
apc.report_autofilter    Off    Off
apc.rfc1867    Off    Off
apc.rfc1867_freq    0    0
apc.rfc1867_name    APC_UPLOAD_PROGRESS    APC_UPLOAD_PROGRESS
apc.rfc1867_prefix    upload_    upload_
apc.shm_segments    1    1
apc.shm_size    64    64
apc.slam_defense    0    0
apc.stat    Off    Off
apc.stat_ctime    Off    Off
apc.ttl    7200    7200
apc.user_entries_hint    4096    4096
apc.user_ttl    7200    7200
apc.write_lock    On    On


另外apc可以在php.ini文件中進行相關的配置,詳細的配置可以看apc的配置與測試

或者可以查看php官方的英文配置說明http://cn.php.net/manual/en/apc.configuration.php

我在這兒引用一下幾個比較關鍵的配置
apc.cache_by_default = on
;sys
; 是否默認對所有文件啓用緩衝。
; 若設爲off並與以加號開頭的apc.filters指令一起用,則文件僅在匹配過濾器時才被緩存。

apc.enable_cli = off
;sys
; 是否爲cli版本啓用apc功能,僅用於測試和調試目的纔打開此指令。

apc.enabled = on
; 是否啓用apc,如果apc被靜態編譯進php又想禁用它,這是唯一的辦法。

;apc.filters =
;sys
; 一個以逗號分隔的posix擴展正則表達式列表。
; 如果源文件名與任意一個模式匹配,則該文件不被緩存。
; 注意,用來匹配的文件名是傳遞給include/require的文件名,而不是絕對路徑。
; 如果正則表達式的第一個字符是"+"則意味着任何匹配表達式的文件會被緩存,
; 如果第一個字符是"-"則任何匹配項都不會被緩存。"-"是默認值,可以省略掉。

apc.max_file_size = 1m
;sys
; 禁止大於此尺寸的文件被緩存。

apc.shm_segments = 1
;sys
; 爲編譯器緩衝區分配的共享內存塊數量(建議值爲1)。
; 如果apc耗盡了共享內存,並且已將apc.shm_size指令設爲系統允許的最大值,
; 你可以嘗試增大此值。

apc.shm_size = 30
;sys
; 每個共享內存塊的大小(以mb爲單位,建議值爲128~256)。
; 有些系統(包括大多數bsd變種)默認的共享內存塊大小非常少。

apc.stat = on
;sys
; 是否啓用腳本更新檢查。
; 改變這個指令值要非常小心。
; 默認值 on 表示apc在每次請求腳本時都檢查腳本是否被更新,
; 如果被更新則自動重新編譯和緩存編譯後的內容。但這樣做對性能有不利影響。
; 如果設爲 off 則表示不進行檢查,從而使性能得到大幅提高。
; 但是爲了使更新的內容生效,你必須重啓web服務器。
; 這個指令對於include/require的文件同樣有效。但是需要注意的是,
; 如果你使用的是相對路徑,apc就必須在每一次include/require時都進行檢查以定位文件。
; 而使用絕對路徑則可以跳過檢查,所以鼓勵你使用絕對路徑進行include/require操作。

apc.localcache = Off
;SYS
; 是否使用非鎖定本地進程shadow-cache ,它可以減少了向緩衝區寫入時鎖之間的競爭。

apc.localcache.size = 512
;SYS
; 本地進程的shadow-cache,應當設爲一個足夠大的值,大約相當於num_files_hint的一半。

apc.write_lock = On
;SYS
; 是否啓用寫入鎖。
; 在非常繁忙的服務器上,無論是啓動服務還是修改文件,
; 都可能由於多個進程企圖同時緩存一個文件而導致競爭條件。
; 啓用該指令可以避免競爭條件的出現。

apc.num_files_hint = 1000
;SYS
; Web服務器上可能被包含或被請求的不同腳本源代碼文件的大致數量(建議值爲1024~4096)。
; 如果你不能確定,則設爲 0 ;此設定主要用於擁有數千個源文件的站點。

vi /usr/local/webserver/php/etc/php.ini,加入如下的幾行
[APC]
apc.cache_by_default = on
apc.enabled = on
apc.max_file_size = 1m
apc.shm_segments = 3
apc.shm_size = 50
apc.stat = on
apc.write_lock = On
然後重啓php-fpm進程

在php.ini中已經修改的配置在phpinfo頁面中已經生效了
apc.shm_segments 3 3
apc.shm_size 50 50

同時發現了一個問題,發現apc與eAccelerator衝突,如果在php中同時安裝了apc與eAccelerator,則apc的緩存文件的功能不會生效(或者你安裝了其它的php加速器如xCache,Zend Optimizer,如果apc的系統緩存沒有生效,則試着禁止這些看看效果)
;[eaccelerator]
;zend_extension="/usr/local/webserver/php/lib/php/extensions/no-debug-non-zts-20060613/eaccelerator.so"
;eaccelerator.shm_size="128"
;eaccelerator.cache_dir="/usr/local/webserver/eaccelerator_cache"
;eaccelerator.enable="1"
;eaccelerator.optimizer="1"
;eaccelerator.check_mtime="1"
;eaccelerator.debug="0"
;eaccelerator.filter=""
;eaccelerator.shm_max="0"
;eaccelerator.shm_ttl="300"
;eaccelerator.shm_prune_period="120"
;eaccelerator.shm_only="0"
;eaccelerator.compress="1"
;eaccelerator.compress_level="9"

3.測試APC緩存用戶數據的功能(類似於Memcached)
在apc的安裝目錄裏面有一個apc.php文件,拷貝它到Web服務器所在目錄下,這個程序可以監控apc的各種狀態數據
[root@CentOS_Test_Server www]# cd /home/software/APC-3.0.19
[root@CentOS_Test_Server APC-3.0.19]# cp apc.php /home/htdocs/www/

vi apc1.php,輸入如下的內容
<?php
define("LINE", "<br />\n");

$apc_cached = ini_get('apc.cache_by_default');
echo "aa:$apc_cached";
echo $apc_cached ? 'apc cache file' : 'apc not cache file';
echo LINE;
function microtime_float()
{
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

$time_start = microtime_float();

$key = 'name';
$value = 'caihuafeng';

//調用apc_add時對應的key已經存在,則不會覆蓋,函數的返回值是false
$ret = apc_add($key, $value);
echo "ret:$ret<br />\n";
$ret2 = apc_add($key, $value);
echo "ret2:$ret2<br />\n";

//調用apc_store時如果對應的key已經存在,則直接覆蓋
$ret3 = apc_store($key, $value);
echo "ret3:$ret3<br />\n";
for ($i = 0; $i < 100; $i++) {
    apc_store($i, $i);
}

//刪除指定的鍵對應的內容
//apc_delete($key);

$cache_type = $_REQUEST['cache_type'] ? $_REQUEST['cache_type'] : 'user';
echo "cache_type:", $cache_type, LINE;
/*
array apc_cache_info ([ string $cache_type [, bool $limited=false ]] )
Retrieves cached information and meta-data from APC's data store.

cache_type
If cache_type is "user", information about the user cache will be returned.

If cache_type is "filehits", information about which files have been served from the bytecode cache for the current request will be returned. This feature must be enabled at compile time using --enable-filehits.

If an invalid or no cache_type is specified, information about the system cache (cached files) will be returned.
*/
echo 'apc_cache_info';
var_dump(apc_cache_info($cache_type));

/*
bool apc_clear_cache ([ string $cache_type ] )
Clears the user/system cache.

cache_type
If cache_type is "user", the user cache will be cleared; otherwise, the system cache (cached files) will be cleared.
*/
//apc_clear_cache($cache_type);

echo 'name:' . apc_fetch('name') . "<br />\n";
echo "<hr />\n";

$constants = array(
    'ONE'   => 1,
    'TWO'   => 2,
    'THREE' => 3,
);
apc_define_constants('numbers', $constants);
echo 'one, two, three:', ONE, TWO, THREE, LINE;

$constants = array(
    'ONE'   => 1,
    'TWO'   => 2,
    'THREE' => 3,
);
apc_define_constants('numbers', $constants);
apc_load_constants('numbers');
echo 'one, two, three:', ONE, TWO, THREE, LINE;

/*
array apc_sma_info ([ bool $limited=false ] )
Retrieves APC's Shared Memory Allocation information.

limited
When set to FALSE (default) apc_sma_info() will return a detailed information about each segment.
*/
echo 'apc_sam_info';
var_dump(apc_sma_info(false));

echo 'Request time:', $_SERVER['REQUEST_TIME'], LINE;

$time_end = microtime_float();
$time = $time_end - $time_start;

echo "Spend time in $time seconds", LINE;
?>
輸出結果就不在此寫出來了

vi apc2.php,輸入如下的內容
<?php
define("LINE", "<br />\n");
echo 'name:' . apc_fetch('name') . "<br />\n";
?>
輸出:name:caihuafeng
我們看到apc2.php文件中只有apc_fetch,而沒有apc_add或apc_store的操作,說明數據已經保存到共享內存中去了

lsof | grep apc時有如下的輸出,不止下面這些;通過瀏覽器執行完程序你會發現,/tmp/apc*這些文件根本上是不存在的,可能是進程執行完了以後就立即刪除了,DEL應該就是表示刪除的意思
php-cgi   29349       www  DEL       REG        3,1               32854 /tmp/apc.khQ6VN
php-cgi   29350       www  mem       REG        3,1   416983     224539 /usr/local/webserver/php/lib/php/extensions/no-debug-n
on-zts-20060613/apc.so
php-cgi   29350       www  DEL       REG        3,1               32854 /tmp/apc.khQ6VN
php-cgi   29351       www  mem       REG        3,1   416983     224539 /usr/local/webserver/php/lib/php/extensions/no-debug-n
on-zts-20060613/apc.so
php-cgi   29351       www  DEL       REG        3,1               32854 /tmp/apc.khQ6VN
php-cgi   29352       www  mem       REG        3,1   416983     224539 /usr/local/webserver/php/lib/php/extensions/no-debug-n
on-zts-20060613/apc.so

[root@CentOS_Test_Server etc]# ls /tmp/
gconfd-root     keyring-lJxrr7  keyring-vcAy69  keyring-Z3N4md  mysql.sock                       VMwareDnD
keyring-9zOctR  keyring-mPfuTA  keyring-vD5JCr  keyring-zcyUaJ  scim-helper-manager-socket-root  vmware-root
keyring-ayJSKz  keyring-T5LSOn  keyring-vYf2v8  mapping-root    scim-panel-socket:0-root         xdebug
keyring-AZF1bf  keyring-T6jLxb  keyring-x3Jeeh  memcached.pid   scim-socket-frontend-root
keyring-fkCrUe  keyring-tMima3  keyring-XhEixk  mysqlslow.log   virtual-root.xJQE1h

[root@CentOS_Test_Server etc]# ls /tmp/ | grep apc.*

通過ipcs命令查看共享內存的內容也沒有什麼變化,這就有點奇怪了,這個問題以後再來研究
[root@CentOS_Test_Server etc]# ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00000000 32768      gdm       600        393216     2          dest

------ Semaphore Arrays --------
key        semid      owner      perms      nsems

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages

4.測試APC緩存系統數據的功能(也就是緩存文件的編譯結果)
a.啓動緩存系統數據的功能
[APC]
apc.cache_by_default = On
apc.enabled = On
apc.max_file_size = 1m
apc.shm_segments = 1
apc.shm_size = 64
apc.stat = Off
apc.write_lock = On
apc.mmap_file_mask = /tmp/apc.XXXXXX
apc.ttl = 7200
apc.user_ttl = 7200
apc.gc_ttl=3600
apc.num_filters_hint = 1024

apc1.php在啓用apc功能的時候的請求時間
apc enabled
Spend time in 0.0270249843597 seconds
Spend time in 0.0296368598938 seconds
Spend time in 0.0324420928955 seconds
Spend time in 0.0270788669586 seconds
Spend time in 0.0330448150635 seconds

APC編譯數據緩存統計,index.php因爲是第一次訪問,因此Hits爲0,其它的文件均不是第一次訪問,因此Hits均大於0。


b.禁止緩存系統數據的功能
將apc.cache_by_default的值設爲Off,其它的值不變

爲了保證測試結果的準確,將php-fpm及Web服務器nginx均重啓
[root@CentOS_Test_Server etc]# ../sbin/php-fpm restart
Shutting down php_fpm  done
Starting php_fpm  done
[root@CentOS_Test_Server etc]# killall nginx
[root@CentOS_Test_Server etc]# ../../nginx/sbin/nginx

此時查看apc.php的輸出結果中的值,說明此時共享內存中沒有緩存任何數據
File Cache Information
Cached Files 0 ( 0.0 Bytes)
Hits 1
Misses 0

User Cache Information
Cached Variables 0 ( 0.0 Bytes)
Hits 0
Misses 0

再次測試apc1.php的程序執行時間,當然也有可能禁止了系統緩存以後程序執行時間比啓動系統緩存以後程序執行時間還要短,當然這裏面有其它的因素影響,比如恰好是服務器最繁忙的時候,那我們來計算一下平均值,這樣可能更加準確一點,看看下面的數據我們就知道APC的系統緩存起作用了,如果php程序的業務邏輯更加複雜,估計效果更加明顯。

apc disabled
Spend time in 0.02969789505 seconds
Spend time in 0.127185106277 seconds(比啓用系統緩存時5次測試的任何一次都要長)
Spend time in 0.0369350910187 seconds(比啓用系統緩存時5次測試的任何一次都要長)
Spend time in 0.0839560031891 seconds(比啓用系統緩存時5次測試的任何一次都要長)
Spend time in 0.0326659679413 seconds(比啓用系統緩存時5次測試的任何一次都要長)

至少有一點,現在看apc.php中的統計信息也表明系統緩存生效了
File Cache Information
Cached Files 2 (379.5 KBytes)
Hits 52
Misses 2

Cached Variables 102 ( 9.6 KBytes)
Hits 16
Misses 0

5.測試系統數據緩存的其它方法
測試apc的系統數據緩存是否生效還有一個方法,那就是修改php的源代碼
比如apc1.php中開始的幾行原來爲
$apc_cached = ini_get('apc.cache_by_default');
echo $apc_cached ? 'apc cache file' : 'apc not cache file';

現改爲
$apc_cached = ini_get('apc.cache_by_default');
echo "New added:$apc_cached";
echo $apc_cached ? 'apc cache file' : 'apc not cache file';

按ctrl+f5強制刷新頁面,頁面的輸出中完全沒有new added的字樣,這就可以說明apc的系統緩存已經生效了(也就是執行的是編譯結果的緩存)
apc not cache file
ret:
ret2:
ret3:1
cache_type:user
apc_cache_info
......
......

有的人在這裏可能會有疑問了,要是我的php程序修改了,而apc的系統緩存又在生效中,那我要看最新的執行結果怎麼辦?
有如下的幾種方法:
a.用apc_compile_file編譯修改過的文件,我們可以參考一下facebook的代碼
$path = '/path/to/source';
$exclude = $path.'/www/admin/';
$expr = '.*\\.php';
$files = split(' ', exec("find -L $path -regex '$expr'
| grep -v '$exclude' | xargs"));
// prime php files
foreach($files as $file) {
apc_compile_file($file);
}

b.重啓web服務器後所有的用戶數據緩存及系統數據緩存都將失效,這樣我們通過瀏覽器訪問php程序時當然是最新的php程序返回的結果。

c.將apc.stat設爲on,表示apc在每次請求腳本時都檢查腳本是否被更新,如果被更新則自動重新編譯和緩存編譯後的內容。但這樣做對性能有不利影響。

d.如果apc.ttl的值不爲0(比如3600,表示1小時),則在web服務器不重啓的情況下,則只能等待緩存失效了,如果要求比較及時,就只能採用方法a。提示php.ini中與ttl有關的配置只是對系統緩存有效,而用戶緩存是通過函數apc_store或apc_add中的第三個參數ttl來控制的。

apc.ttl = 0
;sys
; 緩存條目在緩衝區中允許逗留的秒數。0 表示永不超時。建議值爲7200~36000。
; 設爲 0 意味着緩衝區有可能被舊的緩存條目填滿,從而導致無法緩存新條目。

apc.user_ttl = 0
;sys
; 類似於apc.ttl,只是針對每個用戶而言,建議值爲7200~36000。
; 設爲 0 意味着緩衝區有可能被舊的緩存條目填滿,從而導致無法緩存新條目。

apc.gc_ttl = 3600
;sys
; 緩存條目在垃圾回收表中能夠存在的秒數。
; 此值提供了一個安全措施,即使一個服務器進程在執行緩存的源文件時崩潰,
; 而且該源文件已經被修改,爲舊版本分配的內存也不會被回收,直到達到此ttl值爲止。
; 設爲零將禁用此特性。

個人認爲比較好的方法是a(此時將apc.stat設爲off),如果有哪些php文件修改,就重新編譯它,如果有多臺Web服務器,則通過rsync之類的軟件自動同步即可,如果要求比較及時的話,則只能手動通過scp之類的命令同步了,因爲rsync多少有些延遲。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章