在 OkHttp 中,RouteDatabase 是一个内部组件,用于管理和记录连接路由(Route)的历史信息。它在连接复用和故障恢复中扮演着重要角色,帮助 OkHttp 在遇到网络问题时快速切换到可用的路由。
1. 什么是 Route 和 RouteDatabase
Route
-
定义:
Route表示一个具体的网络连接路径,包括目标地址、代理、Socket 配置等信息。 -
组成:
Address:目标服务器的地址(主机名、端口号、SSL 配置等)。Proxy:使用的代理服务器(如果有)。InetSocketAddress:实际连接的目标 IP 地址和端口号。
RouteDatabase
-
定义:
RouteDatabase是一个内部数据结构,用于记录和管理Route的成功或失败状态。 -
作用:
- 跟踪路由的使用情况。
- 标记不可用或失败的路由。
- 提供备选路由,支持故障切换。
2. RouteDatabase 的核心作用
-
路由选择优化
- 通过记录成功和失败的路由信息,帮助 OkHttp 优先选择已知的成功路由。
-
故障恢复
- 当某个路由失败时,
RouteDatabase提供备选路由,避免多次尝试失败的路径。
- 当某个路由失败时,
-
连接重试
- 在网络不稳定或服务器不可达时,允许快速切换到其他路由,提高连接成功率。
3. RouteDatabase 的工作机制
1. 记录失败路由
- 当连接某个路由失败时,
RouteDatabase会将该路由标记为失败。 - 方法:
RouteDatabase.failed(route)。
2. 检查路由是否失败
- 在尝试连接之前,检查该路由是否被标记为失败。
- 方法:
RouteDatabase.shouldPostpone(route)返回true表示需要跳过该路由。
3. 提供备选路由
- 如果一个路由失败,OkHttp 会从
RouteSelector获取其他可用的路由,并避免选择已知的失败路由。
4. RouteDatabase 的主要方法
以下是 RouteDatabase 的核心方法及其作用:
1. failed(route: Route)
- 作用:将某个路由标记为失败。
- 参数:
route,表示需要标记的失败路由。
2. connected(route: Route)
- 作用:当某个路由成功连接时,从失败列表中移除该路由。
- 参数:
route,表示成功的路由。
3. shouldPostpone(route: Route): Boolean
- 作用:检查某个路由是否需要推迟尝试。
- 返回值:
true表示该路由已被标记为失败,应跳过。
4. failedRoutesCount(): Int
- 作用:返回当前标记为失败的路由数量,用于调试或统计。
5. RouteDatabase 在 OkHttp 中的作用
1. 提升路由选择效率
- OkHttp 使用
RouteSelector提供候选路由列表,通过RouteDatabase过滤掉失败的路由,优先选择成功的路由。
2. 故障恢复
- 在网络不稳定或路由配置错误时,避免重复尝试不可用的路由,提升连接成功率。
3. 多路由支持
- 支持一个目标服务器有多个路由的场景,例如通过不同的代理或 IP 地址连接同一主机。
4. 配合连接池
RouteDatabase与连接池(ConnectionPool)协作,确保复用连接时选择有效的路由。
6. 工作流程示例
以下是 RouteDatabase 在 OkHttp 工作中的典型流程:
-
初始化连接:
- OkHttp 获取目标地址的所有候选路由。
-
过滤失败路由:
- 使用
RouteDatabase跳过已知失败的路由。
- 使用
-
尝试连接:
- 如果连接成功,调用
RouteDatabase.connected(route)。 - 如果连接失败,调用
RouteDatabase.failed(route)。
- 如果连接成功,调用
-
故障切换:
- 若当前路由失败,从备选路由中获取新的路由并尝试。
7. 代码示例
以下是一个模拟 RouteDatabase 使用的伪代码:
val routeDatabase = RouteDatabase()
// 模拟多个路由
val route1 = Route(address, proxy, socketAddress)
val route2 = Route(address, Proxy.NO_PROXY, socketAddress)
// 标记 route1 失败
routeDatabase.failed(route1)
// 检查是否需要跳过 route1
if (routeDatabase.shouldPostpone(route1)) {
println("Route1 is marked as failed, skipping...")
}
// 连接成功后移除失败标记
routeDatabase.connected(route1)
8. RouteDatabase 的典型使用场景
1. 多路由切换
- 在通过多个代理或 DNS 解析结果连接同一服务器时,
RouteDatabase可以管理路由的成功与失败状态。
2. 网络不稳定场景
- 当某些路由因网络原因无法访问时,快速切换到其他路由。
3. 高可用系统
- 在需要高可用性和快速故障恢复的场景下,例如连接多个数据中心或 CDN。