排队系统设计思考

常用限流处理的几种方式:

1.通过限制单位时间段内调用量来限流

2.通过限制系统的并发调用程度来限流

3.使用漏桶(Leaky Bucket)算法来进行限流

4.使用令牌桶(Token Bucket)算法来进行限流

 

1通过限制单位时间段内调用量来限流:

通过限制某个服务的单位时间内的调用量来进行限流。从字面上,确实很容易理解,我们需要做的就是通过一个计数器统计单位时间段某个服务的访问量,如果超过了我们设定的阈值,则该单位时间段内则不允许继续访问、或者把接下来的请求放入队列中等待到下一个单位时间段继续访问。这里,计数器在需要在进入下一个单位时间段时先清零

对于限制单位时间段内调用量的这种限流方式,实现简单,适用于大多数场景,如果阈值可以通过服务端来动态配置,甚至可以当做业务开关来使用,但也有一定的局限性,因为我们的阈值是通过分析单位时间段内调用量来设置的,如果它在单位时间段的前几秒就被流量突刺消耗完了,将导致该时间段内剩余的时间内该服务“拒绝服务”,可以将这种现象称为“突刺消耗”

 

2通过限制系统的并发调用程度来限流:

通过严格限制某服务的并发访问程度,其实也就限制了该服务单位时间段内的访问量

并发的阈值设置成多少比较合适?比如限制服务的并发访问数是100,而服务处理的平均耗时是10毫秒,那么1分钟内,该服务平均能提供( 100 / 10 ) * 60 * 100 = 6,000 次

通过线上业务的监控数据来逐步对并发阈值进行调优,只要肯花时间,我们总能找到一个即能保证一定服务质量又能保证一定服务吞吐量的合理并发阈值

3通过漏桶算法来进行限流:

漏桶算法是网络中流量整形的常用算法之一,它有点像我们生活中用到的漏斗,液体倒进去以后,总是从下端的小口中以固定速率流出,漏桶算法也类似,不管突然流量有多大,漏桶都保证了流量的常速率输出

漏桶算法其实是悲观的,因为它严格限制了系统的吞吐量

4.令牌桶算法限流

令牌桶算法从某种程度上来说是漏桶算法的一种改进,漏桶算法能够强行限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许某种程度的突发调用

在令牌桶算法中,桶中会有一定数量的令牌,每次请求调用需要去桶中拿取一个令牌,拿到令牌后才有资格执行请求调用,否则只能等待能拿到足够的令牌数

令牌桶算法的精髓就在于“拿令牌”和“放令牌”的方式 

 

 

我们的做法

技术实现目的 :  单位时间内控制一定数量的用户进入活动页面

实现原理 :    使用漏桶算法,每次用户进去活动页面时,检查限流缓存计数值是否存在,如果存在,允许进入,并且计数递减一位;

 当计数器归零后,表示该单位时间内可参与人数已满,后续用户进入排队系统。

排队静态页面按照固定秒数时间后,自动会跳到限流控制页面,重新查询缓存计数值

 

注意:

1、排队页面纯HTML处理,可以容纳更多的请求数

2、容错页面做成和排队页面差不多的纯静态脚本,让用户无感知

 

3、后台需要设置合理的单位时间并发数限制

 

 

硬货来啦:

$redis = getRedis(); // 获取自己的redis资源

//整理正确的缓存键名,带有时间(测试时,定位到分钟,实际使用时,可以限制到秒)

$cacheKey = $config['自己的cacheKey'].'_'. date('Y-m-d-H:i:s', time());

//如果不存在缓存,计数器初始化

if(!$redis->exists($cacheKey)){

  $redis->set($cacheKey, 预置限流阈值);

  $redis->expire($cacheKey, 100);//100秒后销毁缓存

}

 

 $counts = (int)$redis->get($cacheKey);

if($counts <= 0){

  //当计数器统计数小于等于0时,用户进入排队系统

  header('HTTP/1.1 404 Not Found');

  $redirect_url = 自己的静态页;

}else{

  //可以进入活动

  $redirect_url = 自己的活动页;

  //计数递减

  if($counts > 0){

    $redis->decr($cacheKey);

  }

}

header("location:$redirect_url");

转载于:https://www.cnblogs.com/aifengguo/p/6340828.html

### 银行客户排队系统的设计思路 银行客户排队系统的核心在于利用队列这一基本数据结构来管理客户的等待次序。通过队列的操作特性(先进先出),可以有效地模拟客户到达柜台并依次被服务的过程。 以下是实现该功能的一个典型方案: #### 定义队列结构 在C语言中,可以通过数组或者链表两种方式实现队列。这里采用链表形式的队列,因为其动态扩展能力更强,适合处理不确定数量的客户需求[^4]。 ```c #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> typedef int DataType; // 定义单向链表节点 typedef struct QueueNode { DataType data; struct QueueNode* next; } QNode; // 定义队列结构体 typedef struct PQueue { QNode* head; // 头指针 QNode* tail; // 尾指针 } PQueue; ``` #### 初始化与销毁队列 初始化时需分配内存给`head`和`tail`指针,并将其置为空;而销毁则需要遍历整个链表释放所有节点占用的空间。 ```c void QueueInit(PQueue* pq) { assert(pq); pq->head = NULL; pq->tail = NULL; } void QueueDestroy(PQueue* pq) { assert(pq); while (pq->head != NULL) { QNode* tmp = pq->head; pq->head = pq->head->next; free(tmp); } } ``` #### 基本操作:入队、出队及查询 - **入队** (`push`):新加入的顾客信息存放在新的节点里并通过调整尾指针完成插入动作。 - **出队** (`pop`):移除最前面一位待办事项对应的记录项,更新头指针对应位置即可。 - **获取当前首位元素** (`front`) 和最后一位(`back`) 的方法也十分简单明了。 ```c void QueuePush(PQueue* pq, DataType data) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); if (!newnode){ perror("Failed to allocate memory"); exit(EXIT_FAILURE); } newnode->data = data; newnode->next = NULL; if(!pq->tail){ pq->head = pq->tail = newnode; }else{ pq->tail->next = newnode; pq->tail = newnode; } } DataType QueueFront(const PQueue* pq) { assert(pq && pq->head); return pq->head->data; } bool QueueEmpty(const PQueue* pq) { return pq->head == NULL; } void QueuePop(PQueue* pq) { assert(pq && !QueueEmpty(pq)); QNode* del = pq->head; if(pq->head==pq->tail){ pq->head=pq->tail=NULL; }else{ pq->head = pq->head->next; } free(del); } ``` 以上代码片段展示了如何构建一个基础版的支持增删查等功能的队列类对象模型[^4]。实际应用过程中还需要考虑更多细节比如异常情况下的错误提示机制等附加逻辑部分。 ### 扩展思考方向 考虑到真实场景中的复杂度增加因素如优先级区分、VIP通道支持等问题,则可能需要用到更复杂的多维数组或多条独立运作却互相联系紧密的小型子队列组合而成的整体解决方案[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值