我正在尝试构建一个Web API,该API连接到SQL Server 2012数据库,该数据库在单个表中具有1400万+条记录。API 的唯一操作是 GET,并将作为开放数据 API 向公众开放,因此它需要能够处理许多并发用户。
该表有七个字段:
field1 bigint
field2 nvarchar(50)
field3 nvarchar(10)
field4 float
field5 datetime
field6 nvarchar(20)
field7 nvarchar(10)
我用以下语言编写了简单的测试 API:
- C# .NET 4.6.1
- C# .NET Core 2
我还尝试过将ApirIO作为Nuget包和命令行应用程序。
我也尝试过将Python Eve与SQLAlchemy一起使用,但结果相似。
API 的工作原理是我可以在我的浏览器、邮递员、cURL 等上看到结果。但是当我尝试以每秒 30 个请求(测试持续时间 30 秒)的速度使用 Vegeta 加载测试时,我遇到了多个连接错误,延迟上升到 30 秒左右。
我已经在 AperIO 命令行应用程序上运行的 API 上粘贴了负载测试的结果:
Requests [total, rate] 900, 30.03
Duration [total, attack, wait] 59.9700536s, 29.966666367s, 30.003387233s
Latencies [mean, 50, 95, 99, max] 29.903549803s, 30.002625352s, 30.004389905s, 30.012575115s, 30.03090955s
Bytes In [total, mean] 49579, 55.09
Bytes Out [total, mean] 0, 0.00
Success [ratio] 1.22%
Status Codes [code:count] 200:11 0:889
Error Set:
Get http://localhost:18092/xyz?pageSize=25: net/http: timeout awaiting response headers
我尝试过带或不带 OData 的 C#,以及最大页面大小设置为 50、25、10、5 的手动编码分页类,但结果都大致相似。
注意:我截断了表并重新填充了 5000 条记录,负载测试没有问题。我重新填充了 1400 万条记录,错误再次出现。
有没有办法优化SQL Server,以非常低的延迟(约0.015秒)将记录集超过1400万的数据库提供给具有多个并发用户(例如1000个用户)的API?
提前感谢,
莫
编辑(从评论中澄清):
服务器有 RAM 32GB/内存 160GB/4 个 CPU
- 大约 100 秒后,CPU 达到 5%,我们暂时将服务器增加到 8 个 CPU,但它们也上升到 100%
表上有聚集索引和非聚集索引
控制器中 Get 方法的 Linq 代码为:
var source = (from aqm in _context.aqm_context.
OrderBy(a => a.field1)
select aqm).AsQueryable();
var items = source.Skip((CurrentPage - 1) * PageSize).Take(PageSize).ToList();
return items;
从 SQL Server Profiler 中,正在执行的 SQL 是
SELECT
[Extent1].[field1] AS [field1],
[Extent1].[field2] AS [field2],
[Extent1].[field3] AS [field3],
[Extent1].[field4] AS [field4],
[Extent1].[field5] AS [field5],
[Extent1].[field6] AS [field6],
[Extent1].[field7] AS [field7]
FROM [dbo].[table] AS [Extent1]
ORDER BY [Extent1].[field1] ASC
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY
我最初将MongoDB与Python Eve(具有相同的记录集)一起使用,并且我获得了0.015秒的延迟,并且在运行相同的测试时没有错误。MongoDB不在我的组织批准的技术列表中,所以我被要求尝试SQL Server作为后端。我使用连接到SQL Server的SQLAlchemy尝试了相同的Eve配置,并立即收到了糟糕的延迟和连接错误。
所以问题也可能是:
SQL Server是否是一个有效的选择,可以向公众提供具有1400万记录集的开放数据API,并可能有数千个并发用户?还是像MongoDB这样的NoSQL文档存储更适合?
要回答您的问题,SQL Server 可以处理如此多的数据吗?
是的,我们已经在 4 亿行中使用它。以下是我们遵循的步骤:
- 我们选择了多核服务器,并在那里划分了tempdb并放在SSD上。
- 对我们来说,读取操作很重要,因此索引是基于此完成的。
- 我们通过偏移量获取启用了分页,并确保我们点击了正确的索引。 强制要求客户端
- 应用程序仅允许提取一定数量(并非一次性全部提取)。只允许仓储应用程序,但在非高峰时间(即凌晨 2 点)再次允许
- 索引可以发挥魔力,如果读取操作是优先级。
- 此外,我们还进行了存档,可将超过 2 年的记录移动到存档表中。这使我们桌子的大小几乎保持不变。
我想而不是问你在做什么,这对我来说不是 100% 清楚,因为有几个问题。我想分享我们如何实现绩效。同样,这不是完全证明的;但是,适用于我们的情况。对你来说,其他东西可能会起作用。