swoft-个基于Swoole原⽣协程的PHP微服务框架
刚才百度了⼀下swoft框架,官⽹打不开了,仓库也暂停了。不由感慨。曾经和同事踩了许多坑使⽤此极其⼩众的框架完成微服务项⽬。使⽤它的唯⼀⽬的就是提⾼程序性能(底层使⽤了协程),为此⼤家都学习了很多新知识,解决很多百度都百度不到的问题,赶上了⼀波docker微服务的潮流。更有同事搭建了k8s集作为测试环境(相当复杂)。虽然团队规模不⼤,但是这个项⽬做的可以说是相当规范了。值得欣慰的是项⽬性能达到了预期,堪称精美。随着疫情的冲击,项⽬的商业价值渐渐没落。在运⾏了两年之后下线了,但没有想到的是如今swoft看起来也是⽆法使⽤了。所以码农翻⾝的作者说的对,我们应该把80%时间⽤在不变的基础⾥。追求新技术可能是⼀种赌注。但不管怎么说,这个框架的设计初衷是⾮常理想化的,可能是使⽤的复杂性过⾼导致⽤户太少,失去了⽣命⼒。即使只是昙花⼀现,它也曾闪过光!相信它的设计理念⾥还是有很多有价值可供未来借鉴的部分。
基于swoole 4.0全新的PHP编程模式
上⾯是⼀段PHP代码,其中2个函数的执⾏时间都是1秒,整段代码执⾏完成需要2秒。要想将这种串⾏执⾏⽅式转换为并⾏执⾏,在PHP中可以通过创建多进程来执⾏每个函数,单个进程执⾏单个函数,这样在1秒钟能就能执⾏完上⾯的代码。虽然在Java中多线程应⽤很普遍,但是很可惜PHP并不⽀持多线程。
除开多线程和多进程,还有⼀种⽅式也能实现并⾏编程,那就是协程(Coroutine),这也是GO语⾔的重要特性。协程的并发量相对多线程和多进程要⾼出很多,同⼀个进程内可以创建⼏⼗万甚⾄上百万个协程,且只占⽤少量的内存空间。线程和进程由操作系统调度,是⾮常昂贵的系统资源,创建过多的话,在上下⽂保存和进⾏切换的开销上会很⼤。
这⾥将前⾯的代码以协程的形式进⾏了重写,执⾏的时候会创建两个协程,执⾏时间为1秒。虽然执⾏效果和多进程或多线程⼀样,但实现原理有所不同。协程中这两个函数的执⾏基于⼀种⾃动让出的机制,⼀旦执⾏函数遇到IO操作,就会⾃动让出当前执⾏栈交由下⼀个函数执⾏,在IO完成之后再恢复协程栈。
PHP由于⾃⾝的天然缺陷⽆法⽀持多线程,所以我们绕开了它直接在swoft 4.0中实现了协程。但由于针对CPU密集操作只能利⽤到⼀个核,所以在使⽤协程的时候还是会利⽤多进程的⽅式来复⽤CPU的多核操作。
协程最⼤的好处在于能够提供极⼤的并发,因为它仅占⽤内存,不存在进程/线程切换开销,单个进程就可开启50w个协程。
php支持多线程吗我们在swoft 1.0的时候采⽤的技术⽅案和node.js的异步回调⼀样,在2.0的时候开始尝试实现协程,但是存在⼀些缺陷——协程不能⽤在所有的函数上,只能⽤在⼀些已经预定好的函数上。这是由于PHP
有⼀些动态的特性,⽐如将URL映射到⼀个类⽅法上,这种场景下执⾏2.0的协程程序就会崩溃。4.0的时候我们对此做了⼀些优化,基于开源的库重新实现了协程⽅案,这时的协程就达到了在Go语⾔中的效果。
上⾯展⽰的就是PHP中使⽤协程的三种⽅式。左上的代码通过循环的⽅式创建了10个协程,下⾯这段则是在协程中执⾏读⽂件的操作,且内部还嵌套了两个协程,它们之间是相互依赖的关系。右边的代码直接创建了3个协程,每个协程的执⾏逻辑都不⼀样。
有了协程之后,就会涉及到如何管理协程或数据通信的问题。在Java多线程中,线程之间的通信可能会使⽤锁或者数据结构的⽅式解决,在协程编程中⼀般使⽤的chan的⽅式管理。
协程是⼀个⽤户态的线程,同⼀时间执⾏的协程只有⼀个。这⼀点和多线程不同,创建出来的多个线程都会并⾏执⾏。
左边这段代码是协程编程,它会读取⼀个全局的数组,当协程1读取数组的时候,协程2其实没有运⾏,直到协程1遇到IO操作释放了控制权,协程2才会恢复再去读全局变量,这样就完全不⽤加锁了。
右边是线程编程,可以看到如果程序要读取全局临界资源就⼀定要加锁,要不断的lock、unlock。
Chan有点类似队列,不过它⾃带了协程调度能⼒。
多线程读取队列时,会有⽣产者和消费者。在队列内存占⽤过多⽆法再写⼊的情况下,⽣产者还是会持续写⼊,⼀般的解决⽅案是进⾏盲等,⽐如让⽣产者sleep⼀段时间然后再去写⼊。在队列⽆数据可返回的情况下,⼀种⽅案是让消费者盲等,CPU死循环去等待,不过这样会占满CPU。⼀般的⽅案是在发现⽆数据返回的时候sleep⼀段时间,之后再尝试读取。
协程编程中可以通过chan来完成协程调度。当⽣产者发现容量不⾜的时候会展⽰挂起当前协程,直到有消费者拿⾛⼀些数据之后才会唤醒这个协程。消费者的读取机制也是⼀样的,⽆可⽤数据时就挂起,⼀旦⽣产者push数据后再唤醒。
由于PHP的动态语⾔特性,所以可以向chan中push任意的PHP变量,⽆论是对象还是数组。Chan的底层基于引⽤计数管理,完全没有内存拷贝,除了标量类型是直接复制之外,包括数组、对象这些复杂的数据结构都是⽤的引⽤计数管理。像Go语⾔⼀样,我们也提供了chan::select⽤来对多个chan进⾏读写判读。
协程框架swoft的介绍
Swoft是基于协程实现的web开发框架。它借鉴了spring Cloud做了完全组件化的实现,⾥⾯很多功能都是⼀个⼩的组件,当然也可以⽤⾃定义的组件替换内置的组件。该框架也提供了依赖注⼊、容器、连接池、AOP,除了应⽤在web领域之外,还能够⽤在微服务上。
上⾯两⾏命令分别是⽤来创建swoft⼯程和引⼊相关组件。
⽬前swoft⽀持3种服务器,swoft-http-srever 、swoft-websocket-server swoft-rpc-server。第⼀个⽤来做主流的web应⽤程序,第⼆个是长连接通信服务,最后是微服务领域的RPC服务。
通过命令⾏脚本能够直接启⽤以上3种服务,这⾥也提供了⼀些常⽤的脚本⼯具。
Swoft参考Java的Spring框架,⽤了很多注解编程的⽅式。对于Web开发中的URL映射,可以直接通过注解的⽅式写Route。能够⾃动将URL映射到当前Controller⽅法中,URL中的参数也会⾃动带⼊类⽅法中。
基于swoft协程框架进⾏PHP微服务治理
Swoft⾃带了⼀些微服务常⽤的组件,包括服务注册、熔断、降级、、接⼝多版本等。
Swoft的服务注册与发现是基于Google开源的consul,要使⽤consul需要添加⼀些配置,定义服务提供⽅和接⼊⽅的key。然后在前⾯提到的命令⾏脚本调⽤RPC start就会⾃动将我们的服务器节点注册到consul服务器中。
Swoft的接⼝声明也是基于注解的⽅式,如上图所⽰通过注解定义了service指向的服务以及调⽤的接⼝,
调⽤的时候会映射到对应的⽅法。swoft的熔断机制中失败超过⼀定次数,服务就关闭,成功的话,服务重新连接。
这段代码是关于熔断器的调⽤,⾸先确定熔断器的名词,正常情况下调⽤handler,失败的话就调⽤fallback进⾏⼀些处理。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论