GPDB-内核特性-UDPIFC超时重传

简介: GPDB-内核特性-UDPIFC超时重传

GPDB-内核特性-UDPIFC超时重传


GreenPlum默认使用UDP协议进行数据传输。发生网络拥塞时,实现了超时重传以解决拥塞。


1、unack_queue_ring队列


超时重传的基础数据结构是unack_queue_ring队列。如图所示:

1)currentTime用来标记checkExpiration位于哪个时间周期。发送数据包时回更新该值:

sendBuffers第一次发送时,unack_queue_ring.currentTime更新为发送的时间(会调整到TIMER_SPAN周期内)

checkExpiration检查超时:now为调用该函数时时间。距离上次checkExpiration检测超时时间超过TIMER_CHECKING_PERIOD(gp_interconnect_timer_checking_period,默认20ms)才会再次进入checkExpiration,并更新为检查周期的起使时间:从checkExpiration函数中可知,进入checkExpiration时,距上次已经超过了5ms,则判定超时了,需要进行重发:

handleAckForDisorderPkt调用putIntoUnackQueueRing可能会更新currentTime值:

#define TIMER_SPAN (Gp_interconnect_timer_period * 1000ULL) //5ms

UDP interconnect timer周期,默认5ms

2)idx:slots的下标。currentTime对应的槽位。

3)numOutStanding:unack_queue_ring中未处理包的个数

4)numSharedOutStanding:拥塞窗口中使用共享带宽的未处理包的个数

5)ICBufferList slots[UNACK_QUEUE_RING_SLOTS_NUM]:slots数组,大小2000。每个槽位都是一个链表,表示一个时间段内的所有ICBuffer包


2、超时重传机制


1)执行器启动时初始化lastExpirationCheckTime时间,可以认为最初是ExecutorStart的时间戳

2)SendChunkUDPIFC函数发送数据包。

1)首先调用sendBuffers函数将发送队列conn->sndQueue中的所有ICBuffer数据包都发送。由于向该队列放的时候是向队列尾放,所以从队列头开始发送,先发送最老的包。

2)从发送队列sndQueue中pop出一个ICBuffer,并放到未接收ack的队列unackQueue中。同样向队列尾放。

3)会根据此时的时间戳方将ICBuffer放到unack_queue_ring中,最后发送走。将ICBuffer放到unack_queue_ring的操作见第3)步。

4)判断此时距离上次超时检测是否超过50ms。

5)超过50mspollAcks->poll超时时间是0,不阻塞立即返回。若有事件,则调用handleAcks处理接收的ack,否则直接调用checkExceptions进行超时检测

6)未超过50ms:通过computeTimeout计算出超时时间,和ICBuffer的重发次数有关。

  • unackQueue队列为空,即发送的包都收到ack了:timeout为20ms
  • unackQueue队列头中的ICBuffer(最老的包)没有重发过,并且没有因无可用ICBuffer而checkExceptions检测过:timeout为0ms
  • 其他情况超时时间为20ms
static inline int
computeTimeout(MotionConn *conn, int retry)
{
  if (icBufferListLength(&conn->unackQueue) == 0)
    return TIMER_CHECKING_PERIOD;//gp_interconnect_timer_checking_period:20ms
  ICBufferLink *bufLink = icBufferListFirst(&conn->unackQueue);
  ICBuffer   *buf = GET_ICBUFFER_FROM_PRIMARY(bufLink);
  if (buf->nRetry == 0 && retry == 0)
    return 0;
  if (Gp_interconnect_fc_method == INTERCONNECT_FC_METHOD_LOSS)
    return TIMER_CHECKING_PERIOD;//20ms
  /* for capacity based flow control */
  return TIMEOUT(buf->nRetry);
}

3)通过PutIntoUnackQueueRing将ICBuffer放到unack_queue_ring.slogs[]中,需要先计算下超时时间expTime

    computeExpirationPeriod(curBuf->conn, curBuf->nRetry)://包重发的次数
      uint32  factor = (retry <= 12 ? retry : 12);//factor次数不能超过12次
      return Max(MIN_EXPIRATION_PERIOD, Min(MAX_EXPIRATION_PERIOD, (conn->rtt + (conn->dev << 2)) << (factor)))

    其中:

    #define MIN_EXPIRATION_PERIOD (Gp_interconnect_min_rto * 1000)/* 默认: 20ms */

    #define MAX_EXPIRATION_PERIOD (1000 * 1000) /* 1s */

    conn->rtt:表示往返时延

    conn->dev:表示偏差

    expTime超时时间随着重发次数的增加会变大,但最小为20ms,最大不能超过1s

    然后,看下slots[]使用机制:

      #define UNACK_QUEUE_RING_LENGTH (UNACK_QUEUE_RING_SLOTS_NUM * TIMER_SPAN)
      static void
      putIntoUnackQueueRing(UnackQueueRing *uqr, ICBuffer *buf, uint64 expTime, uint64 now)
      {
        if (uqr->currentTime == 0)//ExecutorStart执行,第一次发送数据包
          uqr->currentTime = now - (now % TIMER_SPAN);
        diff = now + expTime - uqr->currentTime;//现在+超时时间后,位于哪个超时段slots[]
        if (diff >= UNACK_QUEUE_RING_LENGTH)
          diff = UNACK_QUEUE_RING_LENGTH - 1;
        else if (diff < TIMER_SPAN)
          diff = TIMER_SPAN;//[5ms,10s)
        idx = (uqr->idx + diff / TIMER_SPAN) % UNACK_QUEUE_RING_SLOTS_NUM;
        buf->unackQueueRingSlot = idx;//2000ms内,每5ms一个slot
        icBufferListAppend(&unack_queue_ring.slots[idx], buf);
      }

      4)每隔20ms进行一次超时检测。超时检测的当前时间之前的还未收到ack的ICBuffer都需要重发。从最开始的时间段slots[unack_queue_ring.idx](对应unack_queue_ring.currentTime时间段)开始,每隔5ms看下是否超过现在时间,若没有超过,即表示距离上次检测开始:发送的包在超时时间内还没收到ack(因为会加上超时时间后再定位在哪个slots[]中),这时就需要重发了(即语义:超过超时时间还未收到ack,重发)。那么最近刚放进来的包,会不会又立即重发呢?当然不会,因为最近刚放进来的包,也是加了它的超时时间再定位到slots[]的,若在当前now时间内,则表示超过超时时间还未收到ack,若不再则不会重发。


      3、总结

      • 当发送一个包时,会计算一个超时时间expTime,该超时时间至少20ms,不超过1s,然后now-currentTime+expTime定位到超时时间段的slots[]数组中,如图所示,放到队列尾部。
      • 当超时检测时间now1时,将now1所在slots[now1]之前以知道currentTime的全部重发,而now时间发送过的,因为在now1之后,则不重发。
      • 当超时检测时间now2时,now发送的就需要重发了。

      这样,至少20ms内没有接收到ack的都需要重发。

      相关实践学习
      深入解析Docker容器化技术
      Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
      目录
      相关文章
      |
      SQL 分布式计算 调度
      Spark入门(一篇就够了)(三)
      Spark入门(一篇就够了)(三)
      839 0
      |
      10月前
      |
      SQL 人工智能 关系型数据库
      PolarDB-PG AI最佳实践 2 :PolarDB AI X EAS实现自定义库内模型推理最佳实践
      PolarDB通过POLAR_AI插件支持使用SQL调用AI/ML模型,无需专业AI知识或额外部署环境。结合阿里云EAS在线模型服务,可轻松部署自定义模型,在SQL中实现如文本翻译等功能。
      |
      10月前
      |
      人工智能 关系型数据库 分布式数据库
      PolarDB-PG AI最佳实践3 :PolarDB AI多模态相似性搜索最佳实践
      本文介绍了如何利用PolarDB结合多模态大模型(如CLIP)实现数据库内的多模态数据分析和查询。通过POLAR_AI插件,可以直接在数据库中调用AI模型服务,无需移动数据或额外的工具,简化了多模态数据的处理流程。具体应用场景包括图像识别与分类、图像到文本检索和基于文本的图像检索。文章详细说明了技术实现、配置建议、实战步骤及多模态检索示例,展示了如何在PolarDB中创建模型、生成embedding并进行相似性检索
      |
      11月前
      |
      SQL 人工智能 自然语言处理
      PolarDB-PG AI最佳实践 1:基础能力实践
      Polar_AI 是 PolarDB 数据库的 AI 扩展,集成了先进的人工智能模型和算法,使数据库能够执行机器学习和自然语言处理任务。它支持 PostgreSQL 及 Oracle 兼容版本,通过标准 SQL 轻松调用 AI 模型,具备简单易用、灵活可定制、无缝数据融合、数据安全和高性能等优势。用户可以通过 SQL 快速实现文本转向量、情感分类等功能,并能自定义扩展 AI 模型。
      |
      运维 监控 安全
      WAN 革命:SD-WAN 与传统 WAN 对比
      【7月更文挑战第13天】
      1085 1
      WAN 革命:SD-WAN 与传统 WAN 对比
      |
      网络安全 Docker 容器
      VScode远程服务器之远程 远程容器 进行开发(五)
      VScode远程服务器之远程 远程容器 进行开发(五)
      421 1
      |
      消息中间件 缓存 算法
      分布式系列第一弹:分布式一致性!
      分布式系列第一弹:分布式一致性!
      320 0
      |
      Oracle 关系型数据库 MySQL
      一文了解PostgreSQL MVCC机制
      一文了解PostgreSQL MVCC机制
      881 0
      |
      开发工具 开发者 git
      2023 Visual Studio Code 插件推荐:18 个提高开发效率的常用插件
      Visual Studio Code (简称VSCode) 是一款强大的开源代码编辑器,它拥有众多功能强大的扩展插件,使得开发者可以根据自己的需求来定制编辑器的功能和外观。在本文中,我们将分享一些非常实用的 VSCode 插件,这些插件将提高您的开发效率,使编码变得更加愉快。
      882 0
      |
      网络协议 数据挖掘 关系型数据库
      GPDB-内核特性-UDP流量控制
      Greenplum UDP流量控制
      360 0