写点什么

MongoDB 客户端怎么做负载均衡

用户头像
海明菌
关注
发布于: 4 小时前
MongoDB 客户端怎么做负载均衡

问题

在 mongodb 的社群里面有人问 mongos 连接不均


于是乎我就看了一下源码分析

更详细请查看 -》Mongodb 客户端怎么做负载均衡 - Being

先提出疑问

1、mongodb 是怎样建立连接

2、怎样选择连接节点

3、集群或分片下是怎样选择节点

分析从一个 dsn 新建链接的过程

下面是 libmongoc 源码首先根据 dsn 字符创建对象 uri 结构体


uri = mongoc_uri_new_with_error (uri_string, &error); -> 解析这个dsn的语义
处理dsn的结构 uri信息mongoc_client_new_from_uri 分两个步骤
1、mongoc_topology_new -> 看这个mongo 是单体,副本,还是分片,连接协议,寻址服务器地址的say hello 连接时间,并且加入扫描队列定时更新 mongoc_topology_scanner_new -> 调用 hello 命令 包含 所有节点的连接,最近写入,还有节点角色,一些写关注,读关注,超时时间参数等设置,形成服务列表
https://docs.mongodb.com/manual/reference/command/hello/
其中 mongoc_topology_description_add_server(使用快速排序), mongoc_topology_scanner_add(双向链表) 就是添加主机服务到扫描队列中
2、_mongoc_client_new_from_uri 根据 topology 信息,为客户端生成连接sock结构的client结构
复制代码

客户端进行链接过程

当客户端进行操作的时候,所有命令发送都会建立 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,如果写操作找主,读操作找副本 通过所有服务器筛选出能够进行访问的候选节点

通过以下算法     /* Ways to get here:    *   - secondary read    *   - secondary preferred read    *   - primary_preferred and no primary read    *   - sharded anything    * Find the nearest, then select within the window */    for (i = 0; i < data.candidates_len; i++) {      if (candidates[i] &&          (nearest == -1 || nearest > candidates[i]->round_trip_time_msec)) {         nearest = candidates[i]->round_trip_time_msec;      }   }
for (i = 0; i < data.candidates_len; i++) { if (candidates[i] && (candidates[i]->round_trip_time_msec <= nearest + local_threshold_ms)) { _mongoc_array_append_val (set, candidates[i]); } }
返回 候选服务列表后,就随机在里面找一个节点
mongoc_topology_description_suitable_servers ( &suitable_servers, optype, topology, read_pref, local_threshold_ms); if (suitable_servers.len != 0) { rand_n = _mongoc_rand_simple (&topology->rand_seed); sd = _mongoc_array_index (&suitable_servers, mongoc_server_description_t *, rand_n % suitable_servers.len); }
复制代码

大概意思是,找到响应时间最小的节点,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

用户头像

海明菌

关注

后端开发工程师 2017.10.24 加入

爱编码,爱看书,爱写作

评论

发布
暂无评论
MongoDB 客户端怎么做负载均衡