NebulaGraph 論壇最近有些討論帖,各種姿勢來問 NebulaGraph Session 管理相關的事情,我尋思這也不是一個法子,還是來寫一篇文章來講述下 NebulaGraph 中的 Session 管理。由於本文設定為非正式的 Session 講解,所以本文主要分為理論和實操部分,在實操部分主要摘錄了論壇使用者的一些關於 Session 的理解,以及本人對 Session 相關問題的解答。
客戶端互動流程
在之前的原始碼解讀系列的客戶端部分,我們講過 Session 相關的知識點,這裡來回顧下。
透過下圖你能瞭解客戶端和服務端連線時,背後的工作原理:
簡單來說,整個 workflow 由 ConnectionPool、Session、Connection 構成,使用者透過 Session 和計算引擎進行互動,但真正和計算引擎 graphd 發生資料處理關係的是連線池當中的 Connection。
Connection Pool
在連線池初始化階段,使用者使用 Session 之前需要先建立並初始化一個連線池 ConnectionPool,連線池會在初始化時會對使用者指定的 NebulaGraph 服務所在地址建立連線 Connection。如果在用叢集部署方式部署了多個 Graph 服務,連線池會採用輪詢的策略來平衡負載,對每個地址建立近乎等量的連線。
連線池如何管理連線 Connection 呢?連線池內維護了兩個佇列,空閒連線佇列 idleConnectionQueue 和使用中的連線佇列 activeConnectionQueue,連線池會定期檢測過期空閒的連線並將其關閉。這兩個佇列在增刪元素的時候會透過讀寫鎖來確保多執行緒執行的正確性。當 Session 向連線池請求連線時,會檢查空閒連線佇列中是否有可用的連線,如果有則直接返回給 Session 供使用者使用;如果沒有可用連線並且當前的總連線數沒有超過配置中限定的最大連線數 maxConnSize,則新建一個連線給 Session;如果已經到達了最大連線數的限制,返回錯誤。
大概流程和下面流程圖類似:
一般來說,只有在客戶端程式退出時才需要關閉連線池,在關閉時池中所有的連線都會被斷開。
Session
客戶端會話 Session 透過連線池 ConnectionPool 生成,使用者需要提供使用者密碼進行校驗,在校驗成功後使用者會獲得一個 Session 例項,並透過 Session 中的連線與服務端進行通訊。最常用的介面是 execute()
,如果在執行時發生錯誤,客戶端會檢查錯誤的型別。如果是網路原因或者和 session 通訊的 graph 服務 down 掉,客戶端會自動重連,嘗試繫結一個可用的連線重發請求。
需要注意的是,一個 Session 不支援被多個執行緒同時使用,正確的方式是用多個執行緒申請多個 Session,每個執行緒使用一個 Session。Session 被釋放時,其持有的連線會被放回到連線池的空閒連線佇列 idleConnectionQueue中,以便於之後被其他 Session 複用。
Connection
連線 Connection 每個連線例項都是等價的,可以被任意 Session 持有。這樣設計的目的是這些連線可以被不同的 Session 複用,減少反覆開關 Transport 的開銷。連線會將客戶端的請求傳送到服務端並將其結果返回給 Session。
社群使用者實踐
這裡主要收錄了使用者在使用連線池、Session 遇到的比較有代表性的問題。
如何獲取多個 Session
可透過 https://discuss.nebula-graph.com.cn/t/topic/3765 檢視完整的交流對話。
Sharry2021gu 提問:連線池怎麼會有多個 Session 呢?用來測試併發效能。像下面的 pipeline 裡怎麼才能獲取不同的 session?
答:因為你給 Session 包了一層,你直接用 java-client 的 ConnectionPool 拿 Session 就可以了,ConnectionPool 是支援多執行緒呼叫 getSession 的介面。
對 Session 管理的理解
下面部分收錄社群使用者 wuyou 對 Session 管理的理解,你可以透過 https://discuss.nebula-graph.com.cn/t/topic/8777 瞭解全部內容。這塊的內容同上面客戶端互動流程有所重疊,不過都是需要注意的使用點。
- NebulaPool 的
maxConnSize
是最大連線數,一個 Session 只能使用一個連線,可以簡單地認為 maxConnSize 就是這個 NebulaPool 裡面支援的最大 Session 數量,適當調整就行了; - NebulaPool 使用常規的單例就行,應用程式結束時記得關閉就行了。Session 的話可以在 graph 配置中設定
session_idle_timeout_secs
讓其自動銷燬就行了; Session 的建立和銷燬是有開銷的,會有五次 IO 互動:Client 和 Graphd 會有 3 次 IO 互動以及 Graphd 和 Metad 有 2 次 IO 互動。
Client 和 Graphd IO 互動:
- 第一次是檢測連線是否是正常的;
- 第二次是做一次認證獲取 sessionId;
- 第三次是 USE SPACE;
Graphd 和 Metad IO 互動:
- 第一次是生成 sessionId;
- 第二次是獲取 space 資訊。
所以,一般情況下不建議每次請求都從 pool getSession,execute 之後再 release,這會有效能開銷,而且還會在服務端生成很多隻用一次的 Session。
- Session 是執行緒不安全的,多個執行緒使用同一 Session 會直接報錯。應對多執行緒可以自己維護一份 Session 列表。如果是多個 space 的話,可以針對每個 space 維護一份 session 列表。這一點目前需要自己實現,暫時沒有官方的好的方式。
自維護 Session
wuyou 提問:官方說需要自己維護 Session 是什麼意思,感覺 NebulaPool 已經在維護了,應用層只需要每次直接 getSession 就完事兒了,每次執行完 nGQL 之後 session.release 釋放掉 Session,讓其回到 pool 中就可以。
答:這裡解釋下如何理解需要自己維護 Session。NebulaPool 維護的只是 Connection,Connection 是無狀態的。Session 的維護是指多執行緒使用的情況下複用 Session 做多次查詢,比如:Session 內部分 sessionInUse 和 idleSession佇列,新建的 Session 放 idle 佇列,用的時候起一個執行緒持有這個 Session 並且移到 inUse 佇列,用完之後不用釋放 Session 放回 idleSession 供下次使用。
Connection 的釋放
wuyou 提問:放回連線池的 Connection 什麼時候會被釋放?
答:有兩種方式來釋放 Connection。第一種,手動關閉連線池時裡面的連線會被釋放。另外一種是,連線池裡的物件池透過 setSoftMinEvictableIdleTimeMillis()
自動定期釋放。
空閒會話超時設定
可透過 https://discuss.nebula-graph.com.cn/t/topic/9037 檢視完整的交流對話。
Ian 提問:設定空閒會話超時時間為 8 小時,是以 SHOW SESSIONS 結果的 update_time 來加 8 小時嗎?如果一直在用,就不會過期?
答:是 udpate_time + 8H。使用過程中 session 的 idle time 會更新,如果你一直在用會話就不會過期。
謝謝你讀完本文 (///▽///)
要來近距離體驗一把圖資料庫嗎?現在可以用用 NebulaGraph Cloud 來搭建自己的圖資料系統喲,快來節省大量的部署安裝時間來搞定業務吧~ NebulaGraph 阿里雲端計算巢現 30 天免費使用中,點選連結來用用圖資料庫吧~
想看原始碼的小夥伴可以前往 GitHub 閱讀、使用、(^з^)-☆ star 它 -> GitHub;和其他的 NebulaGraph 使用者一起交流圖資料庫技術和應用技能,留下「你的名片」一起玩耍呢~