Cronet网络库(Quic连接出错篇章一)

问题

因为业务需求把所有业务的域名都搞成相同的,导致Cronet在底层连接出错的判断逻辑也跟着出错了。原因是域名相同后,假如某个业务域名所建立的连接一直出错,但是该连接的端口有1-3个的话,出错后cronet会记录内存、本地,后续有其他业务域名命中这个1-3个端口的话,就会导致一直命中跳过quic连接的逻辑。本章节主要分析quic连接出错状态后续会导致其他连接被误认为是需要跳过的。

Quic Job创建流程

  1. 要解决问题,我们首先要弄清楚整个quic job的创建流程,首先是job_controller控制所有http请求的Job创建,来到http_stream_factory_job时候,里面就根据逻辑判断来决定走h2还是h3的job,这里流程图只涉及Quic job相关,具体可以看图一。


    图一.png

Quic broken逻辑

  1. quic创建连接跳过逻辑在http_stream_factory_job_controller.cc里的GetAlternativeServiceInfoInternal函数里,在返回AlternativeServiceInfo时候会判断该域名和端口等元素组合而成的Key是否在broken的数组里,如果存在就跳过此次循环,那么就会返回一个默认值的first_alternative_service_info。源码如下图二所示


    图二.png
  2. is_broken的判断逻辑又涉及到broken_alternative_services.cc里面的数据储存了,其中有个储存broken数据的在Quic Job确定连接失败发生下面3个错误情况下,会将当前host、port记录到broken数组里。QuicStreamRequest的创建可以由图一看出在Job::DoInitConnectionImplQuic函数创建的,那么我们回去看callback函数即可。源码如下图三所示


    图三.png
  3. DoInitConnectionImplQuic的构造函数再经过delegate->onFailedOnDefaultNetwork回调给上层,即回调http_stream_factory_job_controller.cc里,可以看出其中回调后会把一个标识位置设置成true,那么我们继续跟着标识位的判断可以发现最后走到MaybeReportBrokenAlternativeService函数里,而函数里的MarkAlternativeServiceBrokenUntilDefaultNetworkChanges就会把数据记录到broken_alternative_services.cc里。

//来源于:http_stream_factory_job_controller.cc
void HttpStreamFactory::JobController::OnFailedOnDefaultNetwork(Job* job) {
  DCHECK_EQ(job->job_type(), ALTERNATIVE);
  alternative_job_failed_on_default_network_ = true;
}

//请求结束
void HttpStreamFactory::JobController::OnRequestComplete() {
  ……
  MaybeNotifyFactoryOfCompletion();
}

//主要是MarkAlternativeServiceBrokenUntilDefaultNetworkChanges,他会把host和port信息记录到broken数组里
void HttpStreamFactory::JobController::MaybeReportBrokenAlternativeService() {
  if (alternative_job_net_error_ == OK &&
      !alternative_job_failed_on_default_network_)
    return;
……

  if (alternative_job_failed_on_default_network_ &&
      alternative_job_net_error_ == OK) {
    session_->http_server_properties()
        ->MarkAlternativeServiceBrokenUntilDefaultNetworkChanges(
            alternative_service_info_.alternative_service(),
            request_info_.network_isolation_key);
    // Reset error status for Jobs after reporting brokenness.
    ResetErrorStatusForJobs();
    return;
  }
……
}


解决问题思路

因为host被业务需要改成相同的了,那我们只需要在is_broken基础上新增一个值来判断当前的host和port是否为同一条连接即可,因为只有当连接相同情况下并且失败过才要跳过quic的创建,如果不是相同的一条连接应该尝试创建quic job。(涉及业务代码的保密性我就不贴出来了)

注意: 不能重载AlternativeService的<、==、!=等符号,因为这个类很多逻辑都共用到的,如果修改后原本判断相同的处理因为新增值就判断不相同了。所以需要做的工作是在取的时候新增个&&判断来解决问题。


总结

  1. 遇到相关开发问题,要尝试理解源码设计后再去改动,不要盲目去大改,毕竟已经上线存在那么久了,没有把握情况下尽量小改解决问题。
  2. 发现Cronet开源项目做的非常棒,不是说能力上(我太菜还没能全部读懂),而是说查询代码的体验上,你点击函数还能跳转进具体函数,像ide一样了。Cronet的源码链接(翻墙)
  3. broken逻辑还涉及本地序列化和反序列化,这里涉及的代码和逻辑我会在下一个篇章分析(如果我有时间的话)。

你可能感兴趣的:(Cronet网络库(Quic连接出错篇章一))