如何使用PHP实现微服务?

斯沃夫特


为什么要谈服务治理?


随着Internet的日益普及,随着应用程序规模的不断扩大,传统的MVC架构变得越来越肿,并且很难维护。


我们需要采取行动,根据业务特征将一个大型系统拆分为多个应用程序。 例如,大型电子商务系统可能包括用户系统,产品系统,订单系统,评估系统等,我们可以将它们分为多个单独的应用程序。 多应用程序体系结构的特征是应用程序独立运行,并且无法相互调用。


尽管多个应用程序解决了过大的应用程序问题,但是这些应用程序彼此独立,并且公共服务或代码无法重用。




对于大型Internet系统,它通常包含具有公共服务的多个应用程序,并且每个应用程序之间都有呼叫关系。 此外,大型Internet系统还面临其他挑战,例如如何应对快速增长的用户,如何管理研发团队以快速迭代系统开发,如何以稳定的方式保持系统升级等等。


因此,为了很好地重用服务并维护易于扩展的模块。 我们希望将服务与应用程序分开。 服务不再位于应用程序中,而是作为单独的服务维护。 应用程序本身不再是庞大的模块堆栈,而是模块化的服务组件。


服务化


特色功能


那么使用“服务化”的功能是什么?


  • 应用程序按业务划分为服务
  • 个别服务可以独立部署
  • 服务可以由多个应用程序共享
  • 服务之间可以相互通信
  • 系统架构更加清晰
  • 核心模块是稳定的,单元中服务组件的升级可以避免频繁发布新版本的风险
  • 易于开发和管理
  • 维护工作可由具有明确工作流程和职责的单个团队完成
  • 服务重用,代码重用
  • 非常容易扩展

服务化的挑战


系统服务化后,系统的依存关系变得复杂,服务之间的交互次数也随之增加。 在fpm的开发模式下,由于无法提供常驻内存,因此每个请求必须从零开始,方法是开始加载进程以退出该进程,从而增加了许多无用的开销。 另外,数据库连接不能重用,也不能受到保护,因为fpm是基于进程的,而fpm进程的数量也决定了并发的数量。 这些是简单的fpm开发给我们带来的问题。 因此,这就是Java.NETPHP相比现在在Internet平台中更受欢迎的原因。 除了PHP non-memory resident ,还有许多其他问题需要解决。


  • 更多服务,更复杂的配置管理
  • 复杂的服务依赖性
  • 服务之间的负载平衡
  • 服务扩展
  • 服务监控
  • 服务降级
  • 服务认证
  • 在线和离线服务
  • 服务文件
    ......

您可以想象常驻记忆带给我们的好处。


  • 一旦我们可以集中精力处理请求,就只能启动框架初始化,因为框架只能在启动时在驻留内存中一次在内存中初始化


  • 连接多路复用 ,如果不使用连接池,一些工程师将无法理解,为每个请求建立连接的结果是什么? 它导致连接中的后端资源过多。 对于某些基本服务(例如Redis),数据库而言,连接是昂贵的工作。



那么,有没有好的解决方案? 答案是肯定的,许多人正在使用名为Swoft的框架。 Swoft是具有Service Governance功能的RPC框架。 Swoft是第一个PHP常驻内存协程全栈框架,基于Spring Boot的核心概念,约定大于配置。


Swoft提供了一种更优雅的方式来使用诸如Dubbo类的RPC服务,并且Swoft的性能与Golang相似。 这是PC发生的Swoft性能压力测试结果。

斯沃夫特


ab压力测试的处理速度非常惊人。 使用i7 generation 8 CPU和16GB内存, 100000请求仅使用5s 。 在fpm开发模式下,基本上不可能实现该时间。 该测试也足以证明Swoft高性能和稳定性。


优雅的服务治理


服务注册和发现


在微服务治理过程中,通常会注册启动到第三方集群的服务,例如consul / etcd。 本章使用Swoft框架中的swoft-consul组件来实现服务注册和发现。
斯沃夫特
实施逻辑


 <?php declare(strict_types=1); namespace App\Common; use ReflectionException; use Swoft\Bean\Annotation\Mapping\Bean; use Swoft\Bean\Annotation\Mapping\Inject; use Swoft\Bean\Exception\ContainerException; use Swoft\Consul\Agent; use Swoft\Consul\Exception\ClientException; use Swoft\Consul\Exception\ServerException; use Swoft\Rpc\Client\Client; use Swoft\Rpc\Client\Contract\ProviderInterface; /** * Class RpcProvider * * @since 2.0 * * @Bean() */ class RpcProvider implements ProviderInterface { /** * @Inject() * * @var Agent */ private $agent; /** * @param Client $client * * @return array * @throws ReflectionException * @throws ContainerException * @throws ClientException * @throws ServerException * @example * [ * 'host:port', * 'host:port', * 'host:port', * ] */ public function getList(Client $client): array { // Get health service from consul $services = $this->agent->services(); $services = [ ]; return $services; } } 

服务断路器


在分布式环境中,尤其是在微服务体系结构的分布式系统中,一个软件系统调用另一个远程系统是很常见的。 这样的远程呼叫的被叫方可以是另一个进程,也可以是网络上的另一个主机。 此远程呼叫与进程的内部呼叫之间的最大区别是,远程呼叫可能会失败或挂起。 超时前无响应。 更糟糕的是,如果有多个调用方调用同一个挂起的服务,则服务的超时很可能迅速传播到整个分布式系统,从而导致连锁反应,从而消耗整个分布式系统中的大量资源。 最终,它可能导致系统瘫痪。


断路器模式旨在防止由分布式系统中此类类似瀑布的连锁反应引起的灾难。



在基本断路器模式下,要确保在断路器处于打开状态时不呼叫供应商,但是在供应商恢复服务后,我们还需要其他方法来重置断路器。 一种可能的解决方案是断路器定期检测供应商的服务是否恢复。 恢复后,状态将设置为关闭。 当断路器重试时,该状态为半开状态。


保险丝的使用既简单又强大。 可以使用@Breaker进行注释。 Swoft的保险丝可以在任何情况下使用,例如服务被调用。 请求第三方服务时,它可以降级或不调用。


 <?php declare(strict_types=1); namespace App\Model\Logic; use Exception; use Swoft\Bean\Annotation\Mapping\Bean; use Swoft\Breaker\Annotation\Mapping\Breaker; /** * Class BreakerLogic * * @since 2.0 * * @Bean() */ class BreakerLogic { /** * @Breaker(fallback="loopFallback") * * @return string * @throws Exception */ public function loop(): string { // Do something throw new Exception('Breaker exception'); } /** * @return string * @throws Exception */ public function loopFallback(): string { // Do something } } 

服务限制


流量限制,断路器,服务降级这些可以重复强调,因为它们确实很重要。 当该服务无法正常工作时,必须将其断开。 流量限制是一种自我保护的工具。 如果没有自我保护机制,无论连接数多少,都可以接收到,那么当流量非常大时,前端肯定会挂起,而后端却无法处理所有连接。


流量限制是为了限制访问闪速销售商品等稀缺资源时的并发数量和请求数量,从而有效地削减峰值并平滑流量曲线。 流量限制的目的是为了限制并发访问和并发请求的速率,或者将请求的速度限制在一个时间窗口内以保护系统。 一旦达到或超过速率限制,就可以拒绝请求或将请求排队。


Swoft流量限制的最Swoft使用令牌桶算法,底层依赖Redis来实现分布式流量限制。


Swoft流量限制不仅限制了控制器,还限制了任何bean中的方法,并控制了方法的访问率。 以下示例是详细说明。


 <?php declare(strict_types=1); namespace App\Model\Logic; use Swoft\Bean\Annotation\Mapping\Bean; use Swoft\Limiter\Annotation\Mapping\RateLimiter; /** * Class LimiterLogic * * @since 2.0 * * @Bean() */ class LimiterLogic { /** * @RequestMapping() * @RateLimiter(rate=20, fallback="limiterFallback") * * @param Request $request * * @return array */ public function requestLimiter2(Request $request): array { $uri = $request->getUriPath(); return ['requestLimiter2', $uri]; } /** * @param Request $request * * @return array */ public function limiterFallback(Request $request): array { $uri = $request->getUriPath(); return ['limiterFallback', $uri]; } } 

这支持symfony/expression-language表达式。 如果速度受到限制,则会调用fallback定义的limiterFallback方法。


配置中心


在讨论配置中心之前,让我们讨论配置文件。 我们对此并不陌生。 它为我们提供了动态修改程序的能力。 某人的报价是:


动态调整系统运行时的飞行姿态!

我可以称我们的工作为快速飞行的飞机修理零件。 我们人类总是无法控制和预测一切。 对于我们的系统,我们总是需要保留一些控制线,以便在需要时进行调整,以控制系统方向(例如,灰度控制,流量限制调整),这对于包含变化的Internet行业尤其重要。


对于独立版本,我们将其称为配置(文件); 对于分布式集群系统,我们称其为配置中心(系统);


分布式配置中心到底是什么?


随着业务的发展和微服务体系结构的升级,服务的数量和程序的配置不断增加(各种微服务,各种服务器地址,各种参数),以及传统的配置文件方法和数据库方法。无法满足开发人员在配置管理中的需求:


  • 安全性:配置遵循存储在代码库中的源代码,很容易导致配置泄漏;
  • 及时性:修改配置并重新启动服务以使其生效。
  • 局限性:不支持动态调整:例如,日志开关,功能开关;

因此,我们需要配置中心来管理配置! 使业务开发人员摆脱复杂繁琐的配置,他们只需要关注业务代码本身,就可以大大提高开发和运营效率。 同时,该软件包的配置和发布将进一步提高发布的成功率,并为微调控制以及操作和维护的紧急处理提供有力的支持。


关于分布式配置中心,网络上有许多开源解决方案,例如:


Apollo是由携程的框架部门开发的分布式配置中心。 它可以集中管理不同环境和不同应用程序集群的配置。 修改配置后,可以实时将其推送到应用程序端。 它具有标准化权限和流程管理的功能,并且适用于配置和管理微服务的场景。


本章以Apollo为例,从远程配置中心提取配置并保护重启服务的安全。 如果您不熟悉Apollo ,则可以首先查看Swoft扩展Apollo组件并阅读Apollo官方文档。


本章以Swoft中的Apollo为例。 当Apollo配置更改时,重新启动服务(http-server / rpc-server / ws-server)。 以下是代理的示例:


 <?php declare(strict_types=1); namespace App\Model\Logic; use Swoft\Apollo\Config; use Swoft\Apollo\Exception\ApolloException; use Swoft\Bean\Annotation\Mapping\Bean; use Swoft\Bean\Annotation\Mapping\Inject; /** * Class ApolloLogic * * @since 2.0 * * @Bean() */ class ApolloLogic { /** * @Inject() * * @var Config */ private $config; /** * @throws ApolloException */ public function pull(): void { $data = $this->config->pull('application'); // Print data var_dump($data); } } 

上面是一个简单的Apollo配置请求,除了这种方法外, Swoft-Apollo还提供了更多使用方式。



Source: https://habr.com/ru/post/zh-CN460855/


All Articles