使用Grafana k6对Grafana Loki进行负载测试的快速指南

995 阅读7分钟

作为Grafana实验室的一名软件工程师,我了解到,当有人开始设置一个新的Loki安装时,通常会有两个问题出现。"我可以将多少日志摄入我的集群?"其次是,"我可以多快地查询这些日志?"

有两种方法可以找到答案:

你可以配置你现有的应用基础设施来推送日志,看看会发生什么--或者你可以用聪明的方法找出答案,用Grafana k6对系统进行负载测试。

Grafana k6是一个现代的负载测试工具。它简洁而平易近人的脚本API可以在本地或云端工作。值得庆幸的是,还有一个k6扩展,允许你向Loki推送日志并从Loki查询日志。它作为一个Loki客户端,模拟真实世界的负载来测试你的Loki安装的可扩展性、可靠性和性能。

在这篇文章中,我将解释如何做到这一点,并向你展示写入和查询路径测试的基本概念,以及一些关于如何使用配置选项来调整你的测试的更多见解。在我的解释中,我将假设你对如何使用k6有一个基本的了解。(如果你是新手,请看一下文档--它很棒!)另外,我不打算解释如何构建和安装k6 Loki扩展,但这并不像你想象的那么难。你可以在这里找到说明。

一旦扩展构建完成,你可以使用生成的二进制文件来执行一个用Javascript编写的负载测试文件。在JS文件中,你可以使用由xk6-loki扩展提供的API。指令本身并不由JS运行时执行,而只是二进制代码的函数调用。这样一来,它就结合了生成日志行和执行网络请求的编译Go代码的性能,以及Javascript中脚本的灵活性。

一个非常基本的test.js负载测试文件看起来像这样:

import loki from 'k6/x/loki';

const timeout = 5000; // ms
const conf = loki.Config("http://localhost:3100", timeout);
const client = loki.Client(conf);

export default () => {
   client.push();
};

并可以像这样执行:

./k6 run test.js

推送日志

首先,让我们看看如何随机推送请求来模拟写路径负载。如上面的例子所示,客户端对象有一个方法push() 。这将产生一个单一的推送请求,其有效载荷包含五个具有随机标签值的数据流,以及总的未经压缩的日志文件大小在800Kb和1Mb之间。

需要调整请求参数吗?客户端也有一个pushParameterized(streams, minSize, maxSize) 方法,可以让你做到这一点。在下面的例子中,推送请求产生的随机量在2到8个流之间,日志总大小在1到2MB之间:

import loki from 'k6/x/loki';

const conf = loki.Config("http://localhost:3100");
const client = loki.Client(conf);

export default () => {
   let streams = randInt(2, 8);
   client.pushParameterized(streams, 1024*1024, 2*1024*1024);
};

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
};

如果你想要一个恒定的批次大小,把第二个和第三个参数设置为相同的值。每个单独流的大小是总大小除以流的数量。

就实际的日志行而言,xk6-loki使用flog 库生成日志行,该库以各种常见的日志格式生成假的日志行,如apache_commonsyslog rfc5424 ,或json 。日志行的格式由流的format 标签定义。

标签和流

到目前为止,我们已经控制了实际日志的格式和大小,但没有看一下日志元数据,也叫标签。一组具有唯一键值对的标签被称为流,而一个流包含许多日志行。当使用pushParameterized(n, minSize, maxSize) 功能将日志推送到Loki时,xk6-loki创建了n个随机标签值的流。

一个流总是包含三个预定义的标签 -instance,os, 和format - 以及可选的标签namespace,app,pod,language, 和word 。预定义标签instance 被设置为VU和主机名;oswindows,linux, 或darwin 中的一个;format 是flog支持的日志格式之一。

可选的标签是在配置对象被实例化时使用的,带有 "标签数量 "地图。该地图定义了应该使用多少个给定标签名称的不同标签值。它允许你控制负载测试可能产生多少个独特的数据流,这只是可能的值的笛卡尔乘积。

下面的例子显示了如何配置可选标签的cardinality:

import loki from 'k6/x/loki';

const labels = {
  "namespace": 2,
  "app": 5,
};
const conf = loki.Config("http://localhost:3100", 10000, labels);
const client = loki.Client(conf);

假设测试是从一台有10个VU的机器上运行的,最大的唯一流数量是:

# instance x os x format x namespace x app
10 x 3 x 6 x 2 x 5 = 1800 streams

在撰写本文时,没有办法定义自定义标签名称。

查询日志

与推送日志一样,客户端对象也提供了从Loki查询日志和元数据的功能。就像Loki的查询API端点一样,这些方法是:

  • instantQuery(query, limit)
  • rangeQuery(query, duration, limit)
  • labelsQuery(duration)
  • labelValuesQuery(label, duration)
  • seriesQuery(matchers, duration)

(它们的作用和它们的名字一样)。

下面的例子使用来自配置对象的标签来生成随机的LogQL查询。由于标签池是在配置对象实例化时生成的--而且是用一个固定的种子完成的--标签名称和值是以一种可预测的方式生成的。当你想分别运行一个写和一个读的负载测试时,这很有用:

import {check} from 'k6';
import loki from 'k6/x/loki';

const conf = loki.Config("http://localhost:3100");
const client = loki.Client(conf);

export default () => {

  // Pick a random log format from label pool
  let format = randomChoice(conf.labels\["format"]);

  // Execute instant query with limit 1
  res = client.instantQuery(`count_over_time({format="${format}"}[15m])`, 1)
  // Check for successful read
  check(res, { 'successful instant query': (res) => res.status == 200 });

  // Execute range query over last 15m and limit 1000
  res = client.rangeQuery(`{format="${format}"}`, "15m", 1000)
  // Check for successful read
  check(res, { 'successful range query': (res) => res.status == 200 });
}

function randomChoice(items) {
  return items\[Math.floor(Math.random() * items.length)];
}

在进行查询测试时,必须始终检查API调用的响应,因为它可以进一步了解查询是否成功。

单用户与多租户

Loki可以在单租户和多租户模式下运行。在单租户模式下运行时,所有日志都存储在同一个租户下。"假"。在多租户模式下,客户可以指定X-Scope-OrgID 头来识别为租户。由特定租户存储的日志只能由同一租户检索。xk6-loki也支持这两种操作方式。

如果Loki被配置为多租户模式(启用认证),并且loki.Config 方法没有收到作为URL一部分的用户名,xk6-loki将为每个虚拟用户(VU)使用不同的X-Scope-OrgID 值(格式为xk6-tenant-$VU )。这意味着,运行一个有n个VU的测试将为每个VU摄取大约1/n的总日志。这同样适用于查询,所以一个租户的查询只处理摄入的总数据的1/n。

如果Loki被配置为多租户模式,但你想在单用户模式下使用xk6-loki,你可以在URL的用户信息部分指定用户名,也可以选择密码。它看起来像这样:

`const conf = loki.Config(“http://username[:password]@localhost:3100”)`

这样,每个请求,包括推送和查询日志,都是在负载测试的所有VU上使用相同的X-Scope-OrgID 头。

多租户模式与单用户模式不同,单用户模式可以选择接受密码,多租户模式不允许对单个租户进行授权(密码)。

监控你的负载测试

最后但并非最不重要的是,如果不收集可以分析和比较的硬数据,那么负载测试将是什么?除了k6的内置指标外,该扩展还收集了额外的自定义指标--包括推送和查询请求--并在测试结束后的总结中打印。下面是一个看起来像什么的例子。

对于查询请求,这些指标被暴露出来:

  • loki_bytes_processed_total
  • loki_bytes_processed_per_second(每秒)
  • loki_lines_processed_total
  • loki_lines_processed_per_second

loki_bytes_processed_total 和 ,分别是字节和行的计数器。loki_lines_processed_total

loki_bytes_processed_per_second 和 ,分别是字节和行的吞吐率。loki_lines_processed_per_second

所有这四个指标都来自Loki服务器发送的查询响应统计。

而对于推送请求,你会想使用:

  • loki_client_lines
  • loki_client_uncompressed_bytes

loki_client_lines 是一个计数器,计算在负载测试期间推送到Loki的总行数。 ,计算推送的日志行的总字节数。loki_client_uncompressed_bytes

这些指标可以深入了解有多少数据被传送到Loki并被其处理。