Below you will find pages that utilize the taxonomy term “PHP”
Posts
使用Hyperf插入100万行数据到MongoDB,能行吗
最近用go搞了一个swoole的边车。是真的边车,用swoole process启动的。挂载到swoole server上跑,swoole起它起,swoole停它停,中间如果go挂了swoole还负责给拉起来。消息投递也照搬swoole task走IPC,从web worker上直接投递,等结果出来再返还web worker。
Posts
云原生Hyperf骨架包
2020-01-22 日更新:现已提供Hyperf Helm chart。详见repo。
Hyperf官方提供了容器镜像,配置选项又非常开放,将Hyperf部署于云端本身并不复杂。下面我们以Kubernetes为例,对Hyperf默认的骨架包进行一些改造,使它可以优雅的运行于Kubernetes上。本文不是Kubernetes的入门介绍,需要读者已经对Kubernetes有一定了解。
生命周期 容器在Kubernetes上启动以后,Kubernetes会对容器进行两项检查: Liveness Probe和Readiness Probe。Liveness Probe如果没有通过,容器会被重启,而Readiness Probe没有通过,则会暂时将服务从发现列表中移除。当Hyperf作为HTTP Web server启动时,我们只需要添加两条路由就行了。
<?php namespace App\Controller; class HealthCheckController extends AbstractController { public function liveness() { return 'ok'; } public function readiness() { return 'ok'; } } <?php // in config/Routes.php Router::addRoute(['GET', 'HEAD'], '/liveness', 'App\Controller\HealthCheckController@liveness'); Router::addRoute(['GET', 'HEAD'], '/readiness', 'App\Controller\HealthCheckController@readiness'); 在Kubernetes的deployment上配置:
livenessProbe:httpGet:path:/livenessport:9501failureThreshold:1periodSeconds:10readinessProbe:httpGet:path:/readinessport:9501failureThreshold:1periodSeconds:10 当然这里我们只是简单了返回‘ok’,显然不能真正检查出健康状况。实际的检查要考虑业务具体场景和业务依赖的资源。例如对于重数据库服务我们可以检查数据库的连接池,如果连接池已满就暂时在Readiness Probe返回状态码503。
服务在Kubernetes销毁时,Kubernetes会先发来SIGTERM信号。进程有terminationGracePeriodSeconds这么长的时间(默认60秒)来自行结束。如果到时间后还没结束,Kubernetes就会发来SIGINT信号来强制杀死进程。Swoole本身是可以正确响应SIGTERM结束服务的,正常情况下不会丢失任何运行中的连接。实际生产中,如果Swoole没有响应SIGTERM退出,很有可能是因为服务端注册的定时器没有被清理。我们可以在OnWorkerExit处清理定时器来保证顺利退出。
<?php // config/autoload/server.php // ... 'callbacks' => [ SwooleEvent::ON_BEFORE_START => [Hyperf\Framework\Bootstrap\ServerStartCallback::class, 'beforeStart'], SwooleEvent::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'], SwooleEvent::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'], SwooleEvent::ON_WORKER_EXIT => function () { Swoole\Timer::clearAll(); }, ], // .
Posts
Hyperf 注解整洁之道
注解是元编程的一种。元编程从字面意思上说就是编写程序的程序。和普通编程一样,注解在给我们带来便捷的同时,如果使用不当,也有可能造成可读性、可维护性下降等问题。
在某些注解中,可能有很多配置项,比如:
//这还不是一个特别夸张的例子 @CircuitBreaker(timeout=0.05, failCounter=1, successCounter=1, fallback="App\Service\UserService::searchFallback") 如果我们的代码里用很多这样复杂的注解,就会引发以下几个问题:
注解中可使用的数据类型表达能力有限,比如必须用方法的字符串全名来表达方法,容易出错。 离开了IDE的帮助,长注解的可读性变得很差。(比如在GitHub上) 同样配置的注解多个地方使用,修改时要改很多地方。 这里我向大家推荐通过继承的方式配置Hyperf内的注解。
下面是一个继承CircuitBreaker(熔断器)注解的例子。
<?php ... /** * @Annotation * @Target({"METHOD"}) * * Shorthand for CircuitBreaker(timeout=0.05, failCounter=1, successCounter=1, fallback="App\Service\UserService::searchFallback") */ class FooCircuitBreakerAnnotation extends CircuitBreakerAnnotation { /** * @var float */ public $timeout = 0.05; /** * @var string */ public $fallback = UserService::class.'::searchFallback'; /** * The counter required to reset to a close state. * @var int */ public $successCounter = 1; /** * The counter required to reset to a open state.
Posts
Purposed PHP Dialect: P++
The first time I saw P++ my reaction was “meh, it is not going anywhere”. Anything breaks backward compatibility and abandons existing user base will get punished eventually. Python community took a decade to heal from the wound caused by Python3. In short, I believe it is not worth it to trade backward compatibility for language design purity. I also wrote a blog about Vue3 changes on its new functional APIs.
Posts
Unboxing Taylor Otwell's Laravel Cloud
Taylor Otwell, the author of Laravel, recently put up a public copy of his unfinished work Laravel Cloud in GitHub. It was taken down by himself briefly after, due to what he described as “too much BS”. Forks are still available everywhere though. Here is my fork.
I cloned the repository and skimmed through most of the classes. Here are my takeaways.
Dependency Injection is used very lightly. The service container is mostly underfilled.
Posts
Contextual Dependency Injection Is a Myth
Sometimes in your daily programming life, you would want to inject different object instances based on the current route or module. For example, you want to connect to Database Foo for route /foo and Database Bar for route /bar. It seems a clever idea to do what is called a “contextual binding”, aka inject instances conditionally based on some runtime value.
In Laravel it looks like this:
<?php $this->app->when(PhotoController::class) ->needs(Filesystem::class) ->give(function () { return Storage::disk('local'); }); $this->app->when([VideoController::class, UploadController::class]) ->needs(Filesystem::class) ->give(function () { return Storage::disk('s3'); }); This code looks nice and handy at first glance, but in my experience, they are often doing more harm than any good.
Posts
Never Force Yourself to Learn New Skills Without a Concrete Project
As the job demand is going nowhere in a decade, a lot of new guys want to get into programming. There are numerous courses online, teaching a variety of skills in programming. There are also new shinning frameworks climbing up GitHub trending every day. I see a lot of people, typically newly graduated students, get confused. There seems to be an endless stream of knowledge to learn. How many skills are enough?
Posts
When Do We Need PHP
When we started huijiwiki.com, PHP was the language of the choice. But it was not much a choice. MediaWiki was coded in PHP. It provided us a solid starting point to expand our idea.
Since then I have touched many languages and am moderately proficient in some of them. Among them, Go is my current favorite. Rust is the language I want to explore more.
Go as well as Rust has a very different nature compared to PHP.