分佈式session是實現分佈式部署的前提, 當前項目因爲歷史緣由未實現分佈式session, 可是因爲在kubernets中部署多個pod時, 負載均衡的調用鏈太長, 致使會話不能保持, 因此迫切須要分佈式session.php
直接在PHP中配置, 或者在代碼中集成git
session.save_handler = redis session.save_path = "tcp://127.0.0.1:6379"
ini_set("session.save_handler", "redis"); ini_set("session.save_path", "tcp://127.0.0.1:6379");
php提供了SessionHandlerInterface接口, 按照此接口進行implements, 便可完成session共享。github
/** * @see http://php.net/manual/zh/class.sessionhandlerinterface.php */ SessionHandlerInterface { abstract public bool close ( void ) abstract public bool destroy ( string $session_id ) abstract public int gc ( int $maxlifetime ) abstract public bool open ( string $save_path , string $session_name ) abstract public string read ( string $session_id ) abstract public bool write ( string $session_id , string $session_data ) } /** * @see http://php.net/manual/zh/class.sessionhandler.php */ MySessionHandler implements SessionHandlerInterface , SessionIdInterface { public bool close ( void ) public string create_sid ( void ) public bool destroy ( string $session_id ) public int gc ( int $maxlifetime ) public bool open ( string $save_path , string $session_name ) public string read ( string $session_id ) public bool write ( string $session_id , string $session_data ) }
如上是PHP文檔中對此interface的描述, 下面介紹下迅速過一下涉及到的幾個方法:redis
方法 | 說明 | |
---|---|---|
open | 方法用於基於文件的session 存儲系統, 該方法中可不放置任何代碼,能夠將其置爲空方法。 |
|
close | 和open 方法同樣,也能夠被忽略,對大多數驅動而言都用不到該方法。 | |
read | 應該返回與給定$sessionId , 相匹配的session 數據的字符串版本。 |
|
write | 應該講給定$data 寫到持久化存儲系統相應的$sessionId destroy |
從持久化存儲中移除 $sessionId 對應的數據。 |
gc | 方法銷燬大於給定 $lifetime 的全部session 數據,對自己擁有過時機制的系統如 Memcached 和 Redis 而言,該方法能夠留空。 |
實現完成後使用session_set_save_handler
完成session驅動
的註冊數據庫
$handler = new MySessionHandler(); session_set_save_handler($handler, true); // 下面這行代碼能夠防止使用對象做爲會話保存管理器時可能引起的非預期行爲 register_shutdown_function('session_write_close'); session_start(); // 如今可使用 $_SESSION 保存以及獲取數據了
Warning: 在腳本執行完畢以後, PHP內部會清除對象, 因此有可能不調用write
和close
回調函數, 這樣可能會引起非預期的行爲, 因此當使用對象做爲會話保存管理器時, 須要經過註冊shutdown
回調函數來規避風險。一般,你能夠經過調用register_shutdown_function()
函數來註冊session_write_close()
回調函數
可經過memcached
、redis
、db
等實現分佈式session
,考慮先實現redis session驅動
瀏覽器
<?php //自定義interface interface SessionInterface { public function set($key, $value, $expire); public function get($key); public function del($key); public function has($key); public function all(); } class RedisSession implements SessionInterface { }
咱們知道通常狀況下cookie中存儲着session id, 因此實現自定義session, 須要一些配置, 配置以下:緩存
參數 | 默認值 | 選項 | 描述 |
---|---|---|---|
sess.driver | files | files/database/redis/memcached/custom | 使用的存儲 session 的驅動 |
sess.cookie_name | my_session | [A-Za-z_-] characters only | session cookie 的名稱 |
sess.expiration | 7200 (2 hours) | Time in seconds (integer) | 你但願 session 持續的秒數 若是你但願 session 不過時(直到瀏覽器關閉),將其設置爲 0 |
sess.save_path | NULL | None | 指定存儲位置,取決於使用的存儲 session 的驅動 |
sess.time_to_update | 300 | Time in seconds (integer) | 該選項用於控制過多久將從新生成一個新 session ID 設置爲 0 將禁用 session ID 的從新生成 |
sess.regenerate_destroy | FALSE | TRUE/FALSE (boolean) | 當自動從新生成 session ID 時,是否銷燬老的 session ID 對應的數據 若是設置爲 FALSE ,數據以後將自動被垃圾回收器刪除 |
使用時, $_SESSION
的操做改成 RedisSession
類操做.安全
例如:cookie
$_SESSION['aa'] = 123;
改成 RedisSession::set('aa', 123);
echo $_SESSION['aa'];
改成 echo RedisSession::get('aa');
session
Warning: 因爲Redis沒有鎖機制, 這個驅動的鎖是經過一個保持300s的值來模擬的。
Redis 是一種存儲引擎,一般用於緩存,並因爲他的高性能而流行起來,這可能也正是你使用 Redis 驅動的緣由。
缺點是它並不像關係型數據庫那樣廣泛,須要你的系統中安裝了 phpredis 這個 PHP 擴展,它並非 PHP 程序自帶的。 可能的狀況是,你使用 Redis 驅動的緣由是你已經很是熟悉 Redis 了而且你使用它還有其餘的目的。
固然不想安裝phpredis客戶端時, 能承受必定的性能損失, 可以使用predis包
和文件驅動和數據庫驅動同樣,你必須經過 sess.save_path 參數來配置存儲 session 的位置。 這裏的格式有些不一樣,同時也要複雜一點,這在 phpredis 擴展的 README 文件中有很好的解釋,連接以下:
https://github.com/phpredis/p...
Warning: 這裏的 Session 類並無真的用到 'redis' 的 session.save_handler , 只是 採用了它的路徑的格式而已。
!
緣由該腳本執行了session_start(),而php session_start()後對該session的寫入是排他的,只有當腳本執行結束或顯式執行session_destroy()才能釋放session文件鎖。
你不只要知道session通常的工做原理,並且要知道它在PHP中如何實現的,還要知道它的內部存儲機制是如何工做的,如何去處理併發,如何去避免死鎖(不能去掉鎖),以及如何處理潛在的安全問題