关于Session管理的问题

怎么保重高并发快速查询继续讨论:

看了很多帖子讨论session的管理,得出以下结论,能否帮忙甄别以下说法是否正确:

  1. NebulaPool的 maxConnSize是最大连接数,一个session只能使用一个连接,是否可以简单的认为maxConnSize就是这个NebulaPool里面支持的最大session数量,适当调整就行了

2.关于NebulaPool使用常规的单例就行了,应用程序结束时记得关闭就行了,session的话可以配置session_idle_timeout_secs让其自动销毁就行了

  1. session的创建和销毁是有开销的,会有五次io交互:client和graphd会有三次io交互,第一次是检测连接是否是正常的,第二次是做一次认证获取session id,第三次是 use space;graphd会和metad有两次io,第一次是生成session id,第二次是获取space信息。所以一般情况下是不建议每次都从poll getSession,excute之后在release的,会有性能开销

4.session是线程不安全的,多个线程使用同一session会直接报错。应对多线程可以自己维护一份session列表,如果是多个space的话可以针对每个space维护一份session列表。这一点目前需要自己实现,暂时没有官方的好的方式

我使用的是java语言, 针对自己维护session列表的方式,目前是使用的java的ThreadLocal来存储session,用完之后没有release session,使用会话自动过期的配置,只是remove了treadloca防止内存泄漏。

如果没有维护session,是不是意味着,每一次的查询都是从NebulaPool getSession,如果maxConnSize=10,那么连续点了10次查询,如果session过期时间是一分钟,且每次执行之后没有手动释放,那session就会报错,连接不够了。

1 个赞
  1. 是的
  2. 是的
  3. 是的
  4. 是的, 需要保证一个session只被一个线程持有

是的, 你说的场景中 getSession() 会优先在连接池的 idle 队列里面拿连接, 如果 idle 队列里没有可用连接的话会试图新建连接, 这个时候就会和 pool config 里的 maxConnSize 比较目前是否到达连接最大值, 因为 session 没有维护, 这时连接池里的10个连接都被不同 session 持有了, 并且到达连接池的连接数上限, 所以获取新 session 会失败

1 个赞



追了一下代码, 发现从NebulaPool每次getSession的时候其实是会从队列里面去取的。
所以还是有一点疑惑,其他帖子里面看到官方大佬们说需要自己维护session是什么意思,感觉NebulaPool已经在维护了,应用层只需要每次直接getSession就完事儿了,每次执行完nGQL之后session.release释放掉session,让其回到pool中就可以,因为如果不释放的话是没法被再次使用的。只需要适当的调整maxConnSize就行了。

这样看来使用ThreadLocal保存当前线程的session就没有太大的意义

NebulaPool 维护的只是 connection, connection 是无状态的.
Session 的维护是指多线程试用的情况下复用 session 做多次查询, 比如分 sessionInUse 和 idleSession队列, 新建的 session 放 idle 队列, 用的时候起一个线程持有这个 session 并且移到 inUse 队列, 用完之后不用释放 session 放回 idleSession 供下次使用

我举个例子您看对吗(前置条件NebulaPool是单例的)

目前maxConnSize=10, 意味着我可以有10个conn连接。 初始化的时候pool里面没有连接,idle队列也没有session。第一次query的时候,从pool里面获取了一个session,这个时候maxConnSize= 10 - 1,然后被这个session持有,idle队列也是没有session的,因为session还没有被释放,自动过期也未过期。 执行完session.execute之后,如果程序release了session,这个时候idle队列里面就存在了一个session。如果没有手动释放,也没有过期,idle是没有任何session的。

第二次query的时候,从pool.getSession (如果第一次release了session)的时候不用重新创建session,因为第一次释放了session,这个session还没有过期的话是在idle队列里面的,可以被其他请求使用。

后续逻辑类似。

所以我在其他帖子看到的session创建有开销,查询之后不需要release。 我是不是可以理解为,在idle队列存在session的时候其实不用考虑创建开销。 我每次操作之后都release 掉session其实是可以的。因为我释放了之后,空闲队列里面就会有可复用的session了。 也不存在创建开销一说了。

您这里说的情况我理解是指单个线程可以多次复用同一session, 如果使用ThreadLocal的话 就是类似于这种效果,线程和session绑定, 同一个线程可以反复使用自己的session。 其他的线程来了之后还是得创建自己的session,或者说idle队列里面正好有空闲的session(其他请求释放过,然后未过期)

首先需要区分 session 和 connection 是不同的概念, pool 里面只有 connection 实例没有 session, session 是完全由用户自己管理的.

getSession() 分两步, 第一步向 meta 鉴权, 鉴权通过后从 pool 里拿连接

session.release() 会通知服务端把当前 session 移除, 同时在客户端把 connection 返还给连接池的 idle 队列, 这个 connection 可以被其他 session 复用

这里和队列没有关系, getSession() 必定会和 meta 通信鉴权产生开销

我知道 pool里面的是connection, session每次都是直接new出来的,由connection等作为构造函数生成。

所以所谓的自己管理session不去release掉,其实指的是让这个session保持和conn的绑定,以便下次复用这个session(同一线程)。 同时release释放session其实也是将conn重新放回连接池。 放回连接池的conn会在什么时候释放呢

这里我讲错了, 应该是conn可以从池里直接拿,但是getSession还是会通过conn鉴权,必定会有开销,所以其他帖子才将不release的话可以节省开销

1 个赞

两种方式:

  1. 手动关闭连接池时, 里面的连接会被释放
  2. 连接池里的对象池通过 setSoftMinEvictableIdleTimeMillis() 自动定期释放
1 个赞

感谢不厌其烦的解答帮助

3 个赞