1、说明
该项目用于简单的模拟尝试,后期完善实际的秒杀活动,将逻辑做到更深更密。
2、接口
接口也只是简单简单的在内存中插入商品,实际要考虑写入Redis
[Route("api/[controller]/[action]")]
[ApiController]
public class OrderController : ControllerBase
{
private readonly IHttpContextAccessor _httpContext;
public OrderController(IHttpContextAccessor httpContext)
{
_httpContext = httpContext;
}
//这里模拟redis
private static IDictionary<string, Product> _product = new Dictionary<string, Product>();
/// <summary>
/// 模拟下单
/// </summary>
/// <param name="product"></param>
/// <returns></returns>
[HttpPost]
public IActionResult Buy([FromBody]Product product)
{
// 登陆
var user = _httpContext.HttpContext.Request.Headers["Client-Remote-User"].ToString();
// 模拟库存量为100
if (_product.Count == 100)
{
return Ok(new AjaxRepsone(3));
}
if (_product.Keys.Contains(user))
{
return Ok(new AjaxRepsone(2));
}
// 加入到redis中
_product.Add(user, product);
return Ok(new AjaxRepsone(1));
}
class AjaxRepsone
{
public AjaxRepsone()
{
Success = true;
}
public AjaxRepsone(int type)
{
Type = type;
}
/// <summary>
/// 1-购买成功,2-已经购买,3-被抢光
/// </summary>
public int Type { get; set; }
public bool Success { get; set; }
}
}
3、模拟器
并发请求接口
class Program
{
[STAThread]
static void Main(string[] args)
{
// 10秒后开始执行
Thread.Sleep(TimeSpan.FromSeconds(3));
var build = new HostBuilder()
.ConfigureServices((hostContext, service) =>
{
service.AddHttpClient();
// 这里可以添加服务注册
//service.AddTransient<TService, Service>();
}).UseConsoleLifetime(options =>
{
options.SuppressStatusMessages = true;
});
var host = build.Build();
var api = "http://localhost:5000/api/Order/Buy";
var now = DateTime.Now;
using (var serviceScope = host.Services.CreateScope())
{
var service = serviceScope.ServiceProvider;
try
{
// 作用域块中获取服务,我这里用于直接请求接口,就免了
var httpClient = service.GetRequiredService<IHttpClientFactory>();
var client = httpClient.CreateClient("test");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var content = new HttpRequestMessage(HttpMethod.Post, new Uri(api));
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};
// 哨兵,监控后台是否返回库存为0
var flag = 0;
// 模拟5W并发请求,查看OPS、TPS峰值
for (int i = 1; i <= 5 * 1000; i++)
{
if (flag == 1)
{
break;
}
content.Headers.Clear();
//content.Headers.Add("Client-Remote-Any", Guid.NewGuid().ToString("N").ToUpper());
content = new HttpRequestMessage(HttpMethod.Post, new Uri(api));
var json = JsonSerializer.Serialize(new
{
Id = i,
Name = "",
Price = 9900d,
XingHao = "Y9000X",
Describle = "lenov"
});
var user = Guid.NewGuid().ToString("N").ToUpper();
content.Content = new StringContent(json, Encoding.UTF8, "application/json");
content.Content.Headers.TryAddWithoutValidation("Client-Remote-User", user);
var response = client.PostAsync(api, content.Content);
//var response= client.SendAsync(content);
if (response.Result.IsSuccessStatusCode)
{
var res = response.Result.Content.ReadAsStringAsync().Result;
var ajax = JsonSerializer.Deserialize<AjaxRepsone>(res, options);
switch (ajax.Type)
{
case 1:
Console.BackgroundColor = ConsoleColor.Green;
Console.WriteLine($"{user}:抢购成功咯!");
break;
case 2:
Console.BackgroundColor = ConsoleColor.Yellow;
Console.WriteLine($"{user}:您已经抢购咯!");
break;
case 3:
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine($"{user}:被其他抢光咯!");
flag = 1;
break;
default:
break;
}
}
}
}
catch (Exception)
{
throw;
}
}
Console.BackgroundColor = ConsoleColor.Blue;
Console.WriteLine($"=======商品{(DateTime.Now - now).TotalMilliseconds}毫秒抢光啦======");
Console.ReadLine();
}
}
class AjaxRepsone
{
public int Type { get; set; }
public bool Success { get; set; }
}
后面尽快完善更切入实际秒杀活动,凭借搜索了解秒杀活动原理,便自己先简单的进行了尝试,当大佬看见时还请多多指教