用Docker Compose在HAProxy负载平衡器后面运行多个DBMS和C#容器。用不同数量的实例测试扩展性

在 上一篇文章,你创建了一个微服务架构,并手动实现了应用层数据库分片。
现在,你将扩展应用程序并运行微服务和数据库的多个容器实例。你将使用Docker Compose和一个HAProxy负载平衡器。

然后你运行JMeter负载测试,看看在使用 不同数量的实例时,应用程序的扩展情况。最后,您还将发布和接收来自RabbitMQ的消息。
1.运行多个数据库和微服务实例
Dockerize微服务
使用 上一篇文章中的代码和环境 作为基础。
将Visual Studio Project-Explorer中的文件 "Dockerfile "重命名为 "dockerfile"(第一个字符小写)。然后右键单击dockerfile,选择"创建 Docker 镜像”.这也将把图像推送到docker。
在Docker中运行应用程序
创建文件_docker-compose.yml_。
该docker文件配置了3个数据库容器和4个_Post_ 服务的实例。目前,只有2个数据库被_Post_ 服务实例所使用。你以后可以删除注释以使用第三个数据库。一个HAProxy负载平衡器在5001端口暴露_Post_ 服务容器。
每个容器有0.5的CPU限制,以帮助在本地机器上进行实际的负载测试。在我的12核笔记本上,仍有未使用的资源,因此,增加更多的服务和数据库实例可以带来好处。
启动应用程序
C:\dev>docker-compose up -d

启动数据库
在http://localhost:5001/swagger/index.html,打开你的浏览器
用至少100个用户和10个类别启动数据库。
你可以创建更多的用户和类别,但由于CPU的限制,这将需要一些时间。

2.用JMeter对扩展的应用程序进行负载测试
创建JMeter测试计划
安装 并打开 JMeter.
创建一个测试计划和一个线程组。

32个线程是一个好的开始数字。在一个线程的每个循环中,它添加一个帖子并读取10个帖子。
添加一个HTTP请求来创建一个帖子。

- 服务器名称:localhost
- 端口:5001
- HTTP-Request:POST
- 路径。/api/Posts
- 主体数据。
{
它为一个随机的用户(ID 1-100)和类别(1-10)创建一个帖子。
在请求中添加一个 Content-Type application/json HTTP header到请求中。

读取一个随机类别的10个帖子。

- 服务器名称:localhost
- 端口:5001
- HTTP-Request:GET
- 路径。/api/Posts
- 随请求发送参数。
NAME | VALUE | CONTENT-TYPE
运行测试
在测试运行时看一下_总结报告_。

应该没有错误。
等待一段时间,直到_平均_ (响应时间)和_吞吐量_ 的值变得稳定。
修改测试参数
在JMeter中停止测试。
你可以改变测试计划中的线程。把它们增加到例如64或128个线程。或者把线程减少到16个,甚至1个。
在编辑_docker-compose.yml_之前,关闭应用程序。
C:\dev>docker-compose down
你可以通过 "scale"属性改变_后期_ 服务实例的数量。改变数据库数量的 "环境"属性(添加/删除注释)。

在你的改变之后,启动应用程序。
C:\dev>docker-compose up -d
需要一些时间,直到数据库服务器运行。并记住要初始化数据库。

3.测试结果示例
**在我的电脑上,两个职位服务和一个数据库的比例可以得到很好的结果。**我可以把它扩展到六个服务和三个数据库,直到我达到硬件的极限。平均时间保持在500ms以下。将线程数增加到64以上会产生错误。
这些结果取决于我的环境和CPU的限制。在你的机器上也会有所不同。

每秒的吞吐量与实例的数量成正比。

在CPU有限的情况下,每秒305个请求,每天大约有2500万个请求。这将允许100万用户每天写10个帖子和阅读帖子。当然,现实生活中的应用会更复杂,但我希望这个例子能说明基本的想法。
4.微服务间的通信和复制用户的变化
Post 服务通过Rabbitmq消息接收来自_User_微服务的用户变更。

您也将用JMeter来模拟这一点。
创建 RabbitMQ 容器
发布以下命令(在控制台窗口中的一行)以启动具有管理 UI 的 RabbitMQ 容器。
C:\dev>docker run -d -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_USER=test -e RABBITMQ_DEFAULT_PASS=test --hostname my-rabbit --name some-rabbit rabbitmq:3-management
该命令将_"test_"配置为用户和密码,而不是默认的 Guest_凭据_ 。Guest 被限制在 localhost,但在 docker 内,容器在不同的主机上。
修改 Post 微服务
在 Visual Studio 中安装_RabbitMQ.Client_NuGet 包。
添加_IntegrationEventListenerService_ 类。
后台服务使用_"test_"帐户来访问 RabbitMQ,并使用 host_.docker.internal 和_ localhost 作为 主机。这允许从容器内部和 Visual Studio 调试器进行连接。
单个活动消费者保证只有一个_Post_ 服务实例接收消息。
如果活动实例崩溃了,那么下一个实例将接管。你以后可以通过在docker中停止当前接收实例来尝试。
该代码创建了交换和管道,如果它们还不存在的话。它使用手动确认。
修改_Startup.cs_以运行IntegrationEventListenerService。
在Docker中运行改变后的微服务
在docker中关闭应用程序 。
C:\dev>docker-compose down
构建_Post_ 服务,将其dockerize并发布到docker。
在你的改动之后启动应用程序。
C:\dev>docker-compose up -d
这需要一些时间,直到数据库服务器运行。并记住要初始化数据库。

修改JMeter测试
在JMeter测试计划中添加一个只有一个线程的线程组。

添加一个恒定的定时器。

恒定的定时器将测试限制在每秒一条消息。
每秒一条消息还是很频繁的。即使在半年内有1,000,000个用户注册,也只是每分钟4个新用户。
添加 HTTP 请求以将消息发布到 RabbitMQ。

- 服务器名称:localhost
- 端口:15672
- HTTP-Request:POST
- 路径。/api/exchanges/%2F/userloadtest/publish
- 身体数据。
{
用户实体有一个版本字段来处理失序的消息。为了保持测试的简单性,它只更新一个用户并增加版本字段。性能影响应该保持不变。
为_内容类型_和对 RabbitMQ 的授权添加一个 HTTP 头管理器。

Content-Type | application/json
"dGVzdDp0ZXN0 "是base64编码的用户和密码 "test"。
运行测试
吞吐量应该与之前的测试类似。
您还可以通过查看控制台输出来识别 docker 中的活动 RabbitMQ 消费者。您可以停止该容器,另一个实例将接管。
5.最后的思考和展望
您创建了一个微服务架构并实现了应用层数据库分片。然后你用多个容器实例扩展了应用程序并对其进行了负载测试。您还处理了来自 RabbitMQ 的用户变更事件。
这只是一个示例应用程序。您将不得不调整代码,以便在生产环境中使用它。
下一步是什么?获取像拥有最多帖子的前 10 个类别的数据需要查询多个数据库实例。这可能会导致延迟并扼杀性能。Redis可以成为查询聚合数据的一个解决方案。我将在下一篇文章中展示它。
你也可以在Kubernetes中运行该应用程序。参见我的其他文章。
如果你有任何问题、想法或建议,请联系我。
如何扩展ASP.NET Core微服务和散列式数据库。用JMeter进行负载测试最初发表在ITNEXT的Medium上,人们在这里通过强调和回应这个故事来继续对话。