質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

4回答

3096閲覧

HTTP/1.1 Pipelining の現在

mpyw

総合スコア5223

HTTP

HTTP(Hypertext Transfer Protocol)とはweb上でHTML等のコンテンツを交換するために使われるアプリケーション層の通信プロトコルです。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

2クリップ

投稿2016/08/18 11:24

編集2016/08/18 11:43

疑問

  • HTTP/1.1のパイプラインって今は使われてないの?

Webブラウザで全く使われていないのは知っていたけどWebサーバも対応やめたの?

  • Webブラウザで使うとゴミになるけどバッチ処理では優秀じゃなかったの?

詳細

以下の記事では,HTTP/1.1パイプラインをPHPから試しています.

ところが,自分でいろいろなサーバ相手に試してみましたが,どのサーバも

Server doesn't support multi-use (yet)

という結果となりました.自分のlibcurlのバージョンも疑ったのですが,「相手サーバが対応していない」という旨のログなので全く関係ないと思います.

実際にHTTP/1.1のパイプラインが稼働するサーバをご存知の方,教えてください.私の環境がおかしい場合,疑うべき場所を教えてください.

検証に使ったコード

php

1<?php 2 3require 'vendor/autoload.php'; 4 5// https://github.com/mpyw/co 6use mpyw\Co\Co; 7 8$urls = [ 9 'https://teratail.com/', 10 'https://github.com/', 11 'http://www.yahoo.co.jp/', 12 'https://google.co.jp/', 13 'https://twitter.com/', 14 'https://api.twitter.com/', 15]; 16 17foreach ($urls as $url) { 18 echo "\n\n---------------------\n\nTrying $url...\n\n"; 19 Co::wait(curls($url, 5), ['pipeline' => true, 'concurrency' => 0]); // 並列化数0で無制限 20} 21 22function curls($url, $n) 23{ 24 $handles = []; 25 for ($i = 0; $i < $n; ++$i) { 26 $ch = curl_init(); 27 curl_setopt_array($ch, [ 28 CURLOPT_URL => $url, 29 CURLOPT_RETURNTRANSFER => true, 30 CURLOPT_VERBOSE => true, 31 ]); 32 $handles[] = $ch; 33 } 34 return $handles; 35}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

いろいろと知見を得たのでメモしておきます…

投稿2016/08/18 18:37

mpyw

総合スコア5223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

原因わかりました! Co::wait() のコールごとにcurl_multiリソースを初期化しているのですが,この実装がまずかったようです.そのため,

php

1<?php 2 3require 'vendor/autoload.php'; 4 5use mpyw\Co\Co; 6 7function curls($url, $n) 8{ 9 $handles = []; 10 for ($i = 0; $i < $n; ++$i) { 11 $ch = curl_init(); 12 curl_setopt_array($ch, [ 13 CURLOPT_URL => $url, 14 CURLOPT_RETURNTRANSFER => true, 15 CURLOPT_VERBOSE => true, 16 CURLOPT_HTTPHEADER => ['Connection: keep-alive'], 17 ]); 18 $handles[] = $ch; 19 } 20 return $handles; 21} 22 23Co::wait(function () { 24 for ($i = 0; $i < 2; ++$i) { 25 echo "\n\n---------------------\n\n Trying... ($i) \n\n"; 26 yield curls('http://example.com/', 3); 27 } 28}, ['pipeline' => true, 'concurrency' => 0]);

このような書き方に変えると,2回目以降のforループでは正常にパイプライン化が行われました.「PHPエクステンションだからキャッシュ管理はもっと低レベルなところでやっているだろう」と勝手に思い込んでいたのですが,意外にもcurl_multiリソースとしてしか保持されないという結果でした.

皆様大変お騒がせしました…

投稿2016/08/18 17:09

mpyw

総合スコア5223

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mpyw

2016/08/18 17:12 編集

せっかくなので少し実装いじっておきます…とほほ
guest

0

回答以来をいただいて大変光栄なのですが、知識に欠ける部分なので、リンクされた記事内容と検証コードについて不思議なことのみ回答します。

記事には

まず、別のサーバーに対してリクエストするのであれば役に立ちません。Pipeliningは同一サーバーへのリクエストをまとめるものだからです。Twitter APIとFacebook APIを同時に叩くためにPipeliningは使えません。

とありますが、

PHP

1$urls = [ 2 'https://teratail.com/', 3 'https://github.com/', 4 'http://www.yahoo.co.jp/', 5 'https://google.co.jp/', 6 'https://twitter.com/', 7 'https://api.twitter.com/', 8];

と、それぞれ別のサーバにアクセスしているように見えます。
見当外れでしたらすいません。


ソースも確認しましたがCは教本を眺めたくらいなので「何らかの定数と比較している」というくらいしか追えず……。

【curl/url.c at master · curl/curl · GitHub】
https://github.com/curl/curl/blob/master/lib/url.c#L3230

【curl/conncache.h at master · curl/curl · GitHub】
https://github.com/curl/curl/blob/master/lib/conncache.h#L34

お役に立てないようです、すいません。

投稿2016/08/18 14:04

kei344

総合スコア69400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mpyw

2016/08/18 14:07

回答ありがとうございます.このコードの趣旨は「5つのHTTPセッションを生成したときそれが1本のTCPコネクション内でパイプライン化されるか」というところにあり,それを異なる複数のサイトに対してためしているところです. やっぱりlibcurlのソース読むしか無いですかね…うーむ
mpyw

2016/08/18 16:06

どうやらKeep-Aliveであることが前提みたいで,接続直後には使えないことになっているそうです.そのため,配列の中に全く同じホストを入れてみて,2回目以降は成功するかなと思って試してみたんですが…ダメでしたorz
kei344

2016/08/18 16:23

Guzzle などの実装は参考になりませんか? 【PHPでHTTPの並行ダウンロードを実現する(Guzzle編) - hnwの日記】 http://d.hatena.ne.jp/hnw/20140824
mpyw

2016/08/18 16:40

はい,Guzzleの存在は把握してます. (Guzzleのオブジェクトでラップされた重厚感はまだいいとして,個人的にジェネレータのコルーチンとしての特性があまり活かせていない点で強い不満があったので,生cURLに特化およびジェネレータを完全なコルーチンとして扱えるようにしたライブラリが,例示したコードに含まれる mpyw/co になります…) それはさておき…パイプライン化の部分は完全にlibcurlに隠蔽されていて,PHP側からどうこう手出しできそうにないですね.libcurlのコードを読んでいたら「CURLMOPT_PIPELINING_SITE_BL」というパイプライン化を禁止するブラックリストのオプションは見つけたのですが,これはまだPHP側には実装されていないオプションです.ブラックリストなんて設定していないので,どこかで BUNDLE_PIPELINING が設定されているはずだ,として探してみると https://github.com/curl/curl/blob/master/lib/http.c#L3424 ここは見つけました.このコードが実行される条件は ・!k->headerline++ が真である ・ncの値が3である (リクエスト1行目のパースに成功している) ・HTTPバージョンが1.1である ・Connection: close でない となるんですが,1つ目の意味がまだ把握できておりません…
mpyw

2016/08/18 17:06 編集

バンドルの管理はどうやらcurl_multiリソース単位であって,新しいリソースを作ってしまうとキャッシュが全部消滅してしまうようです!ここがミソでした…
guest

0

ちなみに、Apacheなど通常のWebサーバー単位では、すでにこの技術に対応している。設定変更などは不要である。むしろ問題はリクナビNEXTなど、高負荷で複数のサーバーから構成されているWebサイトが全体としてこれをサポートしているかだろう。

参照:404 Blog Notfound

とあるので ソースからインストールした apache はデフォルトで有効の模様(つまり自作)

投稿2016/08/18 12:00

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mpyw

2016/08/18 12:03 編集

回答ありがとうございます.2006年の記事ですね.HTTPの並列化で探してみても,新しいものはだいたいHTTP/2絡みであって,HTTP/1.1について言及している最近の記事がほとんど見つからないんですよね…
mpyw

2016/08/18 16:52

HTTP/1.1サーバはパイプラインの実装が強制(MUST)されているみたいなので,Keep-Aliveセッションであることを確認した後にパイプライン化を拒否するサーバはHTTP/1.1に準拠していないことになります.こんなにたくさんのサーバが非準拠であるとは考えにくいので,自分が何か勘違いしているんだと思いますが…どこが悪いのかまだわからないです…
mpyw

2016/08/18 17:13

自己解決しました,お騒がせしました…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問