記事のディレクトリ
第二に、データベースレベル
2.1 db.serverStatus()
1.ロック情報の監視
rs0:PRIMARY> db.serverStatus().globalLock
{
"totalTime" : NumberLong("2651301900000"), //自上次发生lock以来的时间
"currentQueue" : { //锁等待队列信息
"total" : 0, //因为锁而产生的排队的总数
"readers" : 0, //等待读锁而产生的排队数(kQueuedReader)
"writers" : 0 //等待写锁而产生的排队数(kQueuedWriter)
},
"activeClients" : { //活跃连接数信息
"total" : 38, //当前活跃连接数
"readers" : 0, //当前执行读操作的活跃连接数(kActiveReader)
"writers" : 0 //当前执行写操作的活跃连接数(kActiveWriter)
}
}
MongoDBロック:(「+」は互換性を意味し、「-」は相互排除を意味します)
ロックモード | MODE_NONE | MODE_IS | MODE_IX | MODE_S | MODE_X |
---|---|---|---|---|---|
MODE_NONE | + | + | + | + | + |
MODE_IS | + | + | + | - | - |
MODE_IX | + | + | + | + | - |
MODE_S | + | + | - | + | - |
MODE_X | + | - | - | - | - |
MongoDBは、ロック時の階層的な管理方法です。
globalLock-> DBlock-> CollectionLock。
MongoDB Wiredtigerは、ドキュメントレベルのロック同時実行性です。読み取りと書き込みを同時に行う場合、特定のロック量は次のように実装されます。
写操作
1. globalLock (这一层只关注是读还是写,不关注具体是什么LOCK)
2. DBLock MODE_IX
3. Colleciotn MODE_IX
4. pass request to wiredtiger
读操作
1. globalLock MODE_IS (这一层只关注是读还是写,不关注具体是什么LOCK)
2. DBLock MODE_IS
3. Colleciton MODE_IS
4. pass request to wiredtiger
全体的なプロセスは次のとおりです。
1.Client发送请求至MongoDB
2.判断Client状态是kQueuedReader或kQueuedWriter
2.获取ticket(globalLock完成)
正常情况下,如果有没出现锁竞争,所有读写请求都会被pass到存储引擎层
为了限制存储引擎层并发度,可以设置ticket这个值
wiredtiger默认限制传递到引擎层面的最大读写并发数均为128
mmapv1没有ticket的限制
3.Client状态转换为kActiveReader或kActiveWriter
如果该参数长时间不为0,说明服务现在并发较大,负载较高
可以考虑SQL优化、升配来处理
4.lockBegin
加DB、Collection等层次锁
更底层的锁竞争会间接影响到globalLock
総括する:
serverStatus.globalLockまたはmongostat(qr | qw ar | awインジケーター)は、mongodglobalLockのさまざまなインジケーターを表示できます。
Wiredtigerは、エンジンレベルに渡される同時読み取りと書き込みの最大数を128に制限します(妥当な経験値、通常は調整なし)。このしきい値を超えると、キューに入れられた要求がglobalLock.currentQueue.readers / writersに反映されます。
globalLock.currentQueue.readers / writersの値が長期間0でない場合(現時点では、globalLock.activeClients.readers / writersは継続的に128に近いか等しい必要があります)、これはシステムの同時実行性が高すぎることも示します。 、または長期間、フォアグラウンドでのインデックス作成など、ミューテックスロックを占有するリクエストは、単一のリクエストの処理時間を最適化するか(たとえば、COLLSCANまたはSORTを削減するためのインデックス作成)、またはバックエンドをアップグレードすることで最適化できます。リソース(メモリ、ディスクIO容量、CPU)。
globalLock.activeClients.readers / writersは引き続きゼロ以外であり(ただし、128には到達せず、現時点ではcurrentQueueは空です)、リクエスト処理がすでに非常に遅いと思われる場合は、特定の遅いクエリを探すことも検討できます。上記でそれらを最適化するか、リソースをアップグレードします。
2.接続情報の監視
rs0: PRIMARY > db.serverStatus().connections {
"current": 5, //当前连接数
"available": 814, //剩余可以连接数
"totalCreated": NumberLong(186) //截止到现在创建连接数
}
3.メモリ情報の監視
rs0:PRIMARY> db.serverStatus().mem
{
"bits" : 64, //64位
"resident" : 245, //物理内存消耗
"virtual" : 1262, //虚拟内存消耗
"supported" : true, //支持显示额外内存信息
"mapped" : 0, //映射内存
"mappedWithJournal" : 0 //除了映射内存外还包括journal日志消耗的映射内存
}
4.エラー情報の監視
rs0: PRIMARY > db.serverStatus().asserts {
"regular": 0, //服务启动后asserts错误个数
"warning": 0, //服务启动后warning个数
"msg": 0, //服务启动后message asserts个数
"user": 22, //服务启动后user asserts格式
"rollovers": 0 //服务启动后重置次数
}
5.ネットワークトラフィックの監視
rs0:PRIMARY> db.serverStatus().network
{
"bytesIn" : NumberLong(1013083142), //网络入流量
"bytesOut" : NumberLong(1123552013), //网络处流量
"numRequests" : NumberLong(3592562) //累积请求数
}
2、db.stats()
rs0:PRIMARY> db.stats()
{
"db" : "test", //数据库名
"collections" : 5, //数据库中集合数
"objects" : 139, //数据库预估数据行
"avgObjSize" : 63.65467625899281, //平均每行数据大小,单位为bytes
"dataSize" : 8848, //当前数据库数据大小,单位为bytes
"storageSize" : 1077248, //当前数据库物理存储大小,单位为bytes
"numExtents" : 5,
"indexes" : 2,
"indexSize" : 16352, //索引空间大小,单位为bytes
"fileSize" : 67108864, //数据库预分配文件大小
"nsSizeMB" : 16,
"extentFreeList" : {
"num" : 1,
"totalSize" : 32768
},
"dataFileVersion" : {
"major" : 4,
"minor" : 22
},
"ok" : 1
}
3.現在アクティブなセッションを表示します
3.1 db.currentOp()
在会话1执行db.fsyncLock()
在会话2执行db.cc.insert({"name":"aa"})
在会话3执行db.currentOp()
> db.currentOp()
{
"inprog" : [
{
"desc" : "conn10",
"threadId" : "0x3fdf860",
"connectionId" : 10,
"opid" : 380692, //db.killOp使用的就是该opid
"active" : true, //是否活跃
"secs_running" : 4, //执行时间(秒)
"microsecs_running" : NumberLong(4603324),
"op" : "insert", //执行操作类型
"ns" : "test.cc", //执行操作数据库
"insert" : { //执行操作语句
"_id" : ObjectId("5bee323020e268b4d947a580"),
"name" : "aa"
},
"client" : "127.0.0.1:42066", //执行操作客户端
"numYields" : 0,
"locks" : { //执行操作需要持有锁
"Global" : "w"
},
"waitingForLock" : true, //是否锁等待 ?
"lockStats" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(1),
"w" : NumberLong(1)
},
"acquireWaitCount" : {
"w" : NumberLong(1)
},
"timeAcquiringMicros" : {
"w" : NumberLong(22503637)
}
}
}
}
],
"fsyncLock" : true, //是否全局锁定数据库
"info" : "use db.fsyncUnlock() to terminate the fsync write/snapshot lock"
}
注目に値するのは:
1. MongoDBシェルを切断した後、接続は閉じられますが、接続要求のスレッドは終了しません。コマンドが実行され、接続が検出されたときにスレッドが結果をクライアントに返すまで、スレッドは終了しません。閉じられます。
2. MongoDBは、killOpを送信した直後にリクエストを終了しません
接続の対応するサービススレッドがkillPendingフィールドをコードロジックに格納している場合にのみ、コードはこのパラメーターを呼び出し続けて、killPendingの状態を確認および判別します。killOpを送信した後、リクエストは次の[チェックポイント]まで実行され、現在のセッションは、killPending = 1と判断された後にのみ強制終了されます。
3.2遅いセッションを殺す
> db.killOp(380692)
{ "info" : "attempting to kill op" }
db.killOp(opid)の実現原理は次のとおりです。
各接続に対応するサービススレッドは、killPendingフィールドを格納します。killOpが送信されると、フィールドは1に設定されます。リクエストの実行中に、OperationContext :: checkForInterrupt()を継続的に呼び出して、killPendingが設定されているかどうかを確認できます。設定されると、スレッドは終了します。
リクエストのkillOpをサポートするには、リクエストの処理ロジックにcheckForInterrupt()を追加する必要があります。そうしないと、killOpが送信されても、スレッドはリクエストが完全に処理された後にのみ終了できます。