负载测试,尝试生成随机名称但为许多虚拟用户获取相同的名称
Load Tests, trying to generate random names but getting same names for many virtual users
我正在使用 Visual Studio 性能测试。我想在我的每个请求之前生成一个随机名称。我为此使用了这个 WebTestRequestPlugin:
using System;
using System.ComponentModel;
using System.Linq;
using Microsoft.VisualStudio.TestTools.WebTesting;
namespace TransCEND.Tests.Performance.Plugins
{
public class RandomStringContextParameterWebRequestPlugin : WebTestRequestPlugin
{
[Description("Name of the Context Paramter that will sotre the random string.")]
[DefaultValue("RandomString")]
public string ContextParameter { get; set; }
[Description("Length of the random string.")]
[DefaultValue(10)]
public int Length { get; set; }
[Description("Prefix for the random string.")]
[DefaultValue("")]
public string Prefix { get; set; }
private readonly string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Random _random = new Random();
public RandomStringContextParameterWebRequestPlugin()
{
ContextParameter = "RandomString";
Prefix = "";
Length = 10;
}
public override void PreRequestDataBinding(object sender, PreRequestDataBindingEventArgs e)
{
e.WebTest.Context[ContextParameter] = CreateNewRandomString();
base.PreRequestDataBinding(sender, e);
}
private string CreateNewRandomString()
{
var randomString = new string(Enumerable.Repeat(_chars, Length).Select(s => s[_random.Next(s.Length)]).ToArray()).ToLower();
return $"{Prefix}{randomString}";
}
}
}
我的问题是,当我开始对多个虚拟用户进行负载测试时,前几个用户的 preRequest 代码 运行 立即开始,在每个 运行 上重写 RandomName 上下文参数。所以当我的请求实际上是 运行ning 时,它们使用相同的随机名称,导致我的后端代码发生冲突。
我的问题是,即使用户负载很高,我如何才能为我的每个请求生成随机名称?
我认为问题在于标准随机数例程不是线程安全的。因此每个虚拟用户 (VU) 获得相同的随机种子值,因此获得相同的随机数。请参阅 here and here 以获得更完整的解释。
问题中没有显示 CreateNewRandomString
的代码,但它可能使用了具有上述问题的基本 C# 随机数代码。解决方案是使用更安全的随机数。 This question 提供了一些关于更好的随机数生成器的想法。
我在几个性能测试中使用了基于以下的代码:
public static class RandomNumber
{
private static Random rand = new Random(DateTime.Now.Millisecond);
private static object randLock = new object();
/// <summary>
/// Generate a random number.
/// </summary>
/// <param name="maxPlus1">1 more than the maximum value wanted.</param>
/// <returns>Value between 0 and maxPlus1-1 inclusive. Ie 0 .le. returned value .lt. maxPlus1</returns>
public static int Next(int maxPlus1)
{
int result;
lock (randLock)
{
result = rand.Next(maxPlus1);
}
return result;
}
}
在上面的代码中添加一个字符串创建方法应该很简单,它可以在 lock{ ... }
语句中生成所需的字符串。
问题中 "rewriting the RandomName context parameter on every run. So when my requests are actually running, they are using the same random name" 的部分误解了正在发生的事情。每个VU都有自己的一套CP,只是随机数是一样的。
我正在使用 Visual Studio 性能测试。我想在我的每个请求之前生成一个随机名称。我为此使用了这个 WebTestRequestPlugin:
using System;
using System.ComponentModel;
using System.Linq;
using Microsoft.VisualStudio.TestTools.WebTesting;
namespace TransCEND.Tests.Performance.Plugins
{
public class RandomStringContextParameterWebRequestPlugin : WebTestRequestPlugin
{
[Description("Name of the Context Paramter that will sotre the random string.")]
[DefaultValue("RandomString")]
public string ContextParameter { get; set; }
[Description("Length of the random string.")]
[DefaultValue(10)]
public int Length { get; set; }
[Description("Prefix for the random string.")]
[DefaultValue("")]
public string Prefix { get; set; }
private readonly string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private Random _random = new Random();
public RandomStringContextParameterWebRequestPlugin()
{
ContextParameter = "RandomString";
Prefix = "";
Length = 10;
}
public override void PreRequestDataBinding(object sender, PreRequestDataBindingEventArgs e)
{
e.WebTest.Context[ContextParameter] = CreateNewRandomString();
base.PreRequestDataBinding(sender, e);
}
private string CreateNewRandomString()
{
var randomString = new string(Enumerable.Repeat(_chars, Length).Select(s => s[_random.Next(s.Length)]).ToArray()).ToLower();
return $"{Prefix}{randomString}";
}
}
}
我的问题是,当我开始对多个虚拟用户进行负载测试时,前几个用户的 preRequest 代码 运行 立即开始,在每个 运行 上重写 RandomName 上下文参数。所以当我的请求实际上是 运行ning 时,它们使用相同的随机名称,导致我的后端代码发生冲突。
我的问题是,即使用户负载很高,我如何才能为我的每个请求生成随机名称?
我认为问题在于标准随机数例程不是线程安全的。因此每个虚拟用户 (VU) 获得相同的随机种子值,因此获得相同的随机数。请参阅 here and here 以获得更完整的解释。
问题中没有显示 CreateNewRandomString
的代码,但它可能使用了具有上述问题的基本 C# 随机数代码。解决方案是使用更安全的随机数。 This question 提供了一些关于更好的随机数生成器的想法。
我在几个性能测试中使用了基于以下的代码:
public static class RandomNumber
{
private static Random rand = new Random(DateTime.Now.Millisecond);
private static object randLock = new object();
/// <summary>
/// Generate a random number.
/// </summary>
/// <param name="maxPlus1">1 more than the maximum value wanted.</param>
/// <returns>Value between 0 and maxPlus1-1 inclusive. Ie 0 .le. returned value .lt. maxPlus1</returns>
public static int Next(int maxPlus1)
{
int result;
lock (randLock)
{
result = rand.Next(maxPlus1);
}
return result;
}
}
在上面的代码中添加一个字符串创建方法应该很简单,它可以在 lock{ ... }
语句中生成所需的字符串。
问题中 "rewriting the RandomName context parameter on every run. So when my requests are actually running, they are using the same random name" 的部分误解了正在发生的事情。每个VU都有自己的一套CP,只是随机数是一样的。