谈一谈TimeWheel算法删除空闲连接

5 篇文章 0 订阅

Time Wheel的具体算法原理,可以参考网络上的资料,本文不探讨具体的原理。

在多数的网络库中,要删除空闲的连接,都会使用Time Wheel 时间轮算法。

在不做任何优化的情况下,如果所有的TCP连接对象都存储在$connection_list数组中,那么要删除空闲连接,常规的伪代码大致如下

<?php

Class Connection {
   private $fd;

   //最近一次收到消息的时间戳
   public $lastRecvTime; //每次连接onMessage时,都更新该字段
   public $refCount;
}

$connection_list = [];


// 此处将所有的在线连接都加入$connection_list数组

//不做任何优化,删除空闲连接伪代码,算法复杂度 O(N), N=在线连接数

foreach($connection_list as $conn) {
   if($conn->lastRecvTime < time() - 60 ) {
      //此处认为允许连接的idle_time为60秒
      $conn->close();
   }
}

上述代码,如果单机在线连接有几万的话,假设定时器每秒跑一次检测idle connection,那么每秒就有上万次的foreach,对静态语言来说,这点cpu占用可以忽略,但是如果用php之类的开发网络库,那么当在线连接飙升时,因为检测空闲连接,而损失的cpu就不能忽略不计了。

在swoole最新版本中,使用的是直接for循环遍历所有连接,检测idle connection的方法。

定时轮的每格,本文都称为bucket,假设定时轮有60个刻度,那么就有60个bucket,每个bucket可以放N个连接对象。

那么用时间轮算法,就一定会高效吗?假设大部分的连接,每秒都会收到消息,那么触发onMessage回调里就需要把当前连接从定时轮的旧bucket删除,并且移动到最新的bucket中,会存在2内存读,2次内存写,那所有的连接加起来,就有4N次内存IO,那反而更慢了(在swoole的源码中,旧版本就是这样的,看图)

所以在连接收到数据时,将当前连接移动到最新的bucket时,要尽量减少内存IO操作。在c++中可以使用shared_ptr,当连接收到数据时,只需要ref_count++就可以了,当定时轮跑到要过期删除的那个bucket时,只要连接的refCount==0 就直接删除,否则refCount--。这样就可以充分利用定时轮带来的减少for循环的次数。而不会增加太多的内存IO。

 

下面贴一下引用计数大概思路,具体实现下回分解

<?php
class Connection
{
    public $fd;
    public $lastRecvTime;

    public $refCount = 0;

    public function __construct($fd, $t)
    {
        $this->fd = $fd;
        $this->lastRecvTime = $t;
    }

    public function getFd()
    {
        return (int)$this->fd;
    }
}

$connection_list = [];
for ($i = 0; $i < 5; $i++) {
    $conn = new Connection($i + 1, time());
    $connection_list[$conn->getFd()] = $conn;

}


$arr1 = [];

$arr1[] = &$connection_list[1];
$arr1[] = &$connection_list[3];

foreach ($arr1 as &$v) {
    $v->refCount += 10;
}

print_r($connection_list);

 

综上所述,如果大部分连接的收发消息的频率很高的话,直接使用for循环遍历所有连接更高效,因为使用TimeWheel,反而增加了内存IO次数,用增加内存IO来减少cpu for循环的次数,得不偿失。

反之,如果大部分连接都是空闲的,那可以考虑TimeWheel,增加部分的内存IO来减少大量的cpu for循环次数. 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值