Fork me on GitHub

GoReplay除杂

  

  最近做项目,用到goreplay来做流量回放,什么是goreplay?

  GoReplay is an open-source network monitoring tool which can record your live traffic, and use it for shadowing, load testing, monitoring and detailed analysis.

  本质上就是通过监控网络,录制http请求信息(对应用无入侵),然后再把请求重新播放出来。

 

 

 

  这是官方给出来运行原理图。

  关于goreplay的使用方式,命令用法官方文档给的很全面了,不作赘述,本篇文章关注的是除杂(过滤)。官方本来是支持过滤filtering的,但过滤的范围有限,目前只有Allow url regexp,Disallow url regexp,Filter based on regexp of header,Filter based on HTTP method,也就是对url,header,method三个方向作了过滤,我的需求是对body过滤,不包括在范围内(也有可能我没找到对应文档)

  官方找不到对应办法,只能“曲线救国”了,因为goreplay录制的内容是文本性质,所以可以对录制内容下手,把自己认定的杂质除掉,然后再播放,这样就达到效果了。

录制:

我是在windows下demo的,所以下载goreplay的winodwst版本【https://github.com/buger/goreplay/releases/download/v1.3.2/gor-1.3.2_windows.zip】,同时还需要安装WinPcap配合【https://www.winpcap.org/install/bin/WinPcap_4_1_3.exe】,这样就可以通过命令进行录制了:

gor --input-raw :5000 --output-file request.gor

被录制的服务是一个api,实现如下

[HttpPost("/order")]
public IActionResult Post([FromBody] Order order)
{
    _logger.LogInformation(System.Text.Json.JsonSerializer.Serialize(order));
    order.Status = 200;
    return new JsonResult(order);
}

public class Order
{
    public string Code { get; set; }
    public decimal Amount { get; set; }
    public int Status { get; set; }
}

  gorreplay录制的内容格式如下:

1 c9051388c0a8000437c39d7f 1629555358511143000 0
POST /pay HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.28.3
Accept: */*
Postman-Token: 3a49aba0-2e9b-4f1d-8fc8-01fb8b15d620
Host: 192.168.0.7:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 92

{
    "code":"3a13abfe-d9cb-4e11-ba90-738e93d2cb07",
    "amount":908.59,
    "status":552
}
🐵🙈🙉
1 c9051388c0a8000437c39d7f 1629555358813757000 0
POST /pay HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.28.3
Accept: */*
Postman-Token: 3a49aba0-2e9b-4f1d-8fc8-01fb8b15d620
Host: 192.168.0.7:5000
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 92

{
    "code":"3a13abfe-d9cb-4e11-ba90-738e93d2cb07",
    "amount":908.59,
    "status":552
}
🐵🙈🙉

除杂

  文中的json就是我请求的body,就要依据这个json中的一些数据来除杂,所以就得写段代码解决这个事情。

  其实原理很简单,因为我知道我请求的都是json,所以就是从录制的文件中,按段切割,很明细就是三只猴子🐵🙈🙉为分割点,把内容中的json查询出来,然后运用上规则引擎达到过滤作用,把符合条件的数据留下,不符合条件的数据就除杂,最后保存成一个新文件,供流量回放时使用。

  规则引擎

  桂素伟,公众号:桂迹一个简单的规则引擎例子

  步骤确定了,下面是代码:

using RulesEngine;
using RulesEngine.Models;
using RulesEngine.Extensions;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json;
using System.Dynamic;

var path = @"C:\MyFile\Source\Repos\Asp.NetCoreExperiment\Asp.NetCoreExperiment\GoReplay\GoReplayDemo01\request_0.gor";
var expression = "input1.amount >= 900.00";
await ImpurityRemoval(path, expression);

/// <summary>
/// 除杂方法,会重新生成一个带有日期时间的新.gor文件
/// </summary>
static async Task ImpurityRemoval(string path, string expression)
{
    using var readFile = new StreamReader(path, Encoding.UTF8);
    using var writeFile = new StreamWriter(@$"{path.Replace(Path.GetFileName(path), Path.GetFileNameWithoutExtension(path) + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + Path.GetExtension(path))}", true, Encoding.UTF8);
    var split = "🐵🙈🙉";
    string? line;
    var request = new StringBuilder();
    while ((line = await readFile.ReadLineAsync()) != null)
    {
        if (line != split)
        {
            request.Append(line + "\n");
        }
        else
        {
            request.Append(line + "\n");
            var list = GetJson(request.ToString());

            foreach (var item in list)
            {
                var converter = new ExpandoObjectConverter();
                var entity = JsonConvert.DeserializeObject<ExpandoObject>(item, converter);
                if (await Filter(entity, expression))
                {
                    await writeFile.WriteAsync(request.ToString());
                }
            }
            request.Clear();
        }
    }
}
/// <summary>
/// 获取json,这里没有完全测试
/// </summary>
static List<string> GetJson(string jsonString)
{
    var pattern = @"\{(.|\s)*\}";
    var list = new List<string>();
    var matches = Regex.Matches(jsonString, pattern, RegexOptions.IgnoreCase);
    foreach (Match m in matches)
    {
        list.Add(m.Value);
    }
    return list;
}
/// <summary>
/// 用规则引擎匹配过滤规则
/// </summary>
static async Task<bool> Filter(dynamic? entity, string expression)
{
    var workRules = new WorkflowRules();
    workRules.WorkflowName = "ImpurityRemoval";
    workRules.Rules = new List<Rule>
    {
        new Rule
        {
            RuleName="ImpurityRemoval01",
            SuccessEvent= "10",
            RuleExpressionType= RuleExpressionType.LambdaExpression,
            Expression= expression,          
        }
    };
    var rulesEngine = new RulesEngine.RulesEngine(new WorkflowRules[] { workRules });
    List<RuleResultTree> resultList = await rulesEngine.ExecuteAllRulesAsync("ImpurityRemoval", entity);
    var result = false;
    resultList.OnSuccess((eventName) =>
    {
        result = true;
    });
    return result;
}

  回放

gor --input-file=request_0_20210821234723.gor --output-http="http://localhost:5000"

 注意事项:

  1. 在录制的时候本机请求不进行录制,需要外部访问api
  2. 在除杂过程中,重新生成gor文件时,换行一定要UNIX(LF),不要是Windows(CRLF),说人话就是生成文件的换行用\n,不要\r\n,否则回放时goreplay不起作用

  想要更快更方便的了解相关知识,可以关注微信公众号 

 

 

posted @ 2022-03-14 21:03  桂素伟  阅读(157)  评论(0编辑  收藏  举报