
# 什么是逻辑会话（Logical Sessions）
#### 概述
在dds中，服务端会话（server sessions）或者逻辑会话（logical sessions）是一种机制，用于在服务端维护和管理客户端的操作状态。应用程序使用客户端会话与服务端会话进行交互。
#### 会话的生命周期
1. 会话的创建
   - 会话的显式创建 会话在客户端请求时由服务端创建。会话通常由驱动程序通过API创建。例如，使用mongo shell创建session：
     ```
     // Start a session.
     session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
     ```
     创建的会话将在服务端维护一个独特的会话ID，用于识别和管理会话。
     ```
     session { "id" : UUID("1c6480a3-8e8d-4726-9f1b-6bf2f6b2b606") }
     ```
     
   
   
   
   - 会话的隐式创建 隐式会话是指在执行某些操作时，驱动程序自动创建会话而无需显式地调用startSession方法。隐式会话主要用于简化开发者的代码，使操作更加便捷。当客户执行数据库操作而没有显式地提供会话参数时，驱动程序会自动创建一个会话。例如，在插入文档或查询数据时，驱动程序会在后台创建一个隐式会话，并在操作完成后自动结束会话。
     ![](https://support.huaweicloud.com/dds_faq/public_sys-resources/caution_3.0-zh-cn.png)
     服务端可以缓存的最大会话数默认为1000000，当会话数大于该值时，将无法显式或者隐式创建会话。
     **会话达到上限时的行为**
     - 拒绝新的会话：如果会话资源达到上限，DDS将无法创建新的会话。这意味着新的操作请求将会被拒绝或阻塞，直到现有的会话释放资源。
     
     - 资源争用：大量的会话可能会导致资源争用，例如内存和CPU利用率增加。这可能会影响数据库的性能和响应时间。
     
     - 事务失败：如果在会话达到上限时尝试启动新事务，可能会导致事务失败。客户端会收到错误消息，指示会话资源已耗尽。
       
   
   - 会话的使用 会话在使用过程中可以进行多种数据库操作，包括读写操作和事务操作。所有在会话上下文中的操作都会绑定到该会话。例如：
     ```
     coll1 = session.getDatabase("mydb1").foo;
     coll2 = session.getDatabase("mydb2").bar;
     coll1.insertOne( { abc: 1 } );
     coll2.insertOne( { xyz: 999 } )。
     ```
     
   
   - 会话的终止 会话可以显式终止，也可以在超时后自动终止。显式终止通过调用endSession方法：
     ```
     session.endSession();
     ```
     服务器会自动清理终止会话所占用的资源。
     
    
2. 会话的管理
   - 事务管理 会话是事务管理的核心。在事务开始时，服务器会在会话上下文中记录事务操作，确保这些操作要么全部提交，要么全部回滚。例如：
     ```
     db.getSiblingDB("mydb1").foo.insertOne(
     {abc: 0},
     { writeConcern: { w: "majority", wtimeout: 2000 } }
     )
     db.getSiblingDB("mydb2").bar.insertOne(
     {xyz: 0},
     { writeConcern: { w: "majority", wtimeout: 2000 } }
     )
     // Start a session.
     session = db.getMongo().startSession( { readPreference: { mode: "primary" } } );
     coll1 = session.getDatabase("mydb1").foo;
     coll2 = session.getDatabase("mydb2").bar;
     // Start a transaction
     session.startTransaction( { readConcern: { level: "local" }, writeConcern: { w: "majority" } } );
     // Operations inside the transaction
     try {
     coll1.insertOne( { abc: 1 } );
     coll2.insertOne( { xyz: 999 } );
     } catch (error) {
     // Abort transaction on error
     session.abortTransaction();
     throw error;
     }
     // Commit the transaction using write concern set at transaction start
     session.commitTransaction();
     session.endSession();
     ```
     
   
   - 会话超时 会话有默认的超时时间，默认超时时间为30分钟。服务器会在超时后自动终止未活动的会话，以释放资源。
     
    
 
#### 逻辑会话的实现细节
1. 会话ID 每个会话都有一个唯一的会话ID，该ID在会话的整个生命周期中保持不变。会话ID用于跟踪和管理会话内的操作。
   
2. 会话资源管理 服务端根据会话的活动情况动态分配资源。未使用的会话元数据会被自动清理，会话元数据清理的writeConcern是majority，这意味着如果majority个数的备机都有时延，则无法清理会话残留的元数据，即使会话结束，服务端的会话元数据也会累积，并且占用会话数量。对于长时间运行的会话，服务端会定期检查其状态，确保不会占用过多资源。
   
 
#### 使用最佳实践
1. 指定w=majority：建议客户在连接DDS实例时指定w=majority，防止主备时延大导致隐式会话累积残留，此外，如果没有以w=majority写入数据，则发生主备倒换时，未同步到备机的数据有丢失风险。
2. 显式结束会话：尽量在操作完成后显式调用endSession，以释放资源。
3. 事务内操作尽量少：在事务内执行的操作应尽量少且简洁，以减少锁定和资源占用。
 
