apache修改最大連接并用ab網(wǎng)站壓力測(cè)試
apache 2.2,使用默認(rèn)配置,默認(rèn)最大連接數(shù)是150
1.首先在httpd.conf中加載httpd-mpm.conf配置(去掉前面的注釋?zhuān)?br /># Server-pool management (MPM
specific)
Include conf/extra/httpd-mpm.conf
2.可見(jiàn)的MPM配置在/usr/local/apache/conf/extra/httpd-mpm.conf,但里面根據(jù)httpd的工作模式分了很多塊,哪一部才是當(dāng)前httpd的工作模式呢?可通過(guò)執(zhí)行
apachectl -l 來(lái)查看:
[root@zh888 extra]# /usr/local/apache/bin/apachectl
-l//因?yàn)椴捎渺o態(tài)編譯
Compiled in
modules:
core.c
mod_authn_file.c
mod_authn_default.c
mod_authz_host.c
mod_authz_groupfile.c
mod_authz_user.c
mod_authz_default.c
mod_auth_basic.c
mod_cache.c
mod_disk_cache.c
mod_mem_cache.c
mod_include.c
mod_filter.c
mod_deflate.c
mod_log_config.c
mod_env.c
mod_expires.c
mod_headers.c
mod_setenvif.c
mod_version.c
mod_proxy.c
mod_proxy_connect.c
mod_proxy_ftp.c
mod_proxy_http.c
mod_proxy_scgi.c
mod_proxy_ajp.c
mod_proxy_balancer.c
prefork.c//才用prefork所以在httpd-mpm.conf中找到mpm_prefork_module
http_core.c
mod_mime.c
mod_status.c
mod_autoindex.c
mod_asis.c
mod_cgi.c
mod_negotiation.c
mod_dir.c
mod_actions.c
mod_userdir.c
mod_alias.c
mod_rewrite.c
mod_so.c
所以修改連接數(shù)就在/usr/local/apache/conf/extra/httpd-mpm.conf這個(gè)文件了,打開(kāi)它就找到prefork模式的默認(rèn)配置是:
StartServers
5
MinSpareServers 5
MaxSpareServers 10
MaxClients
150
MaxRequestsPerChild 0
prefork
控制進(jìn)程在最初建立“StartServers”個(gè)子進(jìn)程后,為了滿(mǎn)足MinSpareServers設(shè)置的需要?jiǎng)?chuàng)建一個(gè)進(jìn)程,等待一秒鐘,繼續(xù)創(chuàng)建兩個(gè),再等待一秒鐘,繼續(xù)創(chuàng)建四個(gè)……如此按指數(shù)級(jí)增加創(chuàng)建的進(jìn)程數(shù),最多達(dá)到每秒32個(gè),直到滿(mǎn)足MinSpareServers設(shè)置的值為止。
這種模式可以不必在請(qǐng)求到來(lái)時(shí)再產(chǎn)生新的進(jìn)程,從而減小了系統(tǒng)開(kāi)銷(xiāo)以增加性能。MaxSpareServers設(shè)置了最大的空閑進(jìn)程數(shù),如果空閑進(jìn)程數(shù)大于這個(gè)值,Apache會(huì)自動(dòng)kill掉一些多余進(jìn)程。這個(gè)值不要設(shè)得過(guò)大,但如果設(shè)的值比MinSpareServers小,Apache會(huì)自動(dòng)把其調(diào)整為
MinSpareServers+1。如果站點(diǎn)負(fù)載較大,可考慮同時(shí)加大MinSpareServers和MaxSpareServers。
MaxRequestsPerChild設(shè)置的是每個(gè)子進(jìn)程可處理的請(qǐng)求數(shù)。每個(gè)子進(jìn)程在處理了“MaxRequestsPerChild”個(gè)請(qǐng)求后將自動(dòng)銷(xiāo)毀。0意味著無(wú)限,即子進(jìn)程永不銷(xiāo)毀。
雖然缺省設(shè)為0可以使每個(gè)子進(jìn)程處理更多的請(qǐng)求,但如果設(shè)成非零值也有兩點(diǎn)重要的好處:
1、可防止意外的內(nèi)存泄漏。
2、在服務(wù)器負(fù)載下降的時(shí)侯會(huì)自動(dòng)減少子進(jìn)程數(shù)。因此,可根據(jù)服務(wù)器的負(fù)載來(lái)調(diào)整這個(gè)值。MaxClients是這些指令中最為重要的一個(gè),設(shè)定的是
Apache可以同時(shí)處理的請(qǐng)求,是對(duì)Apache性能影響最大的參數(shù)。其缺省值150是遠(yuǎn)遠(yuǎn)不夠的,如果請(qǐng)求總數(shù)已達(dá)到這個(gè)值(可通過(guò)ps -ef|grep
httpd|wc
-l來(lái)確認(rèn)),那么后面的請(qǐng)求就要排隊(duì),直到某個(gè)已處理請(qǐng)求完畢。這就是系統(tǒng)資源還剩下很多而HTTP訪問(wèn)卻很慢的主要原因。雖然理論上這個(gè)值越大,可以處理的請(qǐng)求就越多,但Apache默認(rèn)的限制不能大于256。ServerLimit指令無(wú)須重編譯Apache就可以加大MaxClients。
注意,雖然通過(guò)設(shè)置ServerLimit,我們可以把MaxClients加得很大,但是往往會(huì)適得其反,系統(tǒng)耗光所有內(nèi)存。以我手頭的一臺(tái)服務(wù)器為例:內(nèi)存2G,每個(gè)apache進(jìn)程消耗大約0.5%(可通過(guò)ps
aux來(lái)確認(rèn))的內(nèi)存,也就是10M,這樣,理論上這臺(tái)服務(wù)器最多跑200個(gè)apache進(jìn)程就會(huì)耗光系統(tǒng)所有內(nèi)存,所以,設(shè)置MaxClients要慎重。
3.要加到多少?
連接數(shù)理論上當(dāng)然是支持越大越好,但要在服務(wù)器的能力范圍內(nèi),這跟服務(wù)器的CPU、內(nèi)存、帶寬等都有關(guān)系。
查看當(dāng)前的連接數(shù)可以用:
ps aux | grep httpd | wc -l
計(jì)算httpd占用內(nèi)存的平均數(shù):
ps
aux|grep -v grep|awk '/httpd/{sum+=$6;n++};'
由于基本都是靜態(tài)頁(yè)面,CPU消耗很低,每進(jìn)程占用內(nèi)存也不算多,大約200K。
假如服務(wù)器內(nèi)存有2G,除去常規(guī)啟動(dòng)的服務(wù)大約需要500M(保守估計(jì)),還剩1.5G可用,那么理論上可以支持1.5*1024*1024*1024/
= 8053.
約8K個(gè)進(jìn)程,支持2W人同時(shí)訪問(wèn)應(yīng)該是沒(méi)有問(wèn)題的(能保證其中8K的人訪問(wèn)很快,其他的可能需要等待1、2秒才能連上,而一旦連上就會(huì)很流暢)
控制最大連接數(shù)的MaxClients ,因此可以嘗試配置為:
StartServers 5
MinSpareServers
5
MaxSpareServers 10
ServerLimit 5500
MaxClients
5000
MaxRequestsPerChild 100
注意,MaxClients默認(rèn)最大為250,若要超過(guò)這個(gè)值就要顯式設(shè)置ServerLimit,且ServerLimit要放在MaxClients之前,值要不小于MaxClients,不然重啟httpd時(shí)會(huì)有提示。
重啟httpd后,通過(guò)反復(fù)執(zhí)行pgrep httpd|wc -l
來(lái)觀察連接數(shù),可以看到連接數(shù)在達(dá)到MaxClients的設(shè)值后不再增加,但此時(shí)訪問(wèn)網(wǎng)站也很流暢,那就不用貪心再設(shè)置更高的值了,不然以后如果網(wǎng)站訪問(wèn)突增不小心就會(huì)耗光服務(wù)器內(nèi)存,可根據(jù)以后訪問(wèn)壓力趨勢(shì)及內(nèi)存的占用變化再逐漸調(diào)整,直到找到一個(gè)最優(yōu)的設(shè)置值。
(MaxRequestsPerChild不能設(shè)置為0,可能會(huì)因內(nèi)存泄露導(dǎo)致服務(wù)器崩潰)
更佳最大值計(jì)算的公式:
apache_max_process_with_good_perfermance < (total_hardware_memory /
apache_memory_per_process ) * 2
apache_max_process =
apache_max_process_with_good_perfermance * 1.5
4.用/usr/local/apache/bin/ab來(lái)測(cè)試壓力不過(guò)還有一個(gè)工具叫webbench也可以測(cè)試。
[root@zh888 bin]# /usr/local/apache/bin/ab -n 100 -c
100http://192.168.100.1:8000/index.php//參數(shù)很多一般我們用 -c 和 -n
參數(shù)就可以了這個(gè)表示同時(shí)處理100個(gè)請(qǐng)求并運(yùn)行100次index.php文件.
This is ApacheBench Version 2.3
Copyright 1996 Adam Twiss Zeus Technology
Ltd
Licensed to The Apache Software Foundation
Benchmarking 192.168.100.1 (be patient).....done
Server Software: Apache/2.2.19//平臺(tái)apache 版本2.0.54
Server Hostname: 192.168.100.1//服務(wù)器主機(jī)名
Server Port: 8000//端口
Document Path: /index.php//測(cè)試的頁(yè)面文檔
Document Length: bytes//文檔大小
Concurrency Level: 100//并發(fā)數(shù)
Time taken for tests: 4.482 seconds//整個(gè)測(cè)試持續(xù)的時(shí)間
Complete requests: 100//完成的請(qǐng)求數(shù)量
Failed requests: 0//失敗的請(qǐng)求數(shù)量
Write errors: 0
Total transferred: bytes//整個(gè)場(chǎng)景中的網(wǎng)絡(luò)傳輸量
HTML transferred: bytes
Requests per second: 22.31 [#/sec]
(mean)//大家最關(guān)心的指標(biāo)之一,相當(dāng)于 LR 中的 每秒事務(wù)數(shù) ,后面括號(hào)中的 mean 表示這是一個(gè)平均值
Time per request: 4481.929 [ms] (mean)//大家最關(guān)心的指標(biāo)之二,相當(dāng)于 LR 中的 平均事務(wù)響應(yīng)時(shí)間 ,后面括號(hào)中的
mean 表示這是一個(gè)平均值
Time per request: 44.819 [ms] (mean across all concurrent
requests)//每個(gè)請(qǐng)求實(shí)際運(yùn)行時(shí)間的平均值
Transfer rate: 793.68 [Kbytes/sec]
received//平均每秒網(wǎng)絡(luò)上的流量,可以幫助排除是否存在網(wǎng)絡(luò)流量過(guò)大導(dǎo)致響應(yīng)時(shí)間延長(zhǎng)的問(wèn)題
Connection Times (ms)//網(wǎng)絡(luò)上消耗的時(shí)間的分解。
min mean[+/-sd] median max
Connect: 0 73 24.5 79 96
Processing: 252
2542 1291.7 2590 4386
Waiting: 252 2541 1292.5 2590 4384
Total: 253 2615
1311.0 2671 4482
Percentage of the requests served within a certain time
(ms)//整個(gè)場(chǎng)景中所有請(qǐng)求的響應(yīng)情況。在場(chǎng)景中每個(gè)請(qǐng)求都有一個(gè)響應(yīng)時(shí)間,其中50%的用戶(hù)響應(yīng)時(shí)間小于1093 毫秒,60% 的用戶(hù)響應(yīng)時(shí)間小于1247
毫秒,最大的響應(yīng)時(shí)間小于7785
毫秒
由于對(duì)于并發(fā)請(qǐng)求,cpu實(shí)際上并不是同時(shí)處理的,而是按照每個(gè)請(qǐng)求獲得的時(shí)間片逐個(gè)輪轉(zhuǎn)處理的,所以基本上第一個(gè)Time per
request時(shí)間約等于第二個(gè)Time per request時(shí)間乘以并發(fā)請(qǐng)求數(shù)
50% 2671
66% 3351
75% 3923
80% 4095
90% 4358
95%
4441
98% 4472
99% 4482
100% 4482 (longest request)
4.是在使用Apache2.2的ab進(jìn)行測(cè)試時(shí)遇到的問(wèn)題:
使用ab測(cè)試的時(shí)候當(dāng)-c并發(fā)數(shù)超過(guò)1024就會(huì)出錯(cuò):
windows下提示:apr_pollset_create
failed: Invalid argument (22)
linux下提示:socket: Too
many open files (24)
解決辦法:
linux下:ulimit -n
(設(shè)置系統(tǒng)允許同時(shí)打開(kāi)的文件數(shù),系統(tǒng)默認(rèn)是1024),可以用ulimit -a查看open files項(xiàng),# lsof |wc -l
可以查看系統(tǒng)所有進(jìn)程的文件打開(kāi)數(shù)。
ulimit:顯示(或設(shè)置)用戶(hù)可以使用的資源限制
ulimit -a 顯示用戶(hù)可以使用的資源限制
ulimit unlimited
不限制用戶(hù)可以使用的資源,但本設(shè)置對(duì)可打開(kāi)的最大文件數(shù)(max open files)
和可同時(shí)運(yùn)行的最大進(jìn)程數(shù)(max user
processes)無(wú)效
ulimit -n 設(shè)置用戶(hù)可以同時(shí)打開(kāi)的最大文件數(shù)(max open files)
例如:ulimit -n 8192
如果本參數(shù)設(shè)置過(guò)小,對(duì)于并發(fā)訪問(wèn)量大的網(wǎng)站,可能會(huì)出現(xiàn)too many open files的錯(cuò)誤
ulimit -u
設(shè)置用戶(hù)可以同時(shí)運(yùn)行的最大進(jìn)程數(shù)(max user processes)
例如:ulimit -u 1024
5最后補(bǔ)充一下apache的知識(shí):
簡(jiǎn)介
Apache
HTTP服務(wù)器被設(shè)計(jì)為一個(gè)強(qiáng)大的、靈活的能夠在多種平臺(tái)以及不同環(huán)境下工作的服務(wù)器。不同的平臺(tái)和不同的環(huán)境經(jīng)常產(chǎn)生不同的需求,或是為了達(dá)到同樣的最佳效果而采用不同的方法。Apache憑借它的模塊化設(shè)計(jì)很好的適應(yīng)了大量不同的環(huán)境。這一設(shè)計(jì)使得網(wǎng)站管理員能夠在編譯時(shí)和運(yùn)行時(shí)憑借載入不同的模塊來(lái)決定服務(wù)器的不同附加功能。
Apache2.0將這種模塊化的設(shè)計(jì)延伸到了web服務(wù)器的基礎(chǔ)功能上。這個(gè)版本帶有多路處理模塊(MPM)的選擇以處理網(wǎng)絡(luò)端口綁定、接受請(qǐng)求并指派鐘進(jìn)程來(lái)處理這些請(qǐng)求。
將模塊化設(shè)計(jì)延伸到這一層次主要有以下兩大好處:
*
Apache可以更簡(jiǎn)潔、更有效地支持各種操作系統(tǒng)。尤其是在mpm_winnt中使用本地網(wǎng)絡(luò)特性代替Apache1.3中使用的POSIX模擬層后,Windows版本的Apache現(xiàn)在具有更好的性能。這個(gè)優(yōu)勢(shì)借助特定的MPM同樣延伸到了其他各種操作系統(tǒng)。
*
服務(wù)器可以為某些特定的站點(diǎn)進(jìn)行定制。比如,需要更好伸縮性的站點(diǎn)可以選擇象worker或event這樣線程化的MPM,而需要更好的穩(wěn)定性和兼容性以適應(yīng)一些舊的軟件的站點(diǎn)可以用prefork
。
從用戶(hù)角度來(lái)看,MPM更像其他的Apache模塊。主要的不同在于:不論何時(shí),必須有且僅有一個(gè)MPM被載入到服務(wù)器中。現(xiàn)有的MPM列表可以在模塊索引中找到。
選擇一個(gè)MPM
MPM必須在編譯配置時(shí)進(jìn)行選擇,并靜態(tài)編譯到服務(wù)器中。如果編譯器能夠確定線程功能被啟用,它將會(huì)負(fù)責(zé)優(yōu)化大量功能。因?yàn)橐恍㎝PM在Unix上使用了線程,而另外一些沒(méi)有使用,所以如果在編譯配置時(shí)選擇MPM并靜態(tài)編譯進(jìn)Apache,Apache將會(huì)有更好的表現(xiàn)。
你可以在使用configure腳本時(shí)用 --with-mpm=NAME 選項(xiàng)指定MPM,NAME就是你想使用的MPM的名稱(chēng)。
一旦服務(wù)器編譯完成,就可以用 ./httpd -l
命令來(lái)查看使用了哪個(gè)MPM。這個(gè)命令將列出所有已經(jīng)被編譯到服務(wù)器中的模塊,包括MPM。
我們主要闡述prefork和worker這兩種和性能關(guān)系最大的產(chǎn)品級(jí)MPM。
Apache MPM prefork
一個(gè)非線程型的、預(yù)派生的MPM
概述
這個(gè)多路處理模塊(MPM)實(shí)現(xiàn)了一個(gè)非線程型的、預(yù)派生的web服務(wù)器,它的工作方式類(lèi)似于Apache
1.3。它適合于沒(méi)有線程安全庫(kù),需要避免線程兼容性問(wèn)題的系統(tǒng)。它是要求將每個(gè)請(qǐng)求相互獨(dú)立的情況下最好的MPM,這樣若一個(gè)請(qǐng)求出現(xiàn)問(wèn)題就不會(huì)影響到其他請(qǐng)求。
這個(gè)MPM具有很強(qiáng)的自我調(diào)節(jié)能力,只需要很少的配置指令調(diào)整。最重要的是將MaxClients設(shè)置為一個(gè)足夠大的數(shù)值以處理潛在的請(qǐng)求高峰,同時(shí)又不能太大,以致需要使用的內(nèi)存超出物理內(nèi)存的大小。
工作方式
一個(gè)單獨(dú)的控制進(jìn)程(父進(jìn)程)負(fù)責(zé)產(chǎn)生子進(jìn)程,這些子進(jìn)程用于監(jiān)聽(tīng)請(qǐng)求并作出應(yīng)答。Apache總是試圖保持一些備用的(spare)或者是空閑的子進(jìn)程用于迎接即將到來(lái)的請(qǐng)求。這樣客戶(hù)端就不需要在得到服務(wù)前等候子進(jìn)程的產(chǎn)生。
StartServers MinSpareServers MaxSpareServers
MaxClients指令用于調(diào)節(jié)父進(jìn)程如何產(chǎn)生子進(jìn)程。通常情況下Apache具有很強(qiáng)的自我調(diào)節(jié)能力,所以一般的網(wǎng)站不需要調(diào)整這些指令的默認(rèn)值。可能需要處理最大超過(guò)256個(gè)并發(fā)請(qǐng)求的服務(wù)器可能需要增加MaxClients的值。內(nèi)存比較小的機(jī)器則需要減少M(fèi)axClients的值以保證服務(wù)器不會(huì)崩潰。更多關(guān)于調(diào)整進(jìn)程產(chǎn)生的問(wèn)題請(qǐng)參見(jiàn)性能方面的提示。
在Unix系統(tǒng)中,父進(jìn)程通常以root身份運(yùn)行以便邦定80端口,而Apache產(chǎn)生的子進(jìn)程通常以一個(gè)低特權(quán)的用戶(hù)運(yùn)行。User和Group指令用于設(shè)置子進(jìn)程的低特權(quán)用戶(hù)。運(yùn)行子進(jìn)程的用戶(hù)必須要對(duì)它所服務(wù)的內(nèi)容有讀取的權(quán)限,但是對(duì)服務(wù)內(nèi)容之外的其他資源必須擁有盡可能少的權(quán)限。
MaxRequestsPerChild指令控制服務(wù)器殺死舊進(jìn)程產(chǎn)生新進(jìn)程的頻率。
Apache MPM worker
支持混合的多線程多進(jìn)程的多路處理模塊
概述
此多路處理模塊(MPM)使網(wǎng)絡(luò)服務(wù)器支持混合的多線程多進(jìn)程。由于使用線程來(lái)處理請(qǐng)求,所以可以處理海量請(qǐng)求,而系統(tǒng)資源的開(kāi)銷(xiāo)小于基于進(jìn)程的MPM。但是,它也使用了多進(jìn)程,每個(gè)進(jìn)程又有多個(gè)線程,以獲得基于進(jìn)程的MPM的穩(wěn)定性。
控制這個(gè)MPM的最重要的指令是,控制每個(gè)子進(jìn)程允許建立的線程數(shù)的ThreadsPerChild指令,和控制允許建立的總線程數(shù)的MaxClients指令。
工作方式
每個(gè)進(jìn)程可以擁有的線程數(shù)量是固定的。服務(wù)器會(huì)根據(jù)負(fù)載情況增加或減少進(jìn)程數(shù)量。一個(gè)單獨(dú)的控制進(jìn)程(父進(jìn)程)負(fù)責(zé)子進(jìn)程的建立。每個(gè)子進(jìn)程可以建立ThreadsPerChild數(shù)量的服務(wù)線程和一個(gè)監(jiān)聽(tīng)線程,該監(jiān)聽(tīng)線程監(jiān)聽(tīng)接入請(qǐng)求并將其傳遞給服務(wù)線程處理和應(yīng)答。
Apache總是試圖維持一個(gè)備用(spare)或是空閑的服務(wù)線程池。這樣,客戶(hù)端無(wú)須等待新線程或新進(jìn)程的建立即可得到處理。初始化時(shí)建立的進(jìn)程數(shù)量由StartServers指令決定。隨后父進(jìn)程檢測(cè)所有子進(jìn)程中空閑線程的總數(shù),并新建或結(jié)束子進(jìn)程使空閑線程的總數(shù)維持在MinSpareThreads和MaxSpareThreads所指定的范圍內(nèi)。由于這個(gè)過(guò)程是自動(dòng)調(diào)整的,幾乎沒(méi)有必要修改這些指令的缺省值。可以并行處理的客戶(hù)端的最大數(shù)量取決于MaxClients指令。活動(dòng)子進(jìn)程的最大數(shù)量取決于MaxClients除以ThreadsPerChild的值。
有兩個(gè)指令設(shè)置了活動(dòng)子進(jìn)程數(shù)量和每個(gè)子進(jìn)程中線程數(shù)量的硬限制。要想改變這個(gè)硬限制必須完全停止服務(wù)器然后再啟動(dòng)服務(wù)器(直接重啟是不行的),ServerLimit是活動(dòng)子進(jìn)程數(shù)量的硬限制,它必須大于或等于MaxClients除以ThreadsPerChild的值。ThreadLimit是所有服務(wù)線程總數(shù)的硬限制,它必須大于或等于ThreadsPerChild指令。這兩個(gè)指令必須出現(xiàn)在其他workerMPM指令的前面。
在設(shè)置的活動(dòng)子進(jìn)程數(shù)量之外,還可能有額外的子進(jìn)程處于"正在中止"的狀態(tài)但是其中至少有一個(gè)服務(wù)線程仍然在處理客戶(hù)端請(qǐng)求,直到到達(dá)MaxClients以致結(jié)束進(jìn)程,雖然實(shí)際數(shù)量會(huì)很小。這個(gè)行為能夠通過(guò)以下禁止特別的子進(jìn)程中止的方法來(lái)避免:
* 將MaxRequestsPerChild設(shè)為"0"
* 將MaxSpareThreads和MaxClients設(shè)為相同的值
一個(gè)典型的針對(duì)workerMPM的配置如下:
ServerLimit 16
StartServers 2
MaxClients
150
MinSpareThreads 25
MaxSpareThreads 75
ThreadsPerChild
25
在Unix中,為了能夠綁定80端口,父進(jìn)程一般都是以root身份啟動(dòng),隨后,Apache以較低權(quán)限的用戶(hù)建立子進(jìn)程和線程。User和Group指令用于設(shè)置Apache子進(jìn)程的權(quán)限。雖然子進(jìn)程必須對(duì)其提供的內(nèi)容擁有讀權(quán)限,但應(yīng)該盡可能給予它較少的特權(quán)。另外,除非使用了suexec
,否則,這些指令設(shè)置的權(quán)限將被CGI腳本所繼承。
MaxRequestsPerChild指令用于控制服務(wù)器建立新進(jìn)程和結(jié)束舊進(jìn)程的頻率。
常用指令:
StartServers
指令
StartServers指令設(shè)置了服務(wù)器啟動(dòng)時(shí)建立的子進(jìn)程數(shù)量。因?yàn)樽舆M(jìn)程數(shù)量動(dòng)態(tài)的取決于負(fù)載的輕重,所有一般沒(méi)有必要調(diào)整這個(gè)參數(shù)。
MinSpareServers
指令
MinSpareServers指令設(shè)置空閑子進(jìn)程的最小數(shù)量。所謂空閑子進(jìn)程是指沒(méi)有正在處理請(qǐng)求的子進(jìn)程。如果當(dāng)前空閑子進(jìn)程數(shù)少于MinSpareServers
,那么Apache將以最大每秒一個(gè)的速度產(chǎn)生新的子進(jìn)程。
只有在非常繁忙機(jī)器上才需要調(diào)整這個(gè)參數(shù)。將此參數(shù)設(shè)的太大通常是一個(gè)壞主意。
MaxSpareServers
指令
MaxSpareServers指令設(shè)置空閑子進(jìn)程的最大數(shù)量。所謂空閑子進(jìn)程是指沒(méi)有正在處理請(qǐng)求的子進(jìn)程。如果當(dāng)前有超過(guò)MaxSpareServers數(shù)量的空閑子進(jìn)程,那么父進(jìn)程將殺死多余的子進(jìn)程。
只有在非常繁忙機(jī)器上才需要調(diào)整這個(gè)參數(shù)。將此參數(shù)設(shè)的太大通常是一個(gè)壞主意。如果你將該指令的值設(shè)置為比MinSpareServers小,Apache將會(huì)自動(dòng)將其修改成"MinSpareServers+1"。
MaxClients
指令
MaxClients指令設(shè)置了允許同時(shí)伺服的最大接入請(qǐng)求數(shù)量。任何超過(guò)MaxClients限制的請(qǐng)求都將進(jìn)入等候隊(duì)列,直到達(dá)到ListenBacklog指令限制的最大值為止。一旦一個(gè)鏈接被釋放,隊(duì)列中的請(qǐng)求將得到服務(wù)。
對(duì)于非線程型的MPM(也就是prefork),MaxClients表示可以用于伺服客戶(hù)端請(qǐng)求的最大子進(jìn)程數(shù)量,默認(rèn)值是256。要增大這個(gè)值,你必須同時(shí)增大ServerLimit
。
對(duì)于線程型或者混合型的MPM(也就是beos或worker),MaxClients表示可以用于伺服客戶(hù)端請(qǐng)求的最大線程數(shù)量。線程型的beos的默認(rèn)值是50。對(duì)于混合型的MPM默認(rèn)值是16(ServerLimit)乘以25(ThreadsPerChild)的結(jié)果。因此要將MaxClients增加到超過(guò)16個(gè)進(jìn)程才能提供的時(shí)候,你必須同時(shí)增加ServerLimit的值。
MaxRequestsPerChild
指令
MaxRequestsPerChild指令設(shè)置每個(gè)子進(jìn)程在其生存期內(nèi)允許伺服的最大請(qǐng)求數(shù)量。到達(dá)MaxRequestsPerChild的限制后,子進(jìn)程將會(huì)結(jié)束。如果MaxRequestsPerChild為"0",子進(jìn)程將永遠(yuǎn)不會(huì)結(jié)束。
不同的默認(rèn)值
在mpm_netware和mpm_winnt上的默認(rèn)值是"0"。
將MaxRequestsPerChild設(shè)置成非零值有兩個(gè)好處:
*
可以防止(偶然的)內(nèi)存泄漏無(wú)限進(jìn)行,從而耗盡內(nèi)存。
*
給進(jìn)程一個(gè)有限獸命,從而有助于當(dāng)服務(wù)器負(fù)載減輕的時(shí)候減少活動(dòng)進(jìn)程的數(shù)量。
注意:
對(duì)于KeepAlive鏈接,只有第一個(gè)請(qǐng)求會(huì)被計(jì)數(shù)。事實(shí)上,它改變了每個(gè)子進(jìn)程限制最大鏈接數(shù)量的行為。
ThreadsPerChild
指令
這個(gè)指令設(shè)置了每個(gè)子進(jìn)程建立的線程數(shù)。子進(jìn)程在啟動(dòng)時(shí)建立這些線程后就不再建立新的線程了。如果使用一個(gè)類(lèi)似于mpm_winnt只有一個(gè)子進(jìn)程的MPM,這個(gè)數(shù)值要足夠大,以便可以處理可能的請(qǐng)求高峰。如果使用一個(gè)類(lèi)似于worker有多個(gè)子進(jìn)程的MPM,每個(gè)子進(jìn)程所擁有的所有線程的總數(shù)要足夠大,以便可以處理可能的請(qǐng)求高峰。
對(duì)于mpm_winnt,ThreadsPerChild的默認(rèn)值是64;對(duì)于其他MPM是25。
ThreadLimit
指令
這個(gè)指令設(shè)置了每個(gè)子進(jìn)程可配置的線程數(shù)ThreadsPerChild上限。任何在重啟期間對(duì)這個(gè)指令的改變都將被忽略,但對(duì)ThreadsPerChild的修改卻會(huì)生效。
使用這個(gè)指令時(shí)要特別當(dāng)心。如果將ThreadLimit設(shè)置成一個(gè)高出ThreadsPerChild實(shí)際需要很多的值,將會(huì)有過(guò)多的共享內(nèi)存被分配。如果將ThreadLimit和ThreadsPerChild設(shè)置成超過(guò)系統(tǒng)的處理能力,Apache可能無(wú)法啟動(dòng),或者系統(tǒng)將變得不穩(wěn)定。該指令的值應(yīng)當(dāng)和ThreadsPerChild可能達(dá)到的最大值保持一致。
對(duì)于mpm_winnt,ThreadLimit的默認(rèn)值是1920;對(duì)于其他MPM這個(gè)值是64。
注意:
Apache在編譯時(shí)內(nèi)部有一個(gè)硬性的限制"ThreadLimit
"(對(duì)于mpm_winnt是"ThreadLimit "),你不能超越這個(gè)限制。
ServerLimit
指令
對(duì)于preforkMPM,這個(gè)指令設(shè)置了MaxClients最大允許配置的數(shù)值。對(duì)于workerMPM,這個(gè)指令和ThreadLimit結(jié)合使用設(shè)置了MaxClients最大允許配置的數(shù)值。任何在重啟期間對(duì)這個(gè)指令的改變都將被忽略,但對(duì)MaxClients的修改卻會(huì)生效。
使用這個(gè)指令時(shí)要特別當(dāng)心。如果將ServerLimit設(shè)置成一個(gè)高出實(shí)際需要許多的值,將會(huì)有過(guò)多的共享內(nèi)存被分配。如果將ServerLimit和MaxClients設(shè)置成超過(guò)系統(tǒng)的處理能力,Apache可能無(wú)法啟動(dòng),或者系統(tǒng)將變得不穩(wěn)定。
對(duì)于preforkMPM,只有在你需要將MaxClients設(shè)置成高于默認(rèn)值256的時(shí)候才需要使用這個(gè)指令。要將此指令的值保持和MaxClients一樣。
對(duì)于workerMPM,只有在你需要將MaxClients和ThreadsPerChild設(shè)置成需要超過(guò)默認(rèn)值16個(gè)子進(jìn)程的時(shí)候才需要使用這個(gè)指令。不要將該指令的值設(shè)置的比MaxClients
和ThreadsPerChild需要的子進(jìn)程數(shù)量高。
注意:
Apache在編譯時(shí)內(nèi)部有一個(gè)硬限制"ServerLimit
"(對(duì)于preforkMPM為"ServerLimit ")。你不能超越這個(gè)限制。
配置apache使用workerMPM:
cd httpd-2.0.55
make clean
vi server/mpm/worker/worker.c
修改define
DEFAULT_THREAD_LIMIT 64 為100
即=你要設(shè)置的ThreadsPerChild的值(修改默認(rèn)ThreadsPerChild
)
修改define
DEFAULT_SERVER_LIMIT 16 為 25
即=你要設(shè)置的ServerLimit值(修改默認(rèn)ServerLimit值)
:wq
./configure
--prefix=/usr/local/apache --with-mpm=worker
make
make install
cd
/usr/local/apache/conf
vi httpd.conf
修改
StartServers
2
MaxClients 150
MinSpareThreads 25
MaxSpareThreads
75
ThreadsPerChild 25
MaxRequestsPerChild 0
內(nèi)容為
StartServers
3
MaxClients 2000
ServerLimit 25
MinSpareThreads 50
MaxSpareThreads
200
ThreadLimit 200
ThreadsPerChild 100
MaxRequestsPerChild 0
修改
serveradmin servername等信息為正確配置
:wq
/usr/local/apache/bin/apachectl
start
vi /etc/rc.loacl
添加 /usr/local/apache/bin/apachectl
start
PS:
用netstat -an|grep ESTABLISHED|grep 202.100.85.249:80 |wc -l
看連接數(shù),使用worker模式后,httpd進(jìn)程數(shù)變少不能反映tcp連接數(shù)
環(huán)境:
OS:Red Hat Linux As 5
1.服務(wù)器上創(chuàng)建共享目錄
mkdir
doc_share
2.編輯exports文件
vim /etc/exports
寫(xiě)入
/doc_share
192.168.2.131/255.255.255.0(rw,sync)
格式是:
要共享的目錄
共享的IP及掩碼或者域名(權(quán)限,同步更新)
3.啟動(dòng)服務(wù)
/etc/init.d/portmap restart
/etc/init.d/nfs restart
chkconfig nfs
on
chkconfig portmap on
然后關(guān)閉防火墻以及更改Selinux關(guān)于NIS的選項(xiàng)
/etc/init.d/iptables stop (防護(hù)墻服務(wù)關(guān)閉)
chkconfig iptables off
system-config-selinux (設(shè)置selinux)
查看共享的東西
[root@rac1
/]# exportfs -rv
exporting
192.168.2.131/255.255.255.0:/doc_share
試著在本機(jī)看能否加載
mount
192.168.2.131:/doc_share /mnt
[root@rac1 doc_share]# echo
aa>aa.txt
[root@rac1 doc_share]# ls
aa.txt
[root@rac1 /]# cd
/mnt
[root@rac1 mnt]# ls
aa.txt
4.客戶(hù)端
手工mount:
mount -o nolock 192.168.2.131:/doc_share
/mnt
這個(gè)時(shí)候可以看到在節(jié)點(diǎn)1上內(nèi)容了.
[root@rac2
mnt]# cd /mnt
[root@rac2 mnt]# ls
aa.txt
自動(dòng)mount:
編輯fstab文件,實(shí)現(xiàn)開(kāi)機(jī)自動(dòng)掛載
mount -t nfs IP:/目錄 掛載到的目錄
(此為臨時(shí)掛載)
如:mount -t nfs
192.168.0.9:/doce /doc
vim /etc/fstab 添加如下內(nèi)容
192.168.2.131:/doc_share /mnt nfs
defaults 0 0
相關(guān)的一些命令:
showmout命令對(duì)于NFS的操作和查錯(cuò)有很大的幫助.
showmout
-a:這個(gè)參數(shù)是一般在NFS SERVER上使用,是用來(lái)顯示已經(jīng)mount上本機(jī)nfs目錄的cline機(jī)器.
-e:顯示指定的NFS
SERVER上export出來(lái)的目錄.
例如:
showmount -e 192.168.0.30
Export list for localhost:
/tmp *
/home/linux *.linux.org
/home/public (everyone)
/home/test 192.168.0.100
exportfs命令:
如果我們?cè)趩?dòng)了NFS之后又修改了/etc/exports,是不是還要重新啟動(dòng)nfs呢?這個(gè)時(shí)候我們就可以用exportfs命令來(lái)使改動(dòng)立刻生效,該命令格式如下:
exportfs
[-aruv]
-a :全部mount或者unmount /etc/exports中的內(nèi)容
-r :重新mount
/etc/exports中分享出來(lái)的目錄
-u :umount 目錄
-v :在 export
的時(shí)候,將詳細(xì)的信息輸出到屏幕上.
具體例子:
[root @test root]# exportfs
-rv <==全部重新 export 一次!
exporting
192.168.0.100:/home/test
exporting 192.168.0.*:/home/public
exporting
*.the9.com:/home/linux
exporting *:/home/public
exporting *:/tmp
reexporting 192.168.0.100:/home/test to kernel
exportfs -au
<==全部都卸載了
-------------------------------------------------------------------------------
今天在機(jī)器上配置NFS文件系統(tǒng),在/etc/exports中加入以下信息:
/testfs 10.0.0.0/8(rw)
重啟NFS服務(wù)以后,在客戶(hù)機(jī)通過(guò)mount -o rw -t nfs 10.214.54.29:/testfs /rd1命令將網(wǎng)絡(luò)文件mount到本地。執(zhí)行完成之后,目錄是可以訪問(wèn)了,但無(wú)法寫(xiě)入。感覺(jué)有點(diǎn)奇怪,明明在命令中指定可以寫(xiě)入了。于是到網(wǎng)上搜索資料,發(fā)現(xiàn)exports目錄權(quán)限中,有這么一個(gè)參數(shù)no_root_squash。其作用是:登入 NFS 主機(jī)使用分享目錄的使用者,如果是 root 的話,那么對(duì)于這個(gè)分享的目錄來(lái)說(shuō),他就具有 root 的權(quán)限!。默認(rèn)情況使用的是相反參數(shù) root_squash:在登入 NFS 主機(jī)使用分享之目錄的使用者如果是 root 時(shí),那么這個(gè)使用者的權(quán)限將被壓縮成為匿名使用者,通常他的 UID 與 GID 都會(huì)變成 nobody 那個(gè)身份。
因?yàn)槲业目蛻?hù)端是使用root登錄的,自然權(quán)限被壓縮為nobody了,難怪無(wú)法寫(xiě)入。將配置信息改為:
/testfs 10.0.0.0/8(rw,no_root_squash)
據(jù)說(shuō)有點(diǎn)不安全,但問(wèn)題是解決了。
另外,在測(cè)試NFS文件系統(tǒng)時(shí),會(huì)經(jīng)常mount和umount文件,但有時(shí)會(huì)出現(xiàn)device is busy的錯(cuò)誤提示。你肯定感到很奇怪,我明明沒(méi)有使用啊,看看你當(dāng)前所在的目錄,是不是在mount的文件目錄中?回退到上層目錄重新umount,是不是OK了?
ichartjs是一款基于HTML5的圖形庫(kù)。使用純javascript語(yǔ)言,利用HTML5的canvas標(biāo)簽繪制各式圖形。ichartjs可以為web應(yīng)用提供簡(jiǎn)單、直觀、可交互的體驗(yàn)級(jí)圖表組件。是web圖表方面的解決方案。最近正好在學(xué)HTML5,順便就用ichartjs來(lái)練習(xí)。ichartjs目前支持餅圖、折線圖、區(qū)域圖、柱形圖、條形圖。ichartjs是基于Apache License 2.0 協(xié)議的開(kāi)源項(xiàng)目。今天介紹的是如何在android手機(jī)上動(dòng)態(tài)實(shí)現(xiàn)3D柱形圖。若想詳細(xì)了解ichartjs,可以訪問(wèn)ichartjs官網(wǎng):http://www.ichartjs.cn/index.html
實(shí)現(xiàn)主要原理是所需實(shí)現(xiàn)的數(shù)據(jù)打包成json格式,因?yàn)閕chartjs規(guī)定的數(shù)據(jù)源統(tǒng)一采用json對(duì)象方式。數(shù)據(jù)源分為單一數(shù)據(jù)源與集合多值數(shù)據(jù)源,單一數(shù)據(jù)源的值為單一的數(shù)值,而集合多值數(shù)據(jù)源為數(shù)值集合。3D柱形圖使用的單一的數(shù)據(jù)源。廢話不多說(shuō)了,直接上代碼。
首先編寫(xiě)的是封裝數(shù)據(jù)的實(shí)體類(lèi)Contact:
- package com.chinasofti.html;
-
- public class Contact {
- private String name;
- private double value;
- private String color;
-
-
-
-
-
-
-
- public Contact(String name, double value, String color) {
- this.name = name;
- this.value = value;
- this.color = color;
- }
-
-
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public double getValue() {
- return value;
- }
- public void setValue(double value) {
- this.value = value;
- }
- public String getColor() {
- return color;
- }
- public void setColor(String color) {
- this.color = color;
- }
-
- }
package com.chinasofti.html;
public class Contact {
private String name; // 瀏覽器的名稱(chēng)
private double value; // 瀏覽器對(duì)應(yīng)的所占市場(chǎng)份額值
private String color; // 在柱形圖中所顯示的顏色
/**
* 構(gòu)造函數(shù)
* @param name 瀏覽器的名稱(chēng)
* @param value 瀏覽器對(duì)應(yīng)的所占市場(chǎng)份額值
* @param color 在柱形圖中所顯示的顏色
*/
public Contact(String name, double value, String color) {
this.name = name;
this.value = value;
this.color = color;
}
// 下面是三個(gè)實(shí)例變量的getters and setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
接著創(chuàng)建一個(gè)list將所需要的contact對(duì)象添加到list中:
- import java.util.ArrayList;
- import java.util.List;
-
- import com.chinasofti.html.Contact;
-
- public class ContactService {
-
- public List<Contact> getContacts() {
- List<Contact> contacts = new ArrayList<Contact>();
- contacts.add(new Contact("IE", 32.85, "#a5c2d5"));
- contacts.add(new Contact("Chrome", 33.59, "#cbab4f"));
- contacts.add(new Contact("Firefox", 22.85, "#76a871"));
- contacts.add(new Contact("Safari", 7.39, "#9f7961"));
- contacts.add(new Contact("Opera", 1.63, "#a56f8f"));
- contacts.add(new Contact("Other", 1.69, "#6f83a5"));
- return contacts;
- }
- }
import java.util.ArrayList;
import java.util.List;
import com.chinasofti.html.Contact;
public class ContactService {
public List<Contact> getContacts() {
List<Contact> contacts = new ArrayList<Contact>();
contacts.add(new Contact("IE", 32.85, "#a5c2d5"));
contacts.add(new Contact("Chrome", 33.59, "#cbab4f"));
contacts.add(new Contact("Firefox", 22.85, "#76a871"));
contacts.add(new Contact("Safari", 7.39, "#9f7961"));
contacts.add(new Contact("Opera", 1.63, "#a56f8f"));
contacts.add(new Contact("Other", 1.69, "#6f83a5"));
return contacts;
}
}
然后編寫(xiě)android主界面代碼,實(shí)現(xiàn)list轉(zhuǎn)換成json格式字符串,并實(shí)現(xiàn)和html文件的交互:
- import java.util.List;
-
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
-
- import android.app.Activity;
- import android.os.Bundle;
- import android.util.Log;
- import android.webkit.WebView;
-
- public class MainActivity extends Activity {
- private static final String TAG = "MainActivity";
- private ContactService contactService;
- private WebView webView;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- contactService = new ContactService();
- webView = (WebView) this.findViewById(R.id.webView);
- webView.getSettings().setJavaScriptEnabled(true);
- webView.getSettings().setBuiltInZoomControls(true);
-
- webView.addJavascriptInterface(this,TAG);
- webView.loadUrl("file:///android_asset/3dchart.html");
- }
-
-
-
-
-
- public String getContacts() {
- List<Contact> contacts = contactService.getContacts();
- String json = null;
- try {
- JSONArray array = new JSONArray();
- for (Contact contact : contacts) {
-
- JSONObject item = new JSONObject();
- item.put("name", contact.getName());
- item.put("value", contact.getValue());
- item.put("color", contact.getColor());
- array.put(item);
- }
- json = array.toString();
- Log.i(TAG, json);
-
- } catch (JSONException e) {
- e.printStackTrace();
- }
- return json;
- }
- }
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private ContactService contactService; // 構(gòu)建list的類(lèi)
private WebView webView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
contactService = new ContactService();
webView = (WebView) this.findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true); // 允許使用javascript腳本語(yǔ)言
webView.getSettings().setBuiltInZoomControls(true); // 設(shè)置可以縮放
// 設(shè)置javaScript可用于操作MainActivity類(lèi)
webView.addJavascriptInterface(this,TAG);
webView.loadUrl("file:///android_asset/3dchart.html");
}
/**
* 實(shí)現(xiàn)將list轉(zhuǎn)換成json格式字符串
* @return json格式的字符串
*/
public String getContacts() {
List<Contact> contacts = contactService.getContacts();
String json = null;
try {
JSONArray array = new JSONArray();
for (Contact contact : contacts) {
JSONObject item = new JSONObject();
item.put("name", contact.getName());
item.put("value", contact.getValue());
item.put("color", contact.getColor());
array.put(item);
}
json = array.toString();
Log.i(TAG, json);
// webView.loadUrl("javascript:show('" + json + "')");
} catch (JSONException e) {
e.printStackTrace();
}
return json;
}
}
最后是編輯html文件。要實(shí)現(xiàn)ichartjs表圖,首先要保證在assets目錄下已導(dǎo)入了ichart - 1.0.js。然后對(duì)html文件進(jìn)行編輯:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>Hello World</title>
- <meta name="Description" content="" />
- <meta name="Keywords" content="" />
- <script type="text/javascript" src="ichart-1.0.js"></script>
- <script type="text/javascript">
- var data = new Array();
- var contact = window.MainActivity.getContacts(); //得到MainActivity中轉(zhuǎn)換出的json字符串
- eval('data='+contact); //得到j(luò)son數(shù)據(jù)
-
- $(function(){
- new iChart.Column3D({
- render : 'canvasDiv', //渲染的Dom目標(biāo),canvasDiv為Dom的ID
- data: data, //綁定數(shù)據(jù)
- title : 'Top 5 Browsers in August 2012', //設(shè)置標(biāo)題
- showpercent:true, //顯示百分比
- decimalsnum:2,
- width : 800, //設(shè)置寬度,默認(rèn)單位為px
- height : 400, //設(shè)置高度,默認(rèn)單位為px
- align:'left',
- offsetx:50,
- legend : {
- enable : true
- },
- coordinate:{ //配置自定義坐標(biāo)軸
- scale:[{ //配置自定義值軸
- width:600,
- position:'left', //配置左值軸
- start_scale:0, //設(shè)置開(kāi)始刻度為0
- end_scale:40, //設(shè)置結(jié)束刻度為40
- scale_space:8, //設(shè)置刻度間距為8
- listeners:{ //配置事件
- parseText:function(t,x,y){ //設(shè)置解析值軸文本
- return {text:t+"%"}
- }
- }
- }]
- }
- }).draw(); //調(diào)用繪圖方法開(kāi)始繪圖
- });
- </script>
- </head>
- <body>
- <div id='canvasDiv'></div>
- </body>
- </html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World</title>
<meta name="Description" content="" />
<meta name="Keywords" content="" />
<script type="text/javascript" src="ichart-1.0.js"></script>
<script type="text/javascript">
var data = new Array();
var contact = window.MainActivity.getContacts(); //得到MainActivity中轉(zhuǎn)換出的json字符串
eval('data='+contact); //得到j(luò)son數(shù)據(jù)
$(function(){
new iChart.Column3D({
render : 'canvasDiv', //渲染的Dom目標(biāo),canvasDiv為Dom的ID
data: data, //綁定數(shù)據(jù)
title : 'Top 5 Browsers in August 2012', //設(shè)置標(biāo)題
showpercent:true, //顯示百分比
decimalsnum:2,
width : 800, //設(shè)置寬度,默認(rèn)單位為px
height : 400, //設(shè)置高度,默認(rèn)單位為px
align:'left',
offsetx:50,
legend : {
enable : true
},
coordinate:{ //配置自定義坐標(biāo)軸
scale:[{ //配置自定義值軸
width:600,
position:'left', //配置左值軸
start_scale:0, //設(shè)置開(kāi)始刻度為0
end_scale:40, //設(shè)置結(jié)束刻度為40
scale_space:8, //設(shè)置刻度間距為8
listeners:{ //配置事件
parseText:function(t,x,y){ //設(shè)置解析值軸文本
return {text:t+"%"}
}
}
}]
}
}).draw(); //調(diào)用繪圖方法開(kāi)始繪圖
});
</script>
</head>
<body>
<div id='canvasDiv'></div>
</body>
</html>
最后得到效果為:
