MongoDB 客户端怎么做负载均衡
问题
在 mongodb 的社群里面有人问 mongos 连接不均
于是乎我就看了一下源码分析下
更详细请查看 -》Mongodb 客户端怎么做负载均衡 - Being
先提出疑问
1、mongodb 是怎样建立连接
2、怎样选择连接节点
3、集群或分片下是怎样选择节点
分析从一个 dsn 新建链接的过程
下面是 libmongoc 源码首先根据 dsn 字符创建对象 uri 结构体
客户端进行链接过程
当客户端进行操作的时候,所有命令发送都会建立 session,源码部分位 _prime 函数 每个操作都会使用这个建立链接_prime->_mongoc_cursor_run_command->mongoc_client_start_session->_mongoc_topology_pop_server_session -> 找可用服务器地址 形成 client->client_sessions = session + ss 结构,所有建立链接的回话都会存放 client_sessions 通过 b tree 方式进行搜索避免冲突选择节点 mongoc_topology_description_suitable_servers 函数 会根据 服务的架构类型进行筛选 如单体直接返回,副本找主,分片找 mongos,如果写操作找主,读操作找副本 通过所有服务器筛选出能够进行访问的候选节点
大概意思是,找到响应时间最小的节点,local_threshold_ms 意思默认超时时间
问题是 round_trip_time_msec 时间是怎样来的?
_server_monitor_update_topology_description 通过这个数据 也就是通过 hello 命令 更新节点的 round_trip_time_msec 同时把超时的节点剔除
这个 mongodb 开启了一个线程进行 mongoc_client_pool_new 创建线程池 给 mongoc_client_pool_pop 调用 ->_start_scanner_if_needed->_mongoc_topology_background_monitoring_start->_mongoc_topology_background_monitoring_reconcile->_background_monitor_reconcile_server_monitor -> mongoc_server_monitor_run_as_rtt
总结
客户端选择响应节点处理过程根据 say hello 的命令得到所有节点的信息,进行分门别类,形成【拓扑图】 如果是 副本,在 dsn 里面有设置偏向读副本则读副本,如果是写指令则进行 如果是分片,则会使用 mongos,里面就会进行,根据 round_trip_time_msec 时间也就是响应时间在阀值范围内,形成的数组里面随机挑选一个进行响应
结论:总结上面的问题是很大可能是由于其它节点响应时间不稳定导致不平均,在候选数组里面,组合位 【1,2】,【1】,【1】的情况比较多 架构为分片结构,可能导致上面不均
ps:也看过官网的 java-drive 都是能够使用响应时间在阀值范围的节点集合随机挑选可用节点
参考资料
mongodb+srv 如果连接地址是域名,会根据 DNS SRV 记录进行解析 ipTXT 记录能够把连接上的参数都设置在 TXT 记录上,然后通过 DNS 信息获取进行组装https://docs.mongodb.com/manual/reference/connection-string/换句话说就是 DNS 负载均衡,做服务发现 DNS SRV 是 DNS 记录中一种,用来指定服务地址。与常见的 A 记录、cname 不同的是,SRV 中除了记录服务器的地址,还记录了服务的端口,并且可以设置每个服务地址的优先级和权重。访问服务的时候,本地的 DNS resolver 从 DNS 服务器查询到一个地址列表,根据优先级和权重,从中选取一个地址作为本次请求的目标地址。https://www.lijiaocn.com/%E6%8A%80%E5%B7%A7/2017/03/06/dns-srv.html
/* * Set topology type from URI: * + if directConnection=true * - whether or not we have a replicaSet name, initialize to SINGLE * (directConnect with SRV or multiple hosts triggers a URI parse error) * + if directConnection=false * - if we've got a replicaSet name, initialize to RS_NO_PRIMARY * - otherwise, initialize to UNKNOWN * + if directConnection was not specified in the URI (old behavior) * - if we've got a replicaSet name, initialize to RS_NO_PRIMARY * - otherwise, if the seed list has a single host, initialize to SINGLE * - everything else gets initialized to UNKNOWN */
session id 算法_mongoc_server_session_uuid https://tools.ietf.org/html/rfc4122#page-14随机的帖子:https://zhuanlan.zhihu.com/p/64538762mongos 的选择 是通过客户端进行,其中这个算法是通过公共库其算法为https://docs.mongodb.com/manual/core/read-preference-mechanics/
更详细请查看 -》Mongodb 客户端怎么做负载均衡 - Being
评论