Hyperf微服务——一、认识微服务
一、Hyperf是什么?
以下内容摘自Hyperf官方文档
Hyperf 是一个高性能、高灵活性的渐进式 PHP 协程框架
Hyperspeed + Flexibility = Hyperf,从名字上我们就将 超高速 和 灵活性 作为 Hyperf 的基因。
对于超高速,我们基于 Swoole 协程并在框架设计上进行大量的优化以确保超高性能的输出。
对于灵活性,我们基于 Hyperf 强大的依赖注入组件,组件均基于 PSR 标准 的契约和由 Hyperf 定义的契约实现,达到框架内的绝大部分的组件或类都是可替换的。
基于以上的特点,Hyperf 将存在丰富的可能性,如实现 Web 服务,网关服务,分布式中间件,微服务架构,游戏服务器,物联网(IOT)等。
传统FPM进程同步阻塞框架
传统框架的并发受限于php-fpm进程数量。
从理论的角度上说php-fpm进程数越多越好。但是。。。。现实上 php-fpm的进程数会受到你的内存大小的限制。
一般情况下我们 进程数 =用机器内存(M)除以2 再除以20(M);例如8G内存可以有204个进程数。
如果是独立的php服务器还好,如果服务器上还有其他消耗内存的程序如mysql等。那可以分配给php的内存就更少。而且每一个进程都是同步阻塞调用。还有一些mysql的长连接占用进程。所以这也限制了传统框架的并发吞吐量。
Hyperf协程异步非阻塞框架
协程是一种轻量级的线程,由用户代码来调度和管理,而不是由操作系统内核来进行调度,也就是在用户态进行。
swoole实现的协程是一种IO多路复用的模式。通过worker进程的协程调度器来调用进程内的协程资源,当协程遇到IO等待就自动切换协程,然后通过轮询的方式反复处理协程切换和执行。
worker进程内是以单线程的形式运行协程,同一时刻只有一个协程在运行。 和redis的单线程模式基本一致。通常worker进程数与cpu核心数一致或2倍。进程内携程数默认100000。
所以如果协程内代码出现阻塞,则协程调度器无法进行协程切换,并发量会退化到进程数。官方提供了很多协程客户端,如mysql,redis等。但是mongodb目前还没有协程客户端,所以如果使用mongodb查询会降低并发。
另外传统的php框架一个进程只有一个请求,而hyperf协程框架一个进程有多个协程,协程间的通信是通过上下文 context实现的,不能使用全局变量,否则数据会乱。微服务间的一些共享参数,比如用户信息,token等可以通过上下文传输。
二、为什么用微服务
微服务就是一些协同工作的,小而自治的服务
微服务的优点
- 业务解耦
随着需求迭代的增加,业务场景越发复杂臃肿。对单个模块或设计多个模块的功能开发难度也逐步提升,效率逐渐下降。也会出现很多耦合的业务和代码。根据业务线场景进行服务拆分,一方面可以根据组织结构进行弹性变动;一方面可以独立业务场景,对业务线的梳理更清晰、需求迭代的效率增加、难度降低、影响面缩小。 - 性能提升
通过协程框架代替传统FPM框架极大提高系统吞吐量和接口并发。通过rpc调用的方式代替http请求,可以降低传输数据大小,加快传输速率,减少请求时间。 - 独立部署
单个服务可以独立开发和部署,降级因为某个需求的迭代或改动引起一些列衍生问题的概率,并降低影响面。 - 弹性重构
通过服务独立的降级、限流、熔断等方式减少不必要的因为运维或开发问题引起的系统全面瘫痪。可针对不同服务的功能、作用、承载量等多个方面进行弹性设置。可以较少业务重构的困难,降低重构的影响面。让重构更容易。
微服务的缺点
- 对运维的能力有一定要求,并且运维复杂程度要远高于单体应用
- 可能会出现一系列单体应用不会出现的问题,如数据混乱、内存溢出、协程问题等等
HTTP和RPC
OSI网络七层模型第一层:应用层。定义了用于在网络中进行通信和传输数据的接口;第二层:表示层。定义不同的系统中数据的传输格式,编码和解码规范等;第三层:会话层。管理用户的会话,控制用户间逻辑连接的建立和中断;第四层:传输层。管理着网络中的端到端的数据传输;第五层:网络层。定义网络设备间如何传输数据;第六层:链路层。将上面的网络层的数据包封装成数据帧,便于物理层传输;第七层:物理层。这一层主要就是传输这些二进制数据。
HTTP:
基于HTTP协议,在应用层,包含了大量头信息,在接口调用中,大量信息没有利用价值,对信息的可读性要求也不高,建立连接需要三次握手,四次挥手,浪费时间。因为服务前引入了网关增加了可读性,所以服务间调用尽量精简、快速。
RPC:
远程过程调用,基于TCP传输层,安全性高。减少了不必要的层级包装和头信息,较少报文体积,牺牲了信息的可读性提升信息传输的效率。以本地调用的方式调用其他服务的方法。可以跨语言。
RPC调用过程: 1. 客户端以本地调用方式调用客户端存根。 2. 客户端存根将服务信息、调用方法、参数等组装打包成一个消息体并消息体序列化为二进制。 3. 客户端存根发送消息体给指定服务端。 4. 服务端存根接收到消息,并反序列化解包消息体。 5. 服务端存根根据解码信息调用服务端本地方法。 6. 服务端本地执行并返回给服务端存根。 7. 服务端存根序列化打包消息体为二进制。 8. 服务端将消息体发送给客户端。 9. 客户端存根接收消息体并反序列化解包。 10. 客户端得到结果。
三、服务治理
服务注册与发现
consul一个去中心化用于实现分布式系统的服务注册与发现配置。提供一下功能服务:
- 服务健康与检查
- 服务注册与发现
- 自身监控
- Key/Value 存储
- 多数据中心
- web管理界面
- 集群
consul工作原理:
服务启动时,会向consul发送一个post请求,提供自己的IP和PORT。一般一个服务会创建两个以上节点。
consul接收到服务发送的请求,每隔固定时间向服务发送一个心跳检测的请求,检测服务是否健康可用。
如果服务的某一个节点不可用,当服务调用端的请求过来时,会通过选举的方式选出新的leader节点供服务端调用。
服务重试
因为网络的不稳定性,可能会出现不可控的非业务错误的不可调用。如果没有重试机制,会出现一直请求消耗服务器资源造成雪崩。
通过限制请求的重试次数和间歇时间,比如每个请求最多重试3次,间歇0.2s。
重试策略:
- 最大尝试次数
- 错误分类 通过错误类别判断是否可以重试
- 回退 资源耗尽后执行备选方法
- 睡眠
- 超时
- 熔断 重试失败会标记为熔断,不再进行重试
- 预算 通过注解提前生成一个令牌桶,重试前要消耗令牌数量,没有则不能重试
服务熔断与降级
避免因为某个服务不可用导致整个系统雪崩的处理方案。
例如秒杀活动的高并发造成商品服务不可用,因为没有降级服务导致所有调用商品服务的服务全部不可用,甚至系统全面瘫痪。以弃车保帅的方式在遇到突发流程或高并发流量的场景下,保证系统大部分功能可用。
通过注解设置熔断超时时间和失败次数进行熔断,熔断后降级到fallback方法返回数据,不再请求响应服务。
为指定方法设置熔断策略,比如请求超时0.05s,请求失败计数3次,则启动熔断。直接返回降级方法的结果
服务限流
通过注解对指定方法增加限流策略,避免一些并发高的接口因为一些突发流量和高流量下不可用。通过限流策略抛弃一些流量来保证接口可用性。
常用的限流策略:
- 计数器
比较粗暴,一段时间内对请求次数进行计数,与阀值进行比较判断是否需要限流,到达时间临界点,计数器清零。 无法承受瞬间突发流程 - 漏桶
固定容量的漏桶,固定速率流出水滴,但是对进度进入水滴的流速没有限制,水满则溢,请求被丢弃。无法精确评估水滴流出的速度。无法承受大流量和突发流量 - 令牌桶
固定容量的桶,桶可以是空的也可以是装满令牌的。以固定速率填充令牌,到达容量后,多余令牌被丢弃。每个请求过来,匹配相应数量的令牌,没有令牌则丢弃。
调用链追踪
阿里云日志,请求通过nginx访问到网关,网关为每一个请求创建一个唯一id,放入context上下文中,服务调用链全部带上日志id,通过id在阿里云日志可以查看完整的请求调用链,可以快速定位错误。
服务监控
通过一些可视化工具监控服务的内存、cpu、mysql、redis等指标性能。
自动化运维
关于运维方面可以了解学习k8s相关内容。
来源地址:https://blog.csdn.net/LuckyStar_D/article/details/125317201