Sessions共享技術設計

概述

分佈式session是實現分佈式部署的前提, 當前項目因爲歷史緣由未實現分佈式session, 可是因爲在kubernets中部署多個pod時, 負載均衡的調用鏈太長, 致使會話不能保持, 因此迫切須要分佈式session.php

實現方案

a. 修改配置文件php.ini

直接在PHP中配置, 或者在代碼中集成git

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

b. 代碼中動態設置

ini_set("session.save_handler", "redis");
ini_set("session.save_path", "tcp://127.0.0.1:6379");

c. 實現SessionHandlerInterface接口

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數據,對自己擁有過時機制的系統如 MemcachedRedis 而言,該方法能夠留空。

實現完成後使用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內部會清除對象, 因此有可能不調用 writeclose回調函數, 這樣可能會引起非預期的行爲, 因此當使用對象做爲會話保存管理器時, 須要經過註冊 shutdown回調函數來規避風險。一般,你能夠經過調用 register_shutdown_function()函數來註冊 session_write_close()回調函數

d. 自定義session驅動

可經過memcachedredisdb等實現分佈式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

redis驅動實現

Warning: 因爲Redis沒有鎖機制, 這個驅動的鎖是經過一個保持300s的值來模擬的。

Redis 是一種存儲引擎,一般用於緩存,並因爲他的高性能而流行起來,這可能也正是你使用 Redis 驅動的緣由。

缺點是它並不像關係型數據庫那樣廣泛,須要你的系統中安裝了 phpredis 這個 PHP 擴展,它並非 PHP 程序自帶的。 可能的狀況是,你使用 Redis 驅動的緣由是你已經很是熟悉 Redis 了而且你使用它還有其餘的目的。

固然不想安裝phpredis客戶端時, 能承受必定的性能損失, 可以使用predis包

https://github.com/nrk/predis

和文件驅動和數據庫驅動同樣,你必須經過 sess.save_path 參數來配置存儲 session 的位置。 這裏的格式有些不一樣,同時也要複雜一點,這在 phpredis 擴展的 README 文件中有很好的解釋,連接以下:
https://github.com/phpredis/p...

Warning: 這裏的 Session 類並無真的用到 'redis' 的 session.save_handler , 只是 採用了它的路徑的格式而已。

注意事項

a. 瀏覽器A標籤腳本執行過程當中,打開B標籤訪問同一個腳本,會被pending,直到A執行完畢。

緣由該腳本執行了session_start(),而php session_start()後對該session的寫入是排他的,只有當腳本執行結束或顯式執行session_destroy()才能釋放session文件鎖。

b. 自定義session驅動並非那麼簡單, 須要用到不少知識來正確的實現它。

你不只要知道session通常的工做原理,並且要知道它在PHP中如何實現的,還要知道它的內部存儲機制是如何工做的,如何去處理併發,如何去避免死鎖(不能去掉鎖),以及如何處理潛在的安全問題

相關文章
相關標籤/搜索