在短短几分钟内用冰柱构建超快速PHP服务器
Event-based programming is a strange topic for PHP developers. In a language as procedural; events are little more than function calls. Nothing happens between events, and all meaningful code is still blocking.
對于PHP開發人員,基于事件的編程是一個奇怪的話題。 用程序語言 事件只不過是函數調用。 事件之間沒有任何React,所有有意義的代碼仍在阻塞。
Languages like JavaScript show us what PHP could be like if event loops were at the center. Some folks have taken these insights and coded them into event loops and HTTP servers. Today we’re going to create an HTTP server, in PHP. We’ll connect it to Apache to serve static files quickly. Everything else will pass through our PHP HTTP server, based on Icicle.
像JavaScript這樣的語言向我們展示了如果以事件循環為中心,PHP將會是什么樣。 一些人已經掌握了這些見解,并將其編碼為事件循環和HTTP服務器。 今天,我們將用PHP創建一個HTTP服務器。 我們將其連接到Apache,以快速提供靜態文件。 其他所有內容都將通過基于IciclePHP HTTP服務器傳遞。
You can find the example code at https://github.com/sitepoint-editors/icicle-http-server
您可以在https://github.com/sitepoint-editors/icicle-http-server上找到示例代碼
配置Apache (Configuring Apache)
When browsers request existing files, it’s best to serve them without involving the PHP interpreter. Apache is fast and efficient at serving these files, so let’s configure it to handle all static file requests:
當瀏覽器請求現有文件時,最好在不涉及PHP解釋器的情況下提供它們。 Apache在處理這些文件方面既快速又高效,因此我們將其配置為處理所有靜態文件請求:
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*) http://%{SERVER_NAME}:9001%{REQUEST_URI} [P]You can place this code inside a virtual host entry.
您可以將此代碼放在虛擬主機條目中。
These mod_rewrite directives tell Apache to send requests to missing files to a different port. In other words: when a browser requests example.com/robots.txt, Apache will first look to see if the file exists. If so, Apache will return it without spinning up the PHP interpreter. If not, Apache will send the request to http://example.com:9001/robots.txt.
這些mod_rewrite指令告訴Apache mod_rewrite丟失文件的請求發送到另一個端口。 換句話說:當瀏覽器請求example.com/robots.txt ,Apache將首先查看該文件是否存在。 如果是這樣,Apache將返回它,而無需增加PHP解釋器。 否則,Apache會將請求發送到http://example.com:9001/robots.txt 。
一個簡單的HTTP服務器 (A Simple HTTP Server)
Icicle ships with an event loop. We can wrap an HTTP server around that, so new requests come to us in the form of events. Much of this process is abstracted away, but let’s take a look at an example anyway. To begin, let’s download icicleio/http:
冰柱附帶事件循環。 我們可以圍繞它包裝一個HTTP服務器,以便以事件的形式向我們提出新的請求。 這個過程的大部分內容都是抽象的,但是無論如何,讓我們看一個例子。 首先,讓我們下載icicleio/http :
composer require icicleio/httpThis installed version 0.1.0 for me. If you’re having trouble getting my examples to work, you may have a newer version. Try installing this specific version.
這為我安裝了0.1.0版本。 如果您無法使用我的示例,則可能有較新的版本。 嘗試安裝此特定版本。
This will allow you to run the following code:
這將允許您運行以下代碼:
// server.phprequire __DIR__ . "/vendor/autoload.php";use Icicle\Http\Message\RequestInterface; use Icicle\Http\Message\Response; use Icicle\Http\Server\Server; use Icicle\Loop; use Icicle\Socket\Client\ClientInterface;$server = new Server(function(RequestInterface $request, ClientInterface $client) {$response = new Response(200);$response = $response->withHeader("Content-Type", "text/plain");yield $response->getBody()->end("hello world");yield $response;} );$server->listen(9001);Loop\run();處理不同的路線 (Handling Different Routes)
This is the most basic HTTP server one can create. It receives all requests and replies “hello world”. To make it more useful, we would need to incorporate some kind of router. League\Route seems like a good candidate:
這是一個可以創建的最基本的HTTP服務器。 它接收所有請求并回復“ hello world”。 為了使其更有用,我們需要結合某種路由器。 League\Route似乎是一個不錯的候選人:
composer require league/routeNow we can split up individual requests, and send more meaningful responses:
現在,我們可以拆分單個請求,并發送更有意義的響應:
// server.phpuse League\Route\Http\Exception\MethodNotAllowedException; use League\Route\Http\Exception\NotFoundException; use League\Route\RouteCollection; use League\Route\Strategy\UriStrategy;$server = new Server(function(RequestInterface $request, ClientInterface $client) {$router = new RouteCollection();$router->setStrategy(new UriStrategy());require __DIR__ . "/routes.php";$dispatcher = $router->getDispatcher();try {$result = $dispatcher->dispatch($request->getMethod(),$request->getRequestTarget());$status = 200;$content = $result->getContent();} catch (NotFoundException $exception) {$status = 404;$content = "not found";} catch (MethodNotAllowedException $exception) {$status = 405;$content = "method not allowed";}$response = new Response($status);$response = $response->withHeader("Content-Type", "text/html");yield $response->getBody()->end($content);yield $response;} );We’ve pulled in League\Route, and enabled the UriStrategy. It’s one of four different methods for determining which route belongs to which request. League\Route is often used alongside Symfony requests and responses. We’ll need to feed the request method and path/target to the dispatcher.
我們已經加入了League\Route ,并啟用了UriStrategy 。 它是確定哪個路由屬于哪個請求的四種不同方法之一。 League\Route通常與Symfony請求和響應一起使用。 我們需要將請求方法和路徑/目標提供給調度程序。
If a route is matched, we get a Symfony\HttpFoundation Response, so we get the body content with getContent. If there isn’t a matching route, or an allowed method for a matching route, then we return the appropriate errors. So what does routes.php look like?
如果路由匹配,我們將得到一個Symfony \ HttpFoundation響應,因此我們可以使用getContent獲得正文內容。 如果沒有匹配的路由,或者沒有匹配的路由的允許方法,那么我們將返回相應的錯誤。 那么, routes.php什么樣的呢?
$router->addRoute("GET", "/home", function() {return "hello world"; });渲染復雜的視圖 (Rendering Complex Views)
Strings are fine for simple pages. But when we start to build more complex applications, we may need a better tool. How about we use League\Plates? It’s a template engine that adds things like layouts and template inheritance on top of plain PHP.
字符串適合簡單頁面。 但是,當我們開始構建更復雜的應用程序時,我們可能需要一個更好的工具。 我們如何使用League\Plates呢? 它是一個模板引擎,在普通PHP之上添加了諸如布局和模板繼承之類的功能。
composer require league/platesThen we’ll create a layout template, for all the views in our site to inherit from:
然后,我們將創建一個布局模板,以供我們站點中的所有視圖繼承自:
<!doctype html> <html lang="en"><head><meta charset="utf-8" /><title><?php print $this->e($title); ?></title></head><body><?php print $this->section("content"); ?></body> </html>This is from templates/layout.php.
這是來自templates/layout.php 。
The e method escapes HTML entities. The section method will be where the page content gets rendered:
e方法轉義HTML實體。 section方法將是呈現頁面內容的位置:
<?php $this->layout("layout", ["title" => "Home"]); ?> <p>Hello, <?php print $this->e($name); ?> </p>The above is from templates/home.php.
上面是來自templates/home.php 。
Finally, we change our /home route to return a rendered template instead of a simple string:
最后,我們更改/home路由以返回渲染的模板而不是簡單的字符串:
$router->addRoute("GET", "/home", function() {$engine = new League\Plates\Engine(__DIR__ . "/templates");return $engine->render("home", ["name" => "Chris"]); });The above is from routes.php.
以上是來自routes.php 。
Of course, we could create a shortcut function, to save us having to create the engine each time:
當然,我們可以創建一個快捷功能,以免我們每次都要創建引擎:
function view($name, array $data = []) {static $engine = null;if ($engine === null) {$engine = new League\Plates\Engine(__DIR__ . "/templates");}return $engine->render($name, $data); }The above is from helpers.php.
上面是來自helpers.php 。
… and if we include that (or add it to the Composer autoload definition), then our /home route becomes:
…,如果我們包括了(或將其添加到Composer自動加載定義中),那么/home路由將變為:
$router->addRoute("GET", "/home", function() {return view("home", ["name" => "Chris"]); });結論 (Conclusion)
We’ve managed to cobble together a reasonable application framework, using Icicle\Http and a couple of League libraries. Hopefully this has shown you that life outside of Apache (or Nginx) is possible. And that’s just the beginning…
使用Icicle\Http和幾個League庫,我們設法將一個合理的應用程序框架拼湊在一起。 希望這向您顯示了Apache(或Nginx)之外的生活是可能的。 這僅僅是個開始……
I was able to get the following stats (while running Chrome and iTunes, on a 13” Macbook Pro Retina 2014):
我能夠獲得以下統計信息(在13英寸Macbook Pro Retina 2014上運行Chrome和iTunes時):
Concurrency Level: 100 Time taken for tests: 60.003 seconds Complete requests: 11108 Failed requests: 0 Total transferred: 3810044 bytes HTML transferred: 2243816 bytes Requests per second: 185.12 [#/sec] (mean) Time per request: 540.182 [ms] (mean) Time per request: 5.402 [ms] (mean, across all concurrent requests) Transfer rate: 62.01 [Kbytes/sec] receivedI imagine those figures will fluctuate as you add more complexity, and they don’t mean anything when compared to popular frameworks. The point is that this little event-based HTTP server can serve 11.1k requests in a minute, without failures. If you’re careful to avoid memory leaks, you can create a stable server out of this!
我想這些數字會隨著您添加更多復雜性而波動,并且與流行框架相比并沒有任何意義。 關鍵是,這個基于事件的小型HTTP服務器可以在一分鐘內處理11.1k請求,而不會出現故障。 如果您要小心避免內存泄漏,則可以由此創建一個穩定的服務器!
That’s exciting, isn’t it?
令人興奮,不是嗎?
What are your thoughts about this setup? Have you played with Icicle yet? Let us know!
您對此設置有何想法? 你玩過冰柱了嗎? 讓我們知道!
Edit: Aaron Piotrowski, the author of Icicle chimed in with some extra info on why the benchmark above may have been flawed (also discussed in the comments). Here are his (much more impressive) results. He says:
編輯:冰柱的作者亞倫·皮奧特洛夫斯基(Aaron Piotrowski)補充了一些有關為何上述基準可能存在缺陷的額外信息(也在評論中進行了討論)。 這是他(令人印象深刻)的結果。 他說:
“I was able to get the following stats (while running iTunes, Chrome, and several other programs on a 3.4 GHz i7 iMac) using the command ab -n 10000 -c 100 http://127.0.0.1:9001/home”:
“使用命令ab -n 10000 -c 100 http://127.0.0.1:9001/home我能夠獲得以下統計信息(在3.4 GHz i7 iMac上運行iTunes,Chrome和其他幾個程序時) :”
Concurrency Level: 100 Time taken for tests: 5.662 seconds Complete requests: 10000 Failed requests: 0 Total transferred: 2650000 bytes HTML transferred: 2020000 bytes Requests per second: 1766.04 [#/sec] (mean) Time per request: 56.624 [ms] (mean) Time per request: 0.566 [ms] (mean, across all concurrent requests) Transfer rate: 457.03 [Kbytes/sec] receivedI imagine those figures will fluctuate as you add more complexity, and they don’t mean anything when compared to popular frameworks. The point is that this little event-based HTTP server could potentially serve over 100,000 requests in a minute, without failures. If you’re careful to avoid memory leaks, you can create a stable server out of this!
我想這些數字會隨著您添加更多復雜性而波動,并且與流行框架相比并沒有任何意義。 關鍵是,這種基于事件的小型HTTP服務器可以在一分鐘內處理超過100,000個請求,而不會出現故障。 如果您要小心避免內存泄漏,則可以由此創建一個穩定的服務器!
Thanks for chiming in, Aaron!
感謝您的來信,亞倫!
翻譯自: https://www.sitepoint.com/build-a-superfast-php-server-in-minutes-with-icicle/
總結
以上是生活随笔為你收集整理的在短短几分钟内用冰柱构建超快速PHP服务器的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: element table表头设置换行
 - 下一篇: Micropython教程之TPYBoa