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

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

ただいまの
回答率

90.45%

  • PHP

    24645questions

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

  • HTTP

    659questions

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

HTTP/1.1 Pipelining の現在

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,214

mpyw

score 4610

 疑問

  • HTTP/1.1のパイプラインって今は使われてないの?
    Webブラウザで全く使われていないのは知っていたけどWebサーバも対応やめたの?
  • Webブラウザで使うとゴミになるけどバッチ処理では優秀じゃなかったの?

 詳細

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

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

Server doesn't support multi-use (yet)

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

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

 検証に使ったコード

<?php

require 'vendor/autoload.php';

// https://github.com/mpyw/co
use mpyw\Co\Co;

$urls = [
    'https://teratail.com/',
    'https://github.com/',
    'http://www.yahoo.co.jp/',
    'https://google.co.jp/',
    'https://twitter.com/',
    'https://api.twitter.com/',
];

foreach ($urls as $url) {
    echo "\n\n---------------------\n\nTrying $url...\n\n";
    Co::wait(curls($url, 5), ['pipeline' => true, 'concurrency' => 0]); // 並列化数0で無制限
}

function curls($url, $n)
{
    $handles = [];
    for ($i = 0; $i < $n; ++$i) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_VERBOSE => true,
        ]);
        $handles[] = $ch;
    }
    return $handles;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

check解決した方法

+1

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

<?php

require 'vendor/autoload.php';

use mpyw\Co\Co;

function curls($url, $n)
{
    $handles = [];
    for ($i = 0; $i < $n; ++$i) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_VERBOSE => true,
            CURLOPT_HTTPHEADER => ['Connection: keep-alive'],
        ]);
        $handles[] = $ch;
    }
    return $handles;
}

Co::wait(function () {
    for ($i = 0; $i < 2; ++$i) {
        echo "\n\n---------------------\n\n Trying... ($i) \n\n";
        yield curls('http://example.com/', 3);
    }
}, ['pipeline' => true, 'concurrency' => 0]);

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/19 02:10 編集

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

    キャンセル

+1

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

参照:404 Blog Notfound

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/08/18 21:02 編集

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

    キャンセル

  • 2016/08/19 01:52

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

    キャンセル

  • 2016/08/19 02:13

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

    キャンセル

+1

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

記事には

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

とありますが、

$urls = [
    'https://teratail.com/',
    'https://github.com/',
    'http://www.yahoo.co.jp/',
    'https://google.co.jp/',
    'https://twitter.com/',
    'https://api.twitter.com/',
];

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


ソースも確認しましたが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 23:07

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

    やっぱりlibcurlのソース読むしか無いですかね…うーむ

    キャンセル

  • 2016/08/19 01:06

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

    キャンセル

  • 2016/08/19 01:23

    Guzzle などの実装は参考になりませんか?

    【PHPでHTTPの並行ダウンロードを実現する(Guzzle編) - hnwの日記】
    http://d.hatena.ne.jp/hnw/20140824

    キャンセル

  • 2016/08/19 01: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つ目の意味がまだ把握できておりません…

    キャンセル

  • 2016/08/19 02:06 編集

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

    キャンセル

0

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.45%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • PHP

    24645questions

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

  • HTTP

    659questions

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