在網(wǎng)站使用nginx+php做負載均衡情況下,,同一個IP訪問同一個頁面會被分配到不同的服務(wù)器上,如果session不同步的話,就會出現(xiàn)很多問題,,比如說最常見的登錄狀態(tài),。
下面羅列幾種nginx負載均衡中session同步的方式
1)不使用session,,換用cookie session是存放在服務(wù)器端的,cookie是存放在客戶端的,,我們可以把用戶訪問頁面產(chǎn)生的session放到cookie里面,就是以cookie為中轉(zhuǎn)站,。你訪問web服務(wù)器A,,產(chǎn)生了session然后把它放到cookie里面,當你的請求被分配到B服務(wù)器時,,服務(wù)器B先判斷服務(wù)器有沒有這個session,,如果沒有,再去看看客戶端的cookie里面有沒有這個session,,如果也沒有,,說明session真的不存,如果cookie里面有,,就把cookie里面的sessoin同步到服務(wù)器B,,這樣就可以實現(xiàn)session的同步了。 說明:這種方法實現(xiàn)起來簡單,,方便,,也不會加大數(shù)據(jù)庫的負擔,但是如果客戶端把cookie禁掉了的話,,那么session就無從同步了,,這樣會給網(wǎng)站帶來損失;cookie的安全性不高,,雖然它已經(jīng)加了密,,但是還是可以偽造的。
2)session存在數(shù)據(jù)庫(MySQL)中 PHP可以配置將session保存在數(shù)據(jù)庫中,,這種方法是把存放session的表和其他數(shù)據(jù)庫表放在一起,,如果mysql也做了集群的話,每個mysql節(jié)點都要有這張表,,并且這張session表數(shù)據(jù)表要實時同步,。 但是要注意的是: 用數(shù)據(jù)庫來同步session,會加大數(shù)據(jù)庫的IO,,增加數(shù)據(jù)庫的負擔,。而且數(shù)據(jù)庫讀寫速度較慢,不利于session的適時同步,。
3)session存在memcache或者redis中 memcache可以做分布式,,php配置文件中設(shè)置存儲方式為memcache,這樣php自己會建立一個session集群,,將session數(shù)據(jù)存儲在memcache中,。 特別說明: 以這種方式來同步session,,不會加大數(shù)據(jù)庫的負擔,并且安全性比用cookie大大的提高,,把session放到內(nèi)存里面,,比從文件中讀取要快很多。但是memcache把內(nèi)存分成很多種規(guī)格的存儲塊,,有塊就有大小,,這種方式也就決定了,memcache不能完全利用內(nèi)存,,會產(chǎn)生內(nèi)存碎片,,如果存儲塊不足,還會產(chǎn)生內(nèi)存溢出,。
4)采用nginx中的ip_hash機制 nginx中的ip_hash技術(shù)能夠?qū)⒛硞€ip的請求定向到同一臺后端web機器中,,這樣一來這個ip下的某個客戶端和某個后端web機器就能建立起穩(wěn)固的session。 也就是說,,ip_hash機制能夠讓某一客戶機在相當長的一段時間內(nèi)只訪問固定的后端的某臺真實的Web服務(wù)器,,這樣會話就會得以保持,我們在網(wǎng)站頁面進行l(wèi)ogin的時候,, 就不會在后面的web服務(wù)器之間跳來跳去了,,自然也不會出現(xiàn)登陸一次后網(wǎng)站又提醒你沒有登陸需要重新登陸的情況;
ip_hash是在upstream配置中定義的:
1 2 3 4 5 6 7 8 9 10 11 12 | upstream nginx.example.com {
server 192.168.74.235:80;
server 192.168.74.236:80;
ip_hash;
}
server {
listen 80;
location / {
proxy_pass
http: //nginx .example.com;
}
}
|
ip_hash是容易理解的,,但是因為僅僅能用ip這個因子來分配后端web,,因此ip_hash是有缺陷的,不能在一些情況下使用: a)nginx不是最前端的服務(wù)器,。 ip_hash要求nginx一定是最前端的服務(wù)器,,否則nginx得不到正確ip,就不能根據(jù)ip作hash,。譬如使用的是squid為最前端,,那么nginx取ip時只能得到squid的服務(wù)器ip地址,用這個地址來作分流是肯定錯亂的,。 b)nginx的后端還有其它方式的負載均衡,。 假如nginx后端又有其它負載均衡,將請求又通過另外的方式分流了,,那么某個客戶端的請求肯定不能定位到同一臺session應(yīng)用服務(wù)器上,。這么算起來,nginx后端只能直接指向應(yīng)用服務(wù)器,,或者再搭一個squid,,然后指向應(yīng)用服務(wù)器。最好的辦法是用 location作一次分流,,將需要session的部分請求通過ip_hash分流,,剩下的走其它后端去,。
--------------------------------------------------------------------------------------------------------------------------------
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | ----------------------------順便說一下之前線上用過的nginx負載均衡中的session共享處理方案----------------------------
用的就是上面第三站方式,將session存放在memcached里面,。
公司的一些網(wǎng)站頁面(LNMP框架)涉及到登陸需求(有sessionID),,用到了memcache緩存服務(wù),將php的sessionID緩存到memcache里面,。
將sessionID放在memcache里后,,會加快頁面訪問速度,頁面訪問飛快,!
如果memcache里面存放的只是sessionID,而沒有其他業(yè)務(wù),,那么memcache服務(wù)器的內(nèi)存消耗就不大,!
首先保障php擴展模塊里要支持memcached功能(即一定要安裝php的memcached擴展模塊)
[root@huanqiu vhosts] # /Data/app/php5.5.1/bin/php -m
[PHP Modules]
..........
memcached
...........
遇到問題:
在遷移網(wǎng)站業(yè)務(wù)的過程中(遷移后使用的是新的memcache機器)
由于php.ini和代碼中的memcache連接信息沒有及時修改或者沒有完全修改過來,導致遷移后的頁面訪問速度有點緩慢,,有點卡,!
最后仔細排查,把所有有關(guān)memcache連接信息的配置都改過來了,,遷移后的頁面訪問速度就正常了,!
1)
首先部署三臺memcache服務(wù)器,主機名分別是memcache1.server ,,memcache2.server ,,memcache3.server ,啟動相應(yīng)的端口,。
注意,,不用業(yè)務(wù)應(yīng)用到的memcache服務(wù)端口不能沖突。
比如:業(yè)務(wù)A用到memcache1-3.server服務(wù)器的11021,11022,11023端口,,業(yè)務(wù)B就用到了memcache1-3.server的11031,11032,11033端口
部署memcache集群服務(wù)
yum安裝即可,,部署三臺memcache1,memcache2,,memcache3
啟動相應(yīng)緩存端口
[root@memcache2 ~] # ps -ef|grep memcache
root 6139 1 0 May30 ? 00:00:05 /usr/bin/memcached -d -m 512 -p 11021 -u root -c 4096 -P /var/lib/memcache/logs/memcached_11021 .pid
root 6184 1 0 May30 ? 00:00:05 /usr/bin/memcached -d -m 512 -p 11022 -u root -c 4096 -P /var/lib/memcache/logs/memcached_11022 .pid
root 6198 1 0 May30 ? 00:00:05 /usr/bin/memcached -d -m 512 -p 11023 -u root -c 4096 -P /var/lib/memcache/logs/memcached_11023 .pid
root 6214 1 0 May30 ? 00:00:05 /usr/bin/memcached -d -m 512 -p 11031 -u root -c 4096 -P /var/lib/memcache/logs/memcached_11031 .pid
root 6229 1 0 May30 ? 00:00:05 /usr/bin/memcached -d -m 512 -p 11032 -u root -c 4096 -P /var/lib/memcache/logs/memcached_11032 .pid
root 6244 1 0 May30 ? 00:00:05 /usr/bin/memcached -d -m 512 -p 11033 -u root -c 4096 -P /var/lib/memcache/logs/memcached_11033 .pid
將上面的程序添加到開機啟動 /etc/rc . local 里面
2)在業(yè)務(wù)機器上應(yīng)用memcache緩存
a)比如業(yè)務(wù)A
首先在相應(yīng)的業(yè)務(wù)服務(wù)器上的 /etc/hosts 里設(shè)置主機映射(如果能 ping 通memcache機器的內(nèi)網(wǎng),,就用內(nèi)網(wǎng))
#vim /etc/hosts
192.168.1.23 memcache1.server
192.168.1.24 memcache2.server
192.168.1.25 memcache3 .server
首先在php的php.ini里面設(shè)置memcache緩存
#vim /Data/app/php/etc/php.ini
...............
[Session]
session.save_handler = memcached
session.save_path = "memcache1.server :11021,memcache2.server :11022,memcache3.server :11023"
然后重啟php服務(wù)
最后在相應(yīng)的代碼程序里使用memcache緩存,比如:
# vim main.php
$config[ 'params' ][ 'erp_host' ] = 'http://www.' ;
// 以下是memcache配置,,把相應(yīng)的參數(shù)都換成相應(yīng)環(huán)境下的
$config[ 'components' ][ 'cache' ][ 'class' ] = 'system.caching.CMemCache' ;
$config[ 'components' ][ 'cache' ][ 'useMemcached' ] = 'true' ;
$config[ 'components' ][ 'cache' ][ 'keyPrefix' ] = '' ;
$config[ 'components' ][ 'cache' ][ 'hashKey' ] = false ;
$config[ 'components' ][ 'cache' ][ 'serializer' ] = false ;
$config[ 'components' ][ 'cache' ][ 'servers' ][0][ 'host' ] = 'memcache1.server' ;
$config[ 'components' ][ 'cache' ][ 'servers' ][0][ 'port' ] = 11021;
$config[ 'components' ][ 'cache' ][ 'servers' ][0][ 'weight' ] = 10;
...........................
b)業(yè)務(wù)B
在相應(yīng)業(yè)務(wù)服務(wù)器的 /etc/hosts 里設(shè)置主機映射(如果能 ping 通memcache機器的內(nèi)網(wǎng),,就用內(nèi)網(wǎng))
#vim /etc/hosts
192.168.1.23 memcache1.server
192.168.1.24 memcache2.server
192.168.1.25 memcache3 .server
首先在php的php.ini里面設(shè)置memcache緩存
#vim /Data/app/php/etc/php.ini
...............
[Session]
session.save_handler = memcached
session.save_path = "memcache1.server :11031,memcache2.server :11032,memcache3.server :11033"
然后重啟php服務(wù)
最后在相應(yīng)的代碼程序里使用memcache緩存,比如:
# vim main.php
$config[ 'params' ][ 'erp_host' ] = 'http://erp.' ;
// 以下是memcache配置,,把相應(yīng)的參數(shù)都換成相應(yīng)環(huán)境下的
$config[ 'components' ][ 'cache' ][ 'class' ] = 'system.caching.CMemCache' ;
$config[ 'components' ][ 'cache' ][ 'useMemcached' ] = 'true' ;
$config[ 'components' ][ 'cache' ][ 'keyPrefix' ] = '' ;
$config[ 'components' ][ 'cache' ][ 'hashKey' ] = false ;
$config[ 'components' ][ 'cache' ][ 'serializer' ] = false ;
$config[ 'components' ][ 'cache' ][ 'servers' ][0][ 'host' ] = 'memcache1.server' ;
$config[ 'components' ][ 'cache' ][ 'servers' ][0][ 'port' ] = 11031;
$config[ 'components' ][ 'cache' ][ 'servers' ][0][ 'weight' ] = 10;
.............................................
--------------------------------------------------------------------------------------------------
清理memcache緩存的方法:
1)
默認memcache會監(jiān)聽11221端口,,如果想清空服務(wù)器上memecache的緩存,大家一般使用的是:
telnet localhost 11211
flush_all
2)同樣也可以使用:
echo "flush_all" | nc localhost 11211
使用flush_all 后并不是刪除memcache上的key,,而是置為過期
|
------------------------------------php.ini中關(guān)于session屬性的相關(guān)設(shè)置------------------------------------- 1) session.use_cookies:是否在客戶端用 cookie 來存放會話 ID,,1是開啟 ,,0是關(guān)閉 若session.use_cookies = 1 sessionid在客戶端采用的存儲方式,置1代表使用cookie記錄客戶端的sessionid,,同時,,$_COOKIE變量里才會有$_COOKIE[‘PHPSESSIONID’]這個元素存在
一般腳本語言都會原生支持“session機制”,如PHP程序配置: 設(shè)置php.ini的session.use_trans_sid = 1,,PHP自動在URL里傳遞session id 設(shè)置php.ini的session.use_cookies = 1,,使用cookie在客戶端保存session id
2) session.auto start: 將php.ini中的如下選項配置修改即可: session.auto_start=0 修改成 sessioin.auto_start=1 開啟session.auto_start 優(yōu)點在于,任何時候都不會因忘記執(zhí)行session_start()或session_start()在程序里的位置不對,,而導致錯誤,; 缺點在于,如果你使用的是第三方代碼,,則必須刪去其中的全部 session_start(),,否則將不能得到正確的結(jié)果。
3) session的內(nèi)容存在文件里的話,文件在哪兒? 如果不指定, Linux下默認在 "/tmp"目錄,。 線上在php.ini配置文件了做了指定,,session內(nèi)容存放在memcache緩存里。 默認session內(nèi)容是存儲在文件里的,,即session.save_handler = files 但是我們線上是設(shè)置將session內(nèi)容保存到memcache里的
線上環(huán)境下的配置: [Session] ; Handler used to store/retrieve data. ; http:///session.save-handler ;session.save_handler = files session.save_handler = memcached session.save_path = "memcache1.huanqiu.com:11311,memcache1.huanqiu.com:11312,memcache2.huanqiu.com:11311,memcache2.huanqiu.com:11312"
4) session的生命周期的設(shè)置 a)session的默認生命周期是多久? 答:關(guān)閉瀏覽器就失效 原因:因為session_id存在于cookie,而默認情況,cookie關(guān)閉瀏覽器即失敗. b)如何設(shè)置session生命周期為30分鐘呢? 在php.ini文件里設(shè)置session.cookie_lifetime = 1800
線上生產(chǎn)環(huán)境下設(shè)置的是7天,,生命周期是一周 ; Lifetime in seconds of cookie or, if 0, until browser is restarted. ; http:///session.cookie-lifetime session.cookie_lifetime = 604800
5) session的名字 ; Name of the session (used as cookie name). ; http:///session.name session.name = PHPSESSID
------------------------------------------session與cookie的簡單區(qū)別----------------------------------------- session和cookie本質(zhì)上確實是兩個東西,但cookie同時也是session id的載體,,cookie保存session id,。 1)cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務(wù)器上,。 session保存在服務(wù)器端與瀏覽器設(shè)置無關(guān),,cookie在客戶端并受瀏覽器設(shè)置限制。 cookie是在你的電腦上保存的,session是在服務(wù)器上的. 也就是說你換一個電腦你的cookie就不起作用了, 而session只要你的瀏覽器不關(guān)就還能訪問到. 通常的都是兩者結(jié)合著用的. cookie的話你自己就可以通過對瀏覽器的設(shè)置禁用掉.這樣就不起作用了
2)cookie不是很安全,,別人可以分析存放在本地的cookie并進行cookie欺騙,,考慮到安全應(yīng)當使用session。 session是服務(wù)器端緩存,,cookie是客戶端緩存,。 cookie機制采用的是在客戶端保持狀態(tài)的方案,而session機制采用的是在服務(wù)器端保持狀態(tài)的方案
3)session會在一定時間內(nèi)保存在服務(wù)器上,。當訪問增多,,會比較占用你服務(wù)器的性能,考慮到減輕服務(wù)器性能方面,,應(yīng)當使用cookie,。 session是服務(wù)器保持客戶端狀態(tài)信息的方案,一般是保存在服務(wù)器中的一塊內(nèi)存中,session超時時間在服務(wù)器端進行設(shè)置,。 cookie是客戶端保持用戶信息的方案,,一般是文件形式保存,cookie清空時間是在客戶端瀏覽器設(shè)置,。 從開發(fā)角度說,,session信息可以通過技術(shù)方案寫到客戶端保存,cookie中的用戶信息,,也可以在用戶訪問該網(wǎng)站時,,通過技術(shù)手段自動更新用戶的session信息。
4單個cookie保存的數(shù)據(jù)不能超過4K,,很多瀏覽器都限制一個站點最多保存20個cookie,。
5建議:將登陸信息等重要信息存放為session;其他信息如果需要保留,,可以放在cookie中
-------------------------------------------開啟session功能---------------------------------------- 開啟session功能是很重要的,,比如下面一個場景:某個網(wǎng)站程序在測試服務(wù)器上調(diào)試,首頁是ok的,,但一到后臺去登錄就登錄不進去,起初懷疑是rewrite規(guī)則沒有寫對,,后排查就是因為session功能沒有打開引起的,! 那么session應(yīng)該如何開啟? 1)編輯php.ini配置文件 session.save_path=文件夾路徑 指向任意一個有寫權(quán)限的目錄就行了. register_globals = On 打開全局變量,如果不打開,你就這樣用$_SESSION['sessioname'];但是我本人從來沒成功過. 2)重啟php服務(wù)即可(如果是lamp模式,,就重啟apache)
-----------------------------------------看一個linux下Session丟失的案例分析---------------------------------------- 由于各種原因需要進行代碼遷移,,遷移后重新搭建php環(huán)境,運行代碼,。最后在登錄頁面時發(fā)現(xiàn)后臺不能訪問,,會直接返回到登錄頁面,接著對代碼進行測試,,沒有報任何錯誤,,最后排查是因為跳轉(zhuǎn)時session丟失造成的!那么session如何會丟失呢,? 發(fā)現(xiàn)造成這個原因有這幾種: a)session存儲路徑(目錄)不存在,,自然就無法生成session臨時文件 b)session存儲路徑下有沒有權(quán)限,如果沒有,,也就不可能存儲session數(shù)據(jù) c)能正常存session數(shù)據(jù),,但session存入后被清空
嘗試解決的措施: a)在項目根目錄下創(chuàng)建phpinfo.php文件,在文件中寫入phpinfo(),運行此文件,,查看頁面,,就可以找到session的存儲路徑, b)在服務(wù)器上查找session存儲路徑是否存在,不存在創(chuàng)建存儲目錄,,并分配權(quán)限,,如果有session存儲路徑,就查看其是否有權(quán)限,,沒有就分配權(quán)限,, c)是否是第三個原因,可在phpinfo.php頁面中查找date.timezone是否設(shè)置不對,,然后在php.ini配置文件中找到date.timezone進行配置
------------------------------------------------------------------------------------------------------------------- 需要清楚知道的: 1)上面在php.ini文件里將session.save_handler修改為memcached,,即表示將php的session信息存放到memcache里(前提是安裝了memcached擴展),然后在session.save_path處配置連接memcache信息,。如: session.save_handler = memcached session.save_path = "memcache1.huanqiu.com:11311,memcache1.huanqiu.com:11312,memcache2.huanqiu.com:11311,memcache2.huanqiu.com:11312"
注意: 帶d的memcached擴展,,則session.save_path配置連接的時候不需要加tcp:// 如果是不帶d的memcache擴展,則session.save_path配置連接的時候需要加tcp://
2)如果將session.save_handler修改為redis,,即表示將php的session信息存放到redis里(前提是安裝了php的phpredis擴展),,然后在session.save_path處配置redis的connect 地址。如下: session.save_handler = redis session.save_path = "tcp://127.0.0.1:6379" -------------------------------------------------------------------------------------------------------------------
|