非随机加权分布

时间:2009-11-20 14:49:00

标签: c# algorithm

我目前有一个系统,服务器告诉所有客户端应用程序何时在服务器配置的时间窗口(比如客户端时间12到6点)之间连接到服务器。

当前算法按时间窗口中的秒数执行客户端的10位数ID(相当分布)的mod,并为每个客户端连接到服务器提供相当均匀分布的可预测时间。现在的问题是,客户端在不同的时区不成比例,并且某些时区对于给定的窗口重叠,因此净效应是负载不均匀地分布在服务器上。我想要的是设计一种算法,我可以使用我们当前为每个时区拥有的一定比例的客户端进行配置,并让它在窗口之间分配客户端的下一个连接时间,从而以一种方式在服务器上产生均匀负载这是可预测的(非随机的)。

这是一个简单的图形表示:

                            12AM 1AM 2AM 3AM 4AM 5AM 6AM GMT
GMT -4  40% of the clients  ||||||||||||||||||||||||||||||            
GMT -5  10% of the clients       ||||||||||||||||||||||||||||||        
GMT -6  20% of the clients           ||||||||||||||||||||||||||||||    
GMT -7  30% of the clients               ||||||||||||||||||||||||||||||

5 个答案:

答案 0 :(得分:5)

将问题分为两部分:(1)确定您希望每组客户拥有的分布; (2)确定性地分配适合该分布的重新连接时间。

对于问题(1),考虑二维数字数组,非常类似于您绘制的图表:每行代表一个时区,每列代表一个相等的时间段(也许是一小时)天。您必须解决的问题是用数字填充网格

  • 每行的总数是该时区的客户端数量;
  • 对于每一行,该时区重新连接窗口之外的所有数字都为零;
  • 列的总和不超过某个预定的最大值(并且尽可能均衡)。

这类问题有很多解决方案。您可以通过模拟找到一个而无需进行任何硬数学计算。编写一个填充网格的程序,以便每个时区的客户端均匀分布(即,您现在分发它们的方式),然后重复地将客户端从拥挤的时间水平移动到不那么拥挤的客户端。

对于问题(2),您需要一个采用十位数ID和所需分布的函数(即上面问题1中矩阵的一行),并确定性地产生重新连接时间。这可以通过线性插值轻松完成。假设所需的分布是:

12:00    1:00   2:00   3:00   4:00   5:00   6:00 ...
  +------+------+------+------+------+------+----
  |    0 |    0 |  100 |   70 |   30 |    0 |   ...
  +------+------+------+------+------+------+----

首先找到整行的总和,然后将数字缩放到ID范围。也就是说,除以总和并乘以10 10

12:00    1:00   2:00        3:00       4:00        5:00   6:00 ...
  +------+------+-----------+-----------+-----------+------+----
  |    0 |   0  | 500000000 | 350000000 | 150000000 |    0 |   ...
  +------+------+-----------+-----------+-----------+------+----

现在让x =十位数ID,并从左到右读取行。在每个框中,从x中减去该框中的值。继续前进,直到框中的数字大于x中的数字。返回时间

(start time for this box) + (duration of this box) * x / (number in box)

请注意,一旦计算出问题(1)的解决方案,重新连接时间将是确定性的,直到下次重新计算矩阵时。然后每个人的重新连接时间会稍微改变 - 但不会太多,除非矩阵发生显着变化。

答案 1 :(得分:3)

除了ID之外,您还可以考虑用户的时区。

使用它的一个示例解决方案如下:

有24个时区。计算每个时区的相对负载。您可以通过将每个时区的客户端总数与静态数据相加来实现此目的。现在你有“加权时区”。每个时区将获得与其重量成比例的时间份额。

例如,如果您有以下数据(为简单起见,我们假设只有三个时区):

Time Zone | Clients num
------------------------
    0     |     20
    1     |     30
    2     |     10

然后你将你的时间间隔大小除以60,并给每个时区分配时间:第一个时区将获得(20/60 * #time),第二个时区将获得以下(30 / 60 * #time)等。

一旦您拥有较小的时间范围,您可以根据您之前的功能(例如mod)告诉每个客户其时间,根据您为其特定时区计算的内容使用较小的时间间隔。

注意:

  1. 显然,对于流量非常低的时区,您需要一些最小客户端num值,但这很简单 - 您只需编辑原始表。
  2. 这是“时间划分”的一个示例,您可以根据需要修改此示例,例如,您可以为多个时区设置相互时间范围。
  3. 编辑:

    根据您添加到问题中的示例,您可以通过以下方式应用此方法:

    如果我理解正确,您有10个小时的服务器处于活动状态,并且您希望每个小时的负载大致相等。含义:在这几个小时中,您希望10%的客户端访问服务器。 使用上面解释的想法,可以非均匀地划分用户,使得对于每个时区,存在“更多概率”的小时,以及具有“更少概率”的小时。在您的示例中,在GMT-4组中,10%/ 40%的客户端将在第一个小时访问服务器:格林尼治标准时间上午12点至凌晨1点。可以计算每个时区的负载,以便每小时服务器的总负载为10%。有很多方法可以做到这一点 - 贪婪的方法会做。 一旦你有这个,你知道每个时区的权重,并且应该更清楚如何使用上述时间共享方法。

答案 2 :(得分:1)

我会为您正在查看的每个时区定义一个帮助程序类:

class Timezone
{
  DateTime start;
  int hourlyWeights[6]; //assuming you have 6 hour long timeslot for every timezone

  DateTime GetStartTime(long clientId)
  {
    long allTicks = 3600*sum(hourlyWeights);
    long clientTicks = clientId%allTicks;
    int i = 0;
    while(clientTicks>hourlyWeights[i])
    {
      clientTicks -= hourlyWeights[i]*3600;
      i++;
    }
    long seconds = clientTicks/hourlyWeights[i];
    return start.AddHours(i).AddSeconds(seconds);
  }
}

现在,您可以使用方法GetStartTime从此时区获取客户端的开始时间。这里的想法是我们有这个hourlyWeights表,其中包含您希望在给定时区获得的分布,例如: [40,20,0,0,0,0]意味着这些客户端将仅在前2个小时内提供服务,并且我们希望在第一个小时内提供两倍的客户端。注意:我假设id在给定时区的客户端之间均匀分布。

棘手的一点是创建这些类。如果你有相当稳定的客户结构,那么你可以手动找出这些发行版并将它们放在配置文件中。如果它经常变化,请告诉我,我会发布一些代码来动态计算出来。

答案 3 :(得分:0)

对于简单的事情,这是怎么回事:

  • 如果服务器上的负载正常,请向客户端发送您上次发送的相同秒数。

  • 如果服务器上的负载过高,请在时间窗口中向客户端发送一些其他随机数。

过了几天,事情应该自行解决。

(这假设您有一些方法来衡量您尝试优化的数量,这似乎并不太合理。)

答案 4 :(得分:0)

为什么不在服务器上以GMT格式生成重新连接窗口时间并在将时间发送到客户端之前转换为客户端本地时间?