在应用中添加第二台服务器的 7 个技巧
最后更新于 作者: Luis Dalmolin
向您的应用添加第二台服务器可以成为提高应用性能和/或增强其可靠性的好方法。但是,在添加第二台服务器时,您需要牢记一些事项。
在本文中,我们将讨论在将附加服务器添加到您的应用时需要考虑的关键事项。我们将使用托管在 Laravel 中的 Laravel Forge 作为示例,但这些概念可以应用于任何类型的应用程序,甚至不限于 PHP 语言。
当前基础设施
首先,为了确保我们使用相同的语言,这是当前基础设施的概述。该应用程序目前运行在一台由 Laravel Forge 创建的服务器上,并运行在 AWS 上。
- Lets Encrypt 用于 SSL 证书;
- Redis(安装在机器上)用于会话、缓存以及作为队列驱动程序来存储和处理后台作业;
- MySQL(安装在机器上)作为数据库;
- 用于保存用户上传内容的本地文件夹;
- 每分钟使用服务器的 CRON 运行 Laravel 计划程序;
- 部署是通过单击 Laravel Forge 的“立即部署”按钮手动触发的;
1. 负载均衡器
您首先需要一个负载均衡器。这将是您的应用程序的入口点,这意味着您将您的域名 DNS 指向负载均衡器,而不是直接指向服务器。负载均衡器的作用是,正如您所猜测的,在所有正常运行的已注册服务器之间平衡传入请求。
从现在开始,每当我们提到“应用服务器”时,它将指的是运行我们的 Laravel 应用程序的单个服务器。
负载均衡器的一个不错的功能是健康检查,它用于确保所有连接的服务器都是正常的。如果其中一台服务器由于某种原因(例如,计划外的维护)发生故障,则负载均衡器将停止将请求路由到该服务器,直到该服务器重新启动并恢复正常运行状态。
我们建议使用应用程序负载均衡器,它在将来可以提供更强大的功能,如果您需要的话。应用程序负载均衡器可以根据请求的 URL 将流量路由到特定服务器,甚至将请求路由到多个应用程序。现在,我们将使用轮询法均匀地平衡流量。
由于您的域名现在将指向负载均衡器,因此您的 SSL 证书也应该在负载均衡器中,而不是在您的服务器中。
2. 数据库(MySQL)、缓存和队列(Redis)
目前,有一台服务器运行着我们的应用程序,以及 MySQL 和 Redis 的本地实例。当第二台服务器连接到我们的负载均衡器时会发生什么?
对我们的数据库和缓存层有多个真实来源可能会导致各种问题。使用多个数据库,用户会在一台服务器上注册,但在另一台服务器上不会注册。使用每台服务器一个 Redis 实例,您可以在应用服务器 1 上登录,但当负载均衡器将您重定向到应用服务器 2 时,您需要再次登录,因为您的会话存储在本地 Redis 实例中。
我们可以让应用服务器 2 或连接到我们负载均衡器的任何未来的应用服务器连接到应用服务器 1 的服务,但当应用服务器 1 需要停机维护或意外发生故障时会发生什么?添加第二台服务器的原因之一是为了获得更高的可靠性和可扩展性,但这并不能解决我们的问题。
当我们拥有多个应用服务器时,理想情况是让 MySQL 和 Redis 等外部服务运行在独立的环境中。要实现这一点,我们可以使用托管服务(例如 AWS RDS)来处理数据库,使用 AWS Elasticache 来处理 Redis,或者使用非托管服务,这意味着我们将设置独立的服务器来运行这些服务。如果成本不是问题,托管服务通常是更好的选择,因为您不必担心操作系统和软件的升级,而且它们通常具有更好的安全层。
假设我们决定为我们的应用程序使用托管服务。我们的 Laravel 配置将变得类似于以下配置
-DB_HOST=localhost+DB_HOST=app-database.a2rmat6p8bcx7.us-east-1.rds.amazonaws.com-REDIS_HOST=localhost+REDIS_HOST=app-redis.qexyfo.ng.0001.use2.cache.amazonaws.com
设置完成后,当我们将应用服务器连接到我们的服务时,我们的基础设施将如下所示。
3. 用户上传内容
我们的应用程序允许用户上传自定义个人资料图片,这些图片会在您登录时显示。在我们当前的基础设施中,图片会保存在我们应用程序的内部文件夹中,并且也会从该文件夹中提供服务。现在我们拥有多个应用服务器,这将是一个问题,因为在应用服务器 1 中上传的图片不会出现在第二台服务器上。
有几种方法可以解决这个问题。其中一种方法是在您的服务器之间共享一个文件夹(例如,Amazon EFS)。如果我们选择此选项,则需要在 Laravel 中配置一个自定义文件系统,该文件系统将指向我们应用服务器上的此共享文件夹位置。虽然这是一个有效的选项,但这需要您了解如何在服务器上设置磁盘,并且对于您设置的每个新服务器,您都需要再次配置共享文件夹。
我们通常更喜欢使用云对象存储服务,例如 Amazon S3 或 Digital Ocean Spaces。如果您使用的是 文件存储 选项,Laravel 使得与这些服务一起使用变得非常容易。在这种情况下,您只需将文件系统磁盘配置为使用 S3,并将所有以前的用户上传内容上传到一个存储桶。
-FILESYSTEM_DISK=local+FILESYSTEM_DISK=s3 AWS_ACCESS_KEY_ID=your-keyAWS_SECRET_ACCESS_KEY=your-secret-access-keyAWS_DEFAULT_REGION=us-east-1AWS_BUCKET=your-bucket-name
所有用户上传的内容都将存储在同一个集中式存储桶中。S3 内置了版本控制、多层冗余,并且我们添加到负载均衡器的任何其他应用服务器都可以使用同一个存储桶来存储内容。
如果您的应用程序将来发展壮大,您可以设置 AWS Cloudfront,它充当位于 S3 存储桶之上的 CDN 层,为您的用户更快地提供存储桶内容,并且通常比 S3 更便宜。
4. 队列工作者
在步骤 2 中,我们设置了集中式 Redis 服务器,这是我们用来管理应用程序队列的技术。这也适用于我们的负载均衡应用程序,但还有几个不错的选择可以探索。
如果您继续在您的应用服务器上处理队列,利用集中式 Redis 实例,则无需进行任何更改。作业将由拥有可用工作者来处理作业的服务器拾取。
另一种选择是使用像 AWS SQS 这样的服务,它可以通过将工作负载卸载到另一个服务来减轻应用程序增长时 Redis 实例的压力。
5. 计划命令
在负载均衡器后面运行多个服务器时,计划命令默认情况下将在连接到负载均衡器的每台服务器上运行,这不是最佳选择。不仅多次运行相同的命令会浪费处理能力,而且还会导致数据完整性问题,具体取决于该命令的功能。
Laravel 内置了一种处理这种情况的方法,通过链接 onOneServer() 方法,可以确保你的计划任务只在一个服务器上运行。
$schedule->command('report:generate') ->daily() ->onOneServer();
使用此方法需要使用集中式缓存服务器,因此步骤 2 对于使其工作至关重要。
6. 部署
在部署应用程序方面,现在你有许多选择和需要考虑的事项。
我们仍然可以使用以前的方法部署应用程序,但现在必须确保记得在两台服务器上都点击部署按钮。如果忘记,服务器将运行应用程序的不同版本,这会导致重大问题。
对于多台服务器,可能需要升级部署策略。有一些非常好的部署工具和服务,例如 Laravel Envoyer 或 PHP Deployer。这些类型的工具和服务允许你在多台服务器上自动化部署过程,从而消除人为错误。
如果我们想要在部署过程中更深入一层,因为现在有两台应用程序服务器,一个很大的好处是可以暂时从负载均衡器中移除其中一台服务器,该服务器将停止接收请求。这样可以实现零停机时间部署,我们先从负载均衡器中移除第一台服务器,部署新代码,然后将其重新加入负载均衡器,再移除第二台服务器并执行相同的过程。服务器 2 完成后,两台服务器都将具有新代码,并将连接到负载均衡器。为了实现这一点,可以使用像 AWS CodeDeploy 这样的工具,但设置比我们之前的选项更复杂。
部署是我们应用程序中非常重要的过程,因此如果能够使用 Github Actions 或任何 CI/CD 服务自动化部署,就可以极大地改进过程。使部署过程简单,让任何人都可以触发部署,真正体现了开发团队和应用程序的成熟度。
7. 网络和安全
使用负载均衡器带来的另一个好处是,我们的服务器不再是网站的入口点。这意味着我们只能让服务器在内部可访问和/或通过特定 IP(我们的 IP、负载均衡器 IP 等)限制访问。这极大地提高了服务器的安全性,因为它们不再直接可访问。对数据库和缓存集群也可以(也应该)这样做。
为了实现这一点,我们将只允许来自我们自己 IP 的端口 22 的流量(以便我们可以 SSH 到服务器),并且将只允许来自负载均衡器的端口 80 的流量,以便它可以向服务器发送请求。数据库和缓存集群也适用相同的规则。
最后的想法
在基础架构中添加其他服务器时,需要考虑很多事项。它增加了基础架构和工作流程的复杂性,但也提高了应用程序的可靠性和可扩展性,并改善了整体安全性。
从一开始就考虑这些建议,实施起来非常简单,并且可以对改善应用程序产生重大影响。
Luis 是 Kirschbaum 的高级开发人员,拥有超过 10 年的复杂应用程序架构经验,并且自 Laravel 4 早期就开始使用 Laravel。
除了 PHP 和 Laravel 之外,Luis 还擅长 VueJS/Javascript 和所有与 DevOps 相关的事情。他热爱使用开源软件,并为社区贡献了多个开源项目。
Luis 在 Feevale 大学教授 AngularJS 课程,在那里他还获得了互联网系统学位,并且将 Dayle Rees 撰写的 Laravel 图书“Code Bright”翻译成葡萄牙语。