队列讲解

队列调度

 

 

1队列有调度方式:

并发调度和抢占式调度,信用机制。

2现有的并发队列调度的缺点:

最开始,postfix使用一种很简单但却很健壮的发送方法,每当尝试连接发送但失败后,会减少1个并发数,反之增加一个并发数。当然并发数不能超过配置参数maximum per-destination.当并发数降低到0时,我们认为目标主机处于死亡状态,发送终止。 
+/-1并发反馈算法的缺陷 
(1)倍数增长的并发连接数将会导致高并发问题的通道。比如,我们默认的初始化并发参数为5,那么并发连接数将会出现5-10-20的增长,这样将会使连接状况过热。 
(2)同理,连续多次的失败将会过快地降低并发数,而使目标主机被标识为“死亡”态。 
改进的并发调度方法将会有效的解决这一问题。它将并发连接控制和死亡探测分成两种手段。 它使用“less-than-1”反馈机制来提供更加渐进的并发连接适应性,同时它使用反馈滞后机制以减少并发连接率的浮动。。 
同时,区别于等待并发连接降至0来表示主机死亡的方法,目标主机将被判定为死亡在多次连接失败后,这个失败次数由配置决定。

当一定数量的发送任务顺利完成后,我们可以增长并发连接数以提高消息的发送效率(没必要连续)。我们通过正向反馈率g(N)来实现,其中N为预期的目标主机并发连接数目。每次递送使用g(N)=1的反馈机制后,并发连接将会在每次发送成功后递增,这个跟老的反馈机制相同。当使用g(N)=1/N后,并发连接将会在N次成功的连接反馈后+1。less-than-1反馈机制和取整方法很自然的提供给我们应对网络浮动的缓冲方法。当1/g(N)次正向反馈机制后,并发连接数将达到一个较高的水平。

同理,我们使用负向刺激f(N)=1/N来描述温和的并发退却机制,当并发连接反馈失败达到1/f(n)时,并发连接数将降低到较低的水平。

3小结:postfix2.5的并发反馈算法包含可以概括为 
(1)可选择的less-than-1正向反馈机制能够避免服务器过热 
(2)可选择的less-than-1负向反馈机制能够避免投递过早的放弃。 
(3)反馈延迟(feedback hysteresis)能后避免快速的网络浮动

4队列调度机制所有算法如下:

leaky bucket:通过限定邮件随指数性增长的数量,防止qmgr模块在高负载下发生用尽内存等问题。qmgr_message_active_limit  default=20000。

fairness:交替从incoming和deferred队列取信到active队列发送,公平对待新老邮件。

slow start:MDA向收件服务器的发信是并行的,初始并发数由initial_destination_concurrency参数设定,默认值为5。慢启动算法逐步的增加并行值,防止对对方服务器造成过大压力,直到对方拒收或超过default_destination_concurrency_limit(默认20)。

round borin:采用轮询算法公平调度各MDA和各域的邮件发送。

exponentialbackoff:初次投递失败的邮件被送到deferred队列,每次投递失败,双倍递增下次投递时间。

destination status cache:对于无法发送的地址,postfix维护一个列表,在一定时间内不往列表中的目的地发信,以消除没有必要的尝试发信操作。

preemptivemessage scheduling:在发信时可以选择抢占式算法,优先发送等待时间更久更容易发出的信件发送。

fairness、round borin、preemptive message scheduling策略的目的都是为了平衡。fairness策略避免deferred队列中的邮件等待太久。round borin策略优先选择有待发信件的QMGR_TRANSPORT(MDA)和QMGR_QUEEN(收信域)。preemptive message scheduling策略优先选择等待时间更久且更易发送的信件发送,以免部分收信人等待时间过长。

5:相关结构信息:

QMGR_MESSAGE:记录一封邮件的信息。

RESOLVE_REPLY:记录trivial_rewrite模块对邮件地址进行解析的结果。

QMGR_TRANSPORT:表示一类MDA。

QMGR_QUEUE:表示一个收件域。

QMGR_ENTRY:用于做实际的发信操作。

struct QMGR_QUEUE {

int     dflags;                           /* delivery requestoptions */

time_t  last_done;                            /* last deliverycompletion */

char   *name;                          /* domain name oraddress */

char   *nexthop;                      /* domain name */

int     todo_refcount;           /* queue entries (todo list) */

int     busy_refcount;           /* queue entries (busy list) */

int     window;                       /* slow open algorithm */

double  success;                       /* accumulated positivefeedback */

double  failure;                         /* accumulated negativefeedback */

double  fail_cohorts;               /* pseudo-cohort failure count */

QMGR_TRANSPORT *transport;              /*transport linkage */

QMGR_ENTRY_LIST todo;                 /*todo queue entries */

QMGR_ENTRY_LIST busy;                 /*messages on the wire */

QMGR_QUEUE_LIST peers;              /*neighbor queues */

DSN    *dsn;                            /* why unavailable*/

time_t  clog_time_to_warn;                   /* time of last warning */

int     blocker_tag;                /* tagged if blocks job list */

};

window:被初始化为QMGR_TRANSPORT的init_dest_concurrency字段值。为调度的邮件并发数,初始值默认值为5,随时间的变化而变化,根据之前的算法设定。

一个QMGR_TRANSPORT包含多个QMGR_QUEUE ,一个QMGR_QUEUE包含多个

Qmgr_entry.

QMGR_JOB 使一封信使用不同的MDA发送邮件信息,结构体中保存QMGR_TRANSPORT 的成员变量.

qmgr_job_create(message,transport);

qmgr_active_drain:从active队列发送邮件。

qmgr_active_feed:从incoming队列或deferred队列交替取信到active队列,实现了fairness策略。

qmgr_transport_select:要发信,首先选定要使用的MDA。

qmgr_transport_alloc:使用event_enable_read安排发信事件qmgr_deliver。

qmgr_message_alloc:围绕单封邮件构建内部数据结构。

qmgr_message_read:从active队列(文件系统)读取邮件内容。

qmgr_message_reslove:解析收件人地址及MDA、发信域等信息。

qmgr_message_assign:查找或创建QMGR_JOB、QMGR_PEER、QMGR_ENTRY等结构体。

一封信可能经过多个MDA去传递。所以要使用到QMGR_JOB。QMGR_TRANSPORT利用queue_byname 和 job_byname 查找相应的任务和邮件队列。

6:根据官方文档记载之间的关系:

Each transport maintains a set of queues (describing the destinations it shall talk to) and jobs (referencing the messages it shall deliver).

Each queue belongs to one transport, so each destination may be referred to by several queues, one for each transport.

Each queue maintains a list of all recipient entries (batches of message recipients) which shall be delivered to given destination (the todo list), and a list of recipient entries already being delivered by the delivery agents (the busy list).

Each transport job groups everything it takes to deliver one message via its transport. Each job represents one message within the context of the transport. The job belongs to one transport and message, so each message may have multiple jobs, one for each transport. The job groups all the peer structures, which describe the destinations the job‘s message has to be delivered to.

简单的数据结构图如下:

Qmgr 划分的模块:

qmgr_active_drain() allocates one delivery process.

/* Process allocation is asynchronous. Once the delivery

/* process is available, an attempt is made to deliver

/* a message via it. Message delivery is asynchronous, too.

/*

QMGR_TRANSPORT *qmgr_transport_select(void)

/* qmgr_transport_throttle - disable delivery process allocation */

qmgr_deliver_concurrency is a global counter that says how

/*many delivery processes are in use. This can be used, for

/*example, to control the size of the `active‘ message queue*/

Each queue corresponds to multiple peer structures. Each peer structure is like the queue structure, belonging to one transport and referencing one destination. The difference is that it lists only the recipient entries which all originate from the same message, unlike the queue structure, whose entries may originate from various messages. For messages with few recipients, there is usually just one recipient entry for each destination, resulting in one recipient entry per peer. But for large mailing list messages the recipients may need to be split to multiple recipient entries, in which case the peer structure may list many entries for single destination.

The job groups all the peer structures, which describe the destinations the job‘s message has to be delivered to.

时间: 2024-10-14 13:13:28

队列讲解的相关文章

数据结构队列实例

1 //数据结构 --队列 2 //静态队列-用数组实现 3 //静态队列通常是循环队列 4 //循环队列讲解 5 //1.静态队列为什么必须是循环队列? 6 //2.循环队列需要几个参数来确定? 7 /* 8 front 和 rear 9 1)队列初始化,font和rear的值都为零 10 2)队列非空 11 font代表的是队列的第一个元素 12 rear代表的是队列的最后一个有效元素的下一个元素 13 3)队列空 14 front和rear值 15 */ 16 //3.循环队列各个参数的含

多线程系列文章参考

并发概念汇总 http://www.letiantian.me/2015-05-27-java-concurrency-summary/ 两个并发的系统文章 http://www.cnblogs.com/dolphin0520/category/602384.html http://ju.outofmemory.cn/entry/235367 java线程池与队列讲解 http://www.oschina.net/question/565065_86540 最简单的java线程池与任务队列 ht

python就业班-淘宝-目录.txt

卷 TOSHIBA EXT 的文件夹 PATH 列表卷序列号为 AE86-8E8DF:.│ python就业班-淘宝-目录.txt│ ├─01 网络编程│ ├─01-基本概念│ │ 01-网络通信概述.flv│ │ 02-IP地址.flv│ │ 03-Linux.windows查看网卡信息.flv│ │ 04-ip地址的分类-ipv4和ipv6介绍.flv│ │ 05-(重点)端口.mp4│ │ 06-端口分类:知名端口.动态端口.flv│ │ 07-socket介绍.mp4│ │ │ ├─02

HDU -1506 Largest Rectangle in a Histogram&&51nod 1158 全是1的最大子矩阵 (单调栈)

单调栈和队列讲解:传送门 HDU -1506题意: 就是给你一些矩形的高度,让你统计由这些矩形构成的那个矩形面积最大 如上图所示,如果题目给出的全部是递增的,那么就可以用贪心来解决 从左向右依次让每一个矩形的高度当作最后的高度,来从中选取最大值就可以了 但是如果它不是递增的,中间会出现低谷,那么要还想运用贪心策略就要把之前高度大于它的全部扔掉,但是再扔掉他们之前还要判断一下以他们为最后答案的高度可不可行,这样我们就是在构造一个递增序列,可以用栈来维护它 代码: 1 #include<stdio.

JDK源码那些事儿之ConcurrentLinkedQueue

阻塞队列的实现前面已经讲解完毕,今天我们继续了解源码中非阻塞队列的实现,接下来就看一看ConcurrentLinkedQueue非阻塞队列是怎么完成操作的 前言 JDK版本号:1.8.0_171 ConcurrentLinkedQueue是一个基于链表实现的无界的线程安全的FIFO非阻塞队列.最大的不同之处在于非阻塞特性,不会进行阻塞等待直接返回操作结果.其中head和tail的更新类似之前在LinkedTransferQueue中讲解的slack(松弛度)机制,只有在slack阈值大于等于2时

JDK源码那些事儿之ConcurrentLinkedDeque

非阻塞队列ConcurrentLinkedQueue我们已经了解过了,既然是Queue,那么是否有其双端队列实现呢?答案是肯定的,今天就继续说一说非阻塞双端队列实现ConcurrentLinkedDeque 前言 JDK版本号:1.8.0_171 ConcurrentLinkedDeque是一个基于链表实现的无界的线程安全的同时支持FIFO.LIFO非阻塞双端队列.操作上可类比ConcurrentLinkedQueue,利用CAS进行无锁操作,同时通过松弛度阈值设置来减少CAS操作,在理解这个类

39 _ 队列5 _ 循环队列需要几个参数来确定 及其含义的讲解.swf

上面讲解都是循环队列,如果是链表实现的话就很简单,队列只有循环队列才比较复杂 此时队列中只存储一个有效元素3,当在删除一个元素的时候,队列为空,pFont向上移动,pFont等于pRear,但是此时pFont的值不为null 1.下面分析下如何向队列中添加元素 我们添加元素的时候只有在pRear的地方添加,pRear向上移动 上面这种情况,pRear已经指向了数组的最尾部分,此时添加数据的时候,pRear不能继续向上加1,执行6的位置,这个时候会出现内存溢出,pRear要执行到数组的0位置第一个

队列的知识讲解与基本实现(数据结构)

引言 中午在食堂打饭,真是一个令人头疼的事情,去食堂的路上也总是步伐匆匆,为什么啊,这还用说,迟一点去,你就会知道什么叫做人山人海了,在食堂排队的时候,相比较学生来说,打饭阿姨毕竟是少数,在每个窗口都有人的时候,不免我们就得等待,直到前面的一个学生打完饭离开,后面排队的人才可以继续向前走,直到轮到自己,别提多费劲了,但是秩序和规则却是我们每个人都应该遵守的,也只能抱怨自己来的迟了 这种 "先进先出" 的例子就是我们所讲的基本数据结构之一 "队列" 例子补充:用电脑的

java自带线程池和队列详细讲解(转)

Java线程池使用说明 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的问题提供了非常大的帮助. 二:线程池 线程池的作用: 线程池作用就是限制系统中执行线程的数量.     根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果:少了浪