moco固定QPS接口升级补偿机制
时间:2022-07-24
本文章向大家介绍moco固定QPS接口升级补偿机制,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
之前写过一篇?如何mock固定QPS的接口,中间用到了流量控制类Semaphore
和线程安全的知识。当时在测试过程中,多线程并发请求,QPS
误差率在**5%**以内,觉得算是在可接受范围内的,所以并没有做进一步优化。
最近看了一篇有关开源代码文章,有点感触,就在原来的基础上做了优化。主要思路是新建一个线程,通过计算理论值和实际值的差距,通过一个线程安全的对象完成这个补偿修正。
核心代码如下:
package com.fun.moco.support
import com.fun.frame.SourceCode
import com.github.dreamhead.moco.ResponseHandler
import com.github.dreamhead.moco.handler.AbstractResponseHandler
import com.github.dreamhead.moco.internal.SessionContext
import com.github.dreamhead.moco.util.Idles
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger
import static com.google.common.base.Preconditions.checkArgument
/**
* 固定QPS的接口实现类
*/
class QPSHandler extends AbstractResponseHandler {
private static final Semaphore semaphore = new Semaphore(1, true);
/**
* 访问间隔,使用微秒控制
*/
private final int gap
private final ResponseHandler handler
/**
* 用于记录收到第一个请求的时间
*/
private long start
/**
* 用于统计已处理请求的总次数,因为用了流量控制,所以不适用安全类
*/
private int times = 0
/**
* 用于统计实际的请求数和预期请求数直接的差距,由于在真实场景下预期的QPS总是大于实际QPS,所以只处理diff为正值的情况
*/
private AtomicInteger diff = new AtomicInteger(0)
private QPSHandler(ResponseHandler handler, int gap) {
this.gap = gap * 1000
this.handler = handler
}
public static ResponseHandler newSeq(final ResponseHandler handler, int gap) {
checkArgument(handler != null, "responsehandler 不能为空!");
def handler1 = new QPSHandler(handler, gap)
handler1.thread.start()
return handler1;
}
/**
* 具体实现,这里采用微秒,实验证明微秒更准确
* @param context
*/
@Override
void writeToResponse(SessionContext context) {
if (start == 0) start = SourceCode.getNanoMark()
semaphore.acquire()
if (diff.getAndIncrement() <= 0) Idles.idle(gap, TimeUnit.MICROSECONDS)
times++
semaphore.release()
handler.writeToResponse(context)
}
/**
* 用于定时计算实际处理请求与预期处理请求数量差距,补偿缺失部分的多线程
*/
private Thread thread = new Thread(new Runnable() {
@Override
void run() {
while (true) {
SourceCode.sleep(30_000)
long present = SourceCode.getNanoMark()
def t0 = present - start
def t1 = times * gap
if (t0 - t1 > gap) diff.getAndSet((t0 - t1) / gap)
}
}
})
}
-
times
属性我并没有使用线程安全类,因为执行times++
的时候已经是单线程执行了,过多使用线程安全类会使QPS
误差更大。 -
diff
属性的正负值问题。在实际使用时发现diff
的值总是正值,也就是期望QPS
总是大于实际的QPS
,这个跟响应的代码执行和Idles.idle()
方法的误差有关系。
- 2272: [Usaco2011 Feb]Cowlphabet 奶牛文字
- 1632: [Usaco2007 Feb]Lilypad Pond
- 1630/2023: [Usaco2005 Nov]Ant Counting 数蚂蚁
- Java设计模式(七)Decorate装饰器模式
- 1623: [Usaco2008 Open]Cow Cars 奶牛飞车
- 1622: [Usaco2008 Open]Word Power 名字的能量
- 3297: [USACO2011 Open]forgot
- 1740: [Usaco2005 mar]Yogurt factory 奶酪工厂
- 1741: [Usaco2005 nov]Asteroids 穿越小行星群
- 3298: [USACO 2011Open]cow checkers
- 3433: [Usaco2014 Jan]Recording the Moolympics
- 3410: [Usaco2009 Dec]Selfish Grazing 自私的食草者
- 3391: [Usaco2004 Dec]Tree Cutting网络破坏
- 3404: [Usaco2009 Open]Cow Digit Game又见数字游戏
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浅谈django不使用restframework自定义接口与使用的区别
- 实例解析php的数据类型
- 实现PHP中session存储及删除变量
- php微信公众号开发之秒杀
- php fread函数使用方法总结
- Yii2框架控制器、路由、Url生成操作示例
- Laravel框架实现调用百度翻译API功能示例
- phpstudy2018升级MySQL5.5为5.7教程(图文)
- laravel实现简单用户权限的示例代码
- tp5(thinkPHP5框架)时间查询操作实例分析
- PHP使Laravel为JSON REST API返回自定义错误的问题
- 详解PHP PDO简单教程
- Python实现ElGamal加密算法的示例代码
- PHP实现基于状态的责任链审批模式详解
- django rest framework使用django-filter用法