解读公平队列调度

本文说明

研究网络的本质就是研究QoS,本文在研究过程中,惊奇的发现2000年左右研究的热点问题--公平调度问题,网上可见的中文资源有限。
这对很多刚入行的人时十分痛苦的(因为当年我就是这么痛苦hhhh,我在知网上能够查到的资料真的十分有限)。于是便有了这篇文献,
并且再次基础上,我将逐步整理那些年所研究的QoS理论体系。所以,将本文放置于“网络演算”文章集中了。

参考文献

QoS队列调度算法
Queuing and Scheduling
网络流量调度的艺术:权重公平排队算法(WFQ)揭秘,全面解析
加权平均队列(WFQ-Weight Fair Queue)算法
WFQ加权公平队列(每个队列的计算原则与权重比关系)加权效果后转发取证
目前最全的QoS调度算法及其优缺点

QoS原理

1Queuing

1.1Queuing和Scheduling的区别

Queuing:考虑的是数据包如何进入、何时进入是否丢弃的问题;
Scheduling:考虑的是数据包什么时候发送的问题;

几种应用:
	如果您希望将任何未使用的容量分配给非空闲用户,公平排队是您的首选工具,尽管在某些情况下,它可能会从ISP的合作中受益。如果用户更像是只接收他们付费的带宽的客户,那么即使某些带宽因此未使用,您也可能希望强制执行扁平上限;令牌桶过滤将是可行的方法。
如果带宽分配不仅按部门(或客户),而且按工作组(或特定于客户的子类别),则分层排队提供了必要的控制。

1.2基本概念

1.2.1inbound与outbound

在这里插入图片描述

1.2.2class、classful以及classifier

本文中的queuing discipline指的是入队、出队策略。每个queuing discipline可能服务多个input streams。本文称input stream为一个class(或者称为subqueues)。称可以处理多class的queuing discipline为classful(可分类的)。
当我们将一个数据包使用一个queuing discipline服务时,我们需要首先调用classifier去用以决定当前数据包所属的input class。(如果queuing discipline没有服务多class的能力的话,要么不存在classifier,要么所有的数据包都映射到同一input class)。

1.2.3work-conserving与non-work-conserving

FIFO and priority queuing are both work-conserving, meaning that the associated outbound interface is not idle unless the queue is empty.
A non-work-conserving queuing discipline might, for example, artificially delay some packets in order to enforce an administratively imposed bandwidth cap. Non-work-conserving queuing disciplines are often called traffic shapers;

1.2.4分组、包、帧、packet

混用这三个名词了。

1.3优先级队列

根据某个数据包属性将数据包放入适当的子队列中,该属性可能是显式优先级标签,也可能是数据包的目的套接字。每当出站链路空闲并且路由器能够发送下一个数据包时,它总是首先查找优先级较高的队列;如果它不是空的,那么一个数据包就会从那里出队。只有当优先级较高的队列为空时,才为优先级较低的队列提供服务。

请注意,优先级排队是非优先的:如果高优先级数据包到达,而低优先级数据包正在发送,则后者不会被中断。只有当低优先级分组完成传输时,路由器才会再次检查其高优先级子队列。

1.4公平队列

公平队列为每个输入类维护一个单独的逻辑FIFO子队列;我们将这些称为每类子队列。类的划分可以是细粒度的,例如每个TCP连接的单独类,也可以是粗粒度的,例如每一个到达接口的单独类或每一个指定的内部子网的单独类。

简单的公平队列:假设包长均相同
假设所有数据包大小相同;这使得公平排队更容易可视化。在这种(特殊)情况下,路由器只是以循环方式为每个类别的队列提供服务,依次从每个类的队列发送一个数据包。如果每某个类队列是空的,那么它就会被跳过。如果每个类的队列总是非空的,这类似于时分复用。然而,与时分复用不同的是,如果类队列中的一个队列变空,则它不再消耗任何出站带宽。回想所有数据包都是相同大小的,然后在每个类的队列中平均分配总带宽;如果有K个这样的队列,每个队列将获得1/K的输出。

实际公平队列:假设包长不相同
对于可变大小的数据包,有两种广泛的公平排队方法。较新的方法只关注与分配的带宽分数一致的长期带宽保证,如23.5.5Deficit Round Robin和23.5.6Stochastic Fair Queuing。最初的方法23.5.3Bit-by-bit Round Robin和23.5.4 GPS模型提供了相同的带宽保证,但它们也提供了短期延迟保证:每次我们选择下一个要发送的数据包时,我们都会选择最“有资格”的数据包作为下一个数据包,其中数据包的“资格”随着数据包大小的变大而减少,或者如果该流近期发送了数据包,也会导致该留的“资格”值变小。
Specifically, packet-transmission choices are made according to the calculated “virtual finishing time”, 23.5.2 Virtual Finishing Times. We will sometimes refer to this original approach as real-time fair queuing. Real-time fair queuing has potentially significant benefits for real-time traffic management. In particular, we can identify a specific delay guarantee; see 23.5.4.7 Finishing-Order Bound.

作者吐槽:也就是说,在当今世界,数据包传输时间可能是一微秒,但应用程序的数据包延迟要求可能是几毫秒,也就是说大数千倍,实时公平排队并不总是必要的。

1.4.1权重优先级队列

公平排队的一个扩展是加权公平排队(WFQ),其中我们不是给每个类一个相等的份额,而是给每个类分配一个不同的百分比。例如,我们可以将10%、30%和60%的带宽百分比分配给三个不同的部门。如果所有三个子队列都处于活动状态,则每个子队列都会获得列出的百分比。如果60%的子队列是空闲的,那么其他子队列分别获得25%和75%,保持其分配的1:3比例。如果10%的子队列是空闲的,那么其他两个子队列分别获得33.3%和66.7%。

如果所有数据包大小相同,则加权公平排队在概念上是公平排队的直接推广,尽管实际实现细节有时并不重要,因为上面的循环实现自然会产生相等的份额。如果我们有两个每个类的子队列,它们将接收40%和60%的分配(也就是说,以2:3的比例),并且所有的数据包都是相同的大小,那么我们可以通过每个类的一个子队列发送两个数据包,另三个来实现WFQ。或者我们可以将两者混合在一起:类1发送第一个数据包,类2发送第一个信息包,类1发送第二个,类2发出第二个和第三个。

1.4.2虚拟完成时间(Virtual Finishing Times)

在现实世界中,数据包的大小远非相等,混合批量和实时流量往往会使大小变化更糟。在这种情况下,公平排队和加权公平排队仍然是可能的,但我们还有更多的工作要做。

我们将首先介绍的策略——“实时”公平排队策略——是按照计算的虚拟完成时间顺序发送数据包,这有利于具有较小数据包的流和最近没有发送数据包的流量。基于虚拟完成时间的WFQ算法就是上面所说的实时公平排队。

我们提出了两种使用虚拟完成时间处理不同大小数据包的机制;两者最终是等价的。第一个23.5.3 BBRR是RR思想的直接扩展,第二个23.5.4 GPS模型使用了同时数据包传输的“流体”模型。这两种机制都有一个“虚拟时钟”的想法,它的运行速度与活动类(activated class)的数量成反比;最后,我们提出了信用值算法23.5.5 DRR,这是对任何一种精确算法的更有效近似,但作为近似,它不再满足相同的小规模延迟约束。

为了将轮询思想直接推广到不同的数据包大小,我们从一个简化开始。
简化场景1
让我们假设每个类总是活动的,其中,如果路由器每次查看类的队列时它都不是空的,则类活动的。如果每个类在大小相等的数据包情况下总是活动的,则按照增加(或至少不)每个类发送的累积数据的顺序来发送分组。换句话说,每个类都可以发送它的第一个数据包,然后我们才能开始发送第二个数据包等等。
下面直接混用类<–>类的队列<–>类的子队列;
简化场景2:假设所有队列都active但是包的大小不同;
在这里插入图片描述
场景三:包大小不同,不同类也有可能不active
在这里插入图片描述

1.4.2.1第一个虚拟完成的例子

在这里插入图片描述

因为两个子队列总是活动的,并且因为假设每个子队列接收100%的输出带宽的虚拟完成时间,所以从长远来看,实际完成时间将是虚拟时间的两倍左右。然而,这是无关紧要的;所有重要的是相对的虚拟完成时间。

1.4.2.2第二个虚拟完成的例子

该示例分析的是虚拟完成时间的失效场景。
失效场景说明:然而,对于下一个示例,我们允许子队列空闲一段时间,然后变为活动队列。在这种情况下,虚拟完成时间并不能很好地工作,至少当直接基于挂钟时间时是这样。(挂钟时间:是指,实际的物理时钟经历的时间。)
我们回到最初的简化,即所有数据包都是相同的大小,我们将其取为1个单位;这允许我们应用RR机制来确定传输顺序,并将其与虚拟完成顺序进行比较。假设有三个队列P、Q和R,并且直到墙时钟时间20之前P一直是空的。Q总是很忙;其从K=1开始的第K个分组QK具有虚拟结束时间FK=K。

对于第一种情况,假设R完全空闲。当P的第一个分组P1在时间20到达时,其虚拟结束时间将是21。在时间20,Q中的头分组将是Q21;因此这两个分组具有相同的虚拟完成时间。并且,在RR下,队列服务P1和Q21将在同一轮中发送。

对于第二种情况,然而,对于第二种情况,假设R也一直很忙。直到时间20,Q和R各自发送了10个分组;它们的下一个分组是分别具有T=11的虚拟结束时间的Q11和R11。当P的第一个数据包到达T=20时,同样具有虚拟结束时间21,在RR服务下,它应该在与Q11和R11相同的轮中发送。(这是由于P队列长时间无数据,直接使用了挂钟时间作为虚拟时间)。最终,他们的虚拟完成时间相差了大约两倍;

事实证明,trick是不是根据数据包传输时间(即wallclock时间)来测量经过的时间,而是应该根据RR传输的轮次来测量。这相当于缩放用于测量到达时间的时钟;轮次计数而不是分组计数意味着当N个子队列处于活动状态时,我们以1/N的速率运行此时钟。如果我们在情况1中这样做,N=1,那么结束时间不变。然而,在情况2中,在N=2的情况下,分组P1在20个时间单位之后到达,但仅10轮;时钟以半速率运行。因此,其计算的结束时间为11,与P1共享RR传输循环的两个长队列分组Q11和R11的结束时间完全匹配。

注意:起始到这里我发现,问题变为了,找到一种合适的虚拟完成时间的评估算法。

1.4.3Bit-by-bit Round Robin

想象一下,以循环方式,每次从每个活动输入子队列发送一个比特。虽然不能直接实现,但这肯定满足了为每个活动子队列提供同等服务的目标,即使数据包大小不同。We will use bit-by-bit round robin, or BBRR, as a way of modeling packet-finishing times。

前提:有时会发生这样的情况:在一个新的、更短的数据包到达时,正在发送一个更大的数据包,为其计算较小的完成时间。不过,电流传输并未中断;该算法是非抢占式的。

The trick to making the BBRR approach workable is to find an “invariant” formulation of finishing time that does not change as later packets arrive, or as other subqueues become active or inactive. To this end, taking the lead from the example of the previous section, we define the “rounds counter” R(t), where t is the time measured in units of the transmission time for one bit. When there are any active (nonempty or currently transmitting) input subqueues, R(t) counts the number of round-robin 1-bit cycles that have occurred since the last time all the subqueues were empty. If there are K active input subqueues, then R(t) increments by 1 as t increments by K; that is, R(t) grows at rate 1/K.
在这里插入图片描述
具体算法如下:
在这里插入图片描述
发包策略:当每个新的数据包P到达时,我们计算其BBRR结束R值FP,然后以FP的递增顺序以传统的一次一个数据包的方式发送数据包。如上所述,如果其他子队列为空或变为活动,FP将不会改变。这里我理解了一下,FP只会根据上述算法进行改变,而不会由于发包而改变。
R(t)的更新策略
在这里插入图片描述

1.4.3.1BBRR的例子

在这里插入图片描述
在这里插入图片描述
下面之所以800+400/2是因为,800-1000的过程中,以及1000-1200的过程中,P子队列和Q子队列均为non-empty状态。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实现难点:在计算上,维持R值计数器是无关紧要的。BBRR模拟的主要性能问题是,每当要发送新数据包时,都需要找到最小的R值。如果n是等待发送的数据包的数量,那么我们可以在时间O(log(n))中通过保持R值在适当的数据结构中排序来做到这一点。
BBRR方法假定每个子队列的权重相等;这并不能完全直接推广到加权公平排队,因为子队列的数量不能是分数。如果有两个队列,一个是权重为40%,另一个是60%,我们可以使用具有五个子队列的BBRR,其中两个(2/5)分配给40%子队列,另外三个(3/5)分配到60%子队列。但随着分数变得不那么简单,这变得越来越尴尬;其次,GPS模型是一个更好的选择。

1.4.4GPS(Generalized Processor Sharing)模型

与BBRR几乎等价的模型是广义处理器共享模型,或称GPS;它最初是作为CPU调度的应用程序开发的。在这种方法中,我们将数据包想象成液体,将出站接口想象成具有一定总容量的管道。来自每个子队列的头数据包都同时被压缩到管道中,每个数据包都以其指定的分数速率。GPS模型本质上是BBRR的“无穷小”变体。GPS模型具有直接推广到加权公平排队的优点。
说明:由于GPS是流体模型,它允许几种不同的流量混合在一起同时传输。

GPS模型(和BBRR模型)在输入流之间提供了理想程度的隔离:每个流都不会因竞争流上的数据包而产生任何延迟。第i个流接收的带宽至少为𝛼i和数据包只等待属于同一流的其他数据包。当数据包到达非活动子队列时,与路由器正在进行的任何其他工作交织在一起,立即开始转发。

虽然GPS作为一种模型很方便,但从字面上讲,它的可实现性甚至不如BBRR。不过,与BBRR一样,我们可以使用GPS模型来确定一次一包传输的顺序。当每个真正的数据包到达时,如果我们使用GPS,我们会计算它完成的时间。然后,按照增加GPS完成时间的顺序,在WFQ下一次一个地发送分组。
于GPS模型,假设有N个输入子队列,并且第i个子队列0≤i<N是接收分数𝛼i>0,其中𝛼0+𝛼1+…+𝛼N−1=1。如果在某个时刻,输入子队列的集合a是活动的,比如说a={0,2,4},那么子队列0将接收分数𝛼0/(𝛼0+𝛼2+𝛼4)。
在这里插入图片描述
虚拟时钟运行示例1
对于任何一个活动子队列i,相对于虚拟时钟的GPS传输速率(即,以比特/虚拟秒为单位)总是等于分数𝛼i为全输出接口速率。也就是说,如果输出速率是10Mbps,并且活动流具有分数𝛼 = 0.4,则它将总是以每虚拟微秒4比特的速率进行传输。
证明:当所有子队列都处于活动状态,并且VC时钟以wallclock速度运行时,流的实际速率将为4位/µ秒。当子队列单独处于活动状态时,实际时钟测量的速度将为10位/µ秒,但虚拟时钟的运行速度将快2.5倍,因此10位/μ秒是每2.5虚拟微秒10位,或每虚拟微秒4位。
GPS模型虚拟完成时间计算方法
To make this claim more precise, let A be the set of active queues, and let 𝛼 again be the sum of the 𝛼j for j in A. Then VC(t) runs at rate 1/𝛼 and active subqueue i’s data is sent at rate 𝛼i/𝛼 relative to wallclock time. Subqueue i’s transmission rate relative to virtual time is thus (𝛼i/𝛼)/(1/𝛼) = 𝛼i.
对于活跃队列场景
As other subqueues become inactive or become active, the VC(t) rate and the actual transmission rate move in lockstep. Therefore, as with BBRR, a packet P of size S on subqueue i that starts transmission at virtual time T will finish at T + S/(r×𝛼i) by the VC clock, where r is the actual output rate of the router, regardless of what is happening in the other subqueues. In other words, VC-calculated finishing times are invariant.
对于不活跃->活跃队列场景
在这里插入图片描述
说明:上述计算方法是因为Fprev是针对各个队列的。如果队列最开始是不活跃的,则该队列的Fprev值是无效的。

对于所有队列被暂停的场景:在这种情况下,每当输出被阻止时,虚拟时钟都应该被挂起。作为不这样做会发生什么的例子,假设R有两个子队列A和B;第一个是空的,第二个积压了很长时间。R通常每秒处理一个数据包。在T=0/VC=0时,R的输出被暂停。第二子队列b1、b2、b3、…中的分组具有虚拟完成时间1、2、3、…。在T=10时,R恢复传输,并且分组a1到达A子队列。如果R的虚拟时钟已暂停时间间隔0≤T≤10,则a1将被分配完成时间T=1,并且具有与b1相当的优先级。如果R的虚拟时钟继续运行,则a1将被分配完成时间T=11,并且直到b11到达B队列的头部才被发送。

1.4.4.1WFQ调度

WFQ调度,是在GPS模型计算出虚拟完成时间的基础上,实现的”implementable“的部署算法。

为了在加权公平排队下调度实际的数据包传输,我们在到达时计算每个数据包的虚拟时钟完成时间,假设它使用的是GPS模型。每当发送器准备开始发送新的数据包时,它就会从可用的数据包中选择GPS完成时间值最小的数据包。数据包的GPS完成时间不取决于其他子队列上的任何后续到达或空闲时间。与BBRR一样,较小但较晚到达的数据包可能具有较小的虚拟完成时间,但当前正在传输的数据包不会被中断。

1.4.4.2Under GPS and WFQ下的完成顺序

本质上GPS是WFQ的一种理想模型,WFQ是GPS的一种具体实现。
现在我们来看看在GPS和WFQ下数据包完成传输的顺序。目标是在23.5.4.7 Finishing Order Bound中提供与GPS相比,在WFQ下数据包可能需要等待多长时间的严格限制。我们再次强调:

GPS结束时间:GPS模型下基于并行多包传输的理论结束时间
WFQ结束时间:假设数据包按计算的GPS结束时间的升序顺序发送,则实际结束时间

分情况分析
如果所有子队列总是活动的(或者如果子队列的固定子集总是活动的),则分组在WFQ下以与在GPS下相同的顺序完成。这是因为在WFQ下,分组是根据虚拟时钟按照GPS完成时间的顺序发送的,并且如果所有子队列总是活动的,则虚拟时钟以与墙时钟时间相同的速率运行(或者,如果子队列的固定子集总是活动的,则以与墙钟时间成比例的速率运行)。
如果所有子队列总是活动的,那么每个分组在WFQ下至少和在GPS下一样早完成。要看到这一点,让Pj是在GPS或WFQ下完成的第j个数据包。当Pj在WFQ下完成时,路由器R将把其输出带宽的100%专门用于P1到Pj。而GPS由于是流体模型,有可能不会占据100%的输出带宽。

1.4.4.3GPS示例1

作为第一个示例,我们返回23.5.2.1的场景。第一个虚拟完成示例。路由器的两个子队列始终处于活动状态;每个都有一个𝛼=50%。所有大小为1001的分组P1、P2、P3、…在第一队列中等待;所有大小为400的分组Q1、Q2、Q3、…在第二队列中等待。输出带宽为每单位时间1字节,T=0为起始点。
在这里插入图片描述
注意,在任何情况下,实际WFQ完成时间(第三列)总是小于或等于虚拟GPS完成时间。

1.4.4.4GPS示例2(leapfrog场景)

下一个示例示出了较小但较晚到达的分组的场景。
在这里插入图片描述
在T=10之前,我们在GPS下有两个数据包在进行中(因为Q1在T=4时在GPS下结束,Q2在T=4到达),因此GPS时钟以墙时钟时间的3/2速率运行,BBRR时钟以墙钟时间的1/2速率运行。在T=4,当Q2到达时,BBRR时钟处于2,VC时钟处于6,并且我们计算BBRR结束时间为2+6=8,GPS结束时间为6+6/(1/3)=24。在T=10时,BBRR时钟为5,GPS时钟为15。R1到达;我们计算其BBRR结束时间为5+5=10,其GPS结束时间为15+5/𝛼 = 30。

因为Q2具有较早的虚拟时钟结束时间,所以WFQ在P2之后发送它,然后发送R1。
这是GPS下的传输图。图表本身按挂钟时间缩放。BBRR时钟在下面的刻度上;VC时钟总是运行得快三倍。
注意,在WFQ下的发送顺序是P1、Q1、P2、Q2、R1,而在GPS下的完成顺序是P1,Q1、Q2,R1、P2。也就是说,P2通过成为在T=3时可用于传输的唯一分组这一简单的权宜之计,在WFQ下成功地跨越Q2和R1。
在这里插入图片描述
上图中间带状部分是GPS流体模型。

1.4.4.7完成顺序边界

由于Parekh和Gallager【PG93】(另见【PG94】),这些例子使我们得出以下有延迟限制的结论;我们将在下面的24.12 Parekh-Gallager定理中使用它。它可以说是Parekh-Gallager定理最深刻的部分。

结论:对于任何数据包P,P在WFQ下路由器R处的wallclock完成时间不能比P在GPS下R处的wallclock完成时间晚R传输可能出现的最大大小数据包所需的时间。

在这里插入图片描述
证明:
To prove this claim, let us number the packets P1 through Pk in order of WFQ transmission, starting from the most recent point when at least one subqueue of the router became active. (Note that these packets may be spread over multiple input subqueues.) For each i, let Fi be the finishing time of Pi under WFQ, let Gi be the finishing time of Pi under GPS, and let Li be the length of Pi; note that, for each i, Fi+1 = Li+1/r + Fi.
If Pk finishes after P1 through Pk-1 under GPS, then the argument above (23.5.4.2 Finishing Order under GPS and WFQ) for the all-subqueues-active case still applies to show Pk cannot finish earlier under GPS than it does under WFQ; that is, we have Fk ≤ Gk.
Recalling that Fm is the finishing time of Pm under WFQ, the time Tstart above is simply Fm - Lm/r. Between Tstart and Gk, all the packets Pm+1 through Pk must arrive and then, under GPS, depart. The absolute minimum time to send these packets under GPS is the WFQ time for end-to-end transmission, which is (Lm+1 + … + Lk)/r = Fk - Fm. Therefore we have
Gk - Tstart ≥ Fk - Fm
Gk - (Fm - Lm/r) ≥ Fk - Fm
Fk ≤ Gk + Lm/r ≤ Gk + Lmax/r
The last line represents the desired conclusion.

1.4.5Deficit Round Robin

说明:原文中使用的是” quantum “,这里我直接翻译为”信用值“了。

BBRR方法具有成本O(logn),其中n是等待的数据包数量,如前所述。[SV96]中介绍的一种具有O(1)性能的简单但近似的替代方案是为每个输入子队列分配一个与该子队列的带宽份额成比例的信用值。每个子队列还将保持一个赤字,表示它过去被允许发送但由于下一个数据包太大而无法发送的累积数据量。赤字将始终小于子队列的头数据包的大小。当子队列空闲时(因此没有头数据包),赤字总是设置为零。

在每一轮中,一个子队列将被授予发送一个额外信用值值数据的权限;也就是说,信用值将被添加到子队列的赤字中。如果这个新的不足大于头数据包的大小,那么可以发送该数据包,也可能发送其他数据包。然后从赤字中减去发送的数据包的大小,现在赤字将小于新的头数据包的尺寸,下一个子队列将获得一个回合。

One cost of the quantum approach is that the elegant delay bound of 23.5.4.7 Finishing-Order Bound no longer holds. In fact, a sender may be forced to wait for all other senders each to send a full quantum, even if the sender has only a small packet. In particular, deficit round robin is not the same as BBRR, even if the deficit is one bit.

举例如下:
在这里插入图片描述
说明:DRR实际上就类似于令牌桶了,下面将说明为什么DRR算法不能严格的保证延时有界。
假设存在N个队列,只有队列1和队列N中有待发送数据,有可能在队列1发送的过程中,队列2-N-1也来了数据。如果采用GPS策略,队列N的数据应该先发送出去,由于采用轮寻策略,队列1中的数据发完后,有可能会轮询完2-N-1的数据,最后再发送队列N的数据。
在这里插入图片描述
注意:不是说DRR算法无界限,而是说DRR算法的界限比较粗糙。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值