ラベル php の投稿を表示しています。 すべての投稿を表示
ラベル php の投稿を表示しています。 すべての投稿を表示

2016年3月5日土曜日

Amazon SESを使ったLumen(Laravel)のメール送信

Lumen(5.1)では、Laravelのメール機能が標準では含まれていないので、追加して試してみました。

参考

https://laravel.com/docs/5.1/mail

追加するパッケージ

composer.jsonのrequireに以下のパッケージを追加してcomposer updateします。
 "illuminate/mail": "5.1.*",
 "aws/aws-sdk-php": "~3.0",

設定ファイルの追加

config/mail.phpとconfig/services.phpファイルの作成(デフォルト設定ファイルmail.phpをコピーする)
// configディレクトリが無い場合は作成する
cp vendor/laravel/lumen-framework/config/mail.php config/mail.php

// services.phpは空ファイルを作成して設定値を自分で記述した
touch config/services.php

config/mail.phpの修正

// デフォルト値をsesと書き換える。または環境変数MAIL_DRIVERを設定する
driver' => env('MAIL_DRIVER', 'ses'),

config/services.php

awsで作成した値を設定します。
<?php
return [
    'ses' => [
        'key'    => 'keyの値',
        'secret' => 'secretの値',
        'region' => 'リージョンの値',  // e.g. us-east-1
    ]
];

テンプレートの作成

// テンプレートファイルを作成
touch resource/views/emails/example.blade.php
テンプレートには、通常のviewと同様に変数を渡せます。

HTMLメールの送信

Mail::send('emails.example', ['user' => $user], function ($m) use ($user) {
    $m->from('hello@app.com', 'Your Application');
    $m->to('メールアドレス', '名前')->subject('テストメールの件名');
});

テキストメールの送信

// テンプレートの値を配列にしてキーをtext、値にテンプレートのパスを指定する
Mail::send(['text' => 'emails.example'], ['user' => $user], function ($m) use ($user) {
    $m->from('hello@app.com', 'Your Application');
    $m->to('メールアドレス', '名前')->subject('テストメールの件名');
 });

// 配列でhtmlメールを指定する場合
Mail::send(['html.view', 'text.view'], $data, $callback);

まとめ


Laravelのドキュメントを確認した限りでは、送信オプションもいろいろ網羅されているので細かい調整もできそうです。標準以上の機能が必要なケースはあまりないかもしれませんが、もっとカスタマイズが必要な場合は、コアのソースを確認して調査する必要がありそうです。
あと、Amazon SESはデフォルトで送信制限があるので、テスト用のメールアドレスはあらかじめSES側で設定とverify(メールアドレスの有効性の確認)しておく必要があります。制限解除済みであれば登録不要です。

2016年2月14日日曜日

Laravel, LumenのSELECT文いろいろ

Laravel, LumenでSELECT文に慣れていないのでメモ。

参考

https://laravel.com/docs/5.1/eloquent#retrieving-single-models

SELECTもいろいろある

find

  • プライマリーキーでマッチした1レコードを取得する
  • 戻り値はモデルのインスタンス(stdClass)
  • 0件の場合は、null
$flight = Flight::find(1);

first

  • 条件にマッチした最初の1レコードを取得する
  • 戻り値はモデルのインスタンス(stdClass)
  • 0件の場合は、null
$flight = Flight::where('active', 1)->first();

get

  • 条件にマッチした全てのレコードを取得する
  • 戻り値は、配列(各レコードはstdClassオブジェクトのインスタンス)
  • 0件の場合は、オブジェクトが返る
$flight = Flight::where('active', 1)->get();

all

  • 全てのレコードを取得する
  • 戻り値は、配列(各レコードはstdClassオブジェクトのインスタンス)
  • 0件の場合は、オブジェクトが返る
$flight = Flight::all();

0件の場合の評価の違い

$flight = Flight::find(1);
if (!$flight ) {
  // 通る
}

$flight = Flight::where('id', 1)->first();
if (!$flight ) {
  // 通る
}

$flight = Flight::where('id', 1)->get();
if (!$flight) {
    // 通らない (オブジェクトが戻り値のため)
}
if (!count($flight)) {
    // 通る Countableインターフェース
}

$flight = Flight::where('id', 1)->get()->toArray();
if (!$flight) {
    // 通る (オブジェクトを配列に変換したため)
}
if (!count($flight)) {
    // 通る
}

$flight = Flight::all();
if (!$flight) {
    // 通らない (オブジェクトが戻り値のため)
}
if (!count($flight)) {
    // 通る Countableインターフェース
}

まとめ

  • get(), all()の場合は、0件の場合もオブジェクトが返る。
  • Objectはtrueということと、1件または複数レコード(get()を使うか)を意識して書けばよさそう。
  • Illuminate\Database\Eloquent\Collectionは、継承しているクラスがCountableインターフェースを実装していてcount()でitemsの件数が取れる。
Illuminate\Database\Eloquent\Collection Object
(
    [items:protected] => Array
        (
        )
)


2016年2月4日木曜日

Lumenのタイムゾーン設定

Lumenを検証していたところ、時間がUTCになっていたのでメモ

Lumen5.1で時間を表示させたところUTCとなっていました。
echo date('Y-m-d H:i:s e P'); // 2016-02-04 09:00:23 UTC +00:00
Asia/Tokyoとなってほしいのですが、
アプリ側では何も設定していないので、lumenのソースを確認したところ見つかりました。

lumen-framework/src/Application.php

    public function __construct($basePath = null)
    {
        date_default_timezone_set(env('APP_TIMEZONE', 'UTC'));
        $this->basePath = $basePath;
        $this->bootstrapContainer();
        $this->registerErrorHandling();
    }
この場合、環境変数APP_TIMEZONEは設定していないのでUTCになるわけですが、
デフォルト値をphp.iniの設定にしてほしいのは私だけでしょうか。

Dotenvを使っている場合は、.envに追加
使っていない場合は、bootstrap/app.phpに設定を追加することにしました。

.env

APP_TIMEZONE=Asia/Tokyo

bootstrap/app.php

// Dotenv::load(__DIR__.'/../');
putenv('APP_TIMEZONE=Asia/Tokyo');
軽量フレームワークなので、かゆいところは自分で対応する必要があるわけですが、
これはドキュメントに書いてほしいですね。

2016年1月18日月曜日

LaravelとLumenでベンチマークやり直し

前回の「LaravelとLumenのHello Woldを試す」は実用的な計測ではないので、
もう少し通常の動的サイトに近い処理を追加して計測してみました。

テスト環境

前回の記事を参照

LaravelとLumenで以下のファイルを追加

  • ルーティング設定でHomeコントローラを指定する (app/Http/routes.php)
  • データベース設定を追加する (config/database.php)
  • コントローラーにデータを取得する処理を追加する (app/Http/Controllers/HomeController.php)
  • モデル追加する (app/Page.php)
  • ビュー追加する (resources/views/home/index.php)
  • ビュー上でデータをforeachで20件ほど表示する
  • セッション機能はfileを使用する
  • Lumenは、機能(DotEnv, Facade, Eloquent)を削る毎にHomeControllerを修正する

Lumenは機能の有無で4パターン計測

機能の切り替えは、bootstrap/app.phpを修正する
  • DotEnv, Facade, Eloquentを使用する
  • DotEnv, Facadeを使用する
  • DotEnvを使用する
  • DotEnv, Facade, Eloquentを使用しない

Lumen5.2ではなく5.1も対象している理由

Lumen5.2ではAPI Tokenの利用を前提にしているようでsession機能が削除されました。
独自にsession機能を追加すると別のものになってしまうので、できるだけLumenをLaravelに近づけるため5.1の計測をしてみました。
ちなみに、sessionを利用したい場合は、Laravelがおすすめとのこと。

結果

framework req/sec
Laravel 5.2692.81
Lumen 5.1 (DotEnv, Façade, Eloquent)1,341.92
Lumen 5.1 (DotEnv, Façade)1,523.70
Lumen 5.1 (DotEnv)1,632.32
Lumen 5.2 (DotEnv)1,663.94
Lumen 5.11,769.84

前回の結果ほど差はありませんが、1.9〜2.5倍程度Lumenの処理性能が速い結果となりました。
DotEnv, Facade, Eloquentを使っても約2倍近い性能を得ることができるので、パフォーマンス重視の方は選択肢の1つとなるのではないでしょうか。
ソースの書き方によってはLaravelに近づけることや移植もできると思うので、良い派生プロジェクトではないでしょうか。

2016年1月15日金曜日

LaravelとLumenのHello Woldを試す

バルス待機中に気になったので確認してました。
「The stunningly fast micro-framework by Laravel.」と公言しているLumenですが、
Laravelとどの程度の差があるかHello Worldで計測してみました。

テスト環境

Intel Core i7-4790K
メモリー 16GB
Ubuntu 15.10
PHP 5.6.11
nginx/1.9.3

  • 特別なチューニングはしていません
  • nginxとphp-fpmの設定もインストールした時のデフォルトのままです。
  • LaravelとLumenはcomposerインストールした状態です
  • どちらもroute.phpで文字列"Hello World!"を返すように修正しました。
  • abコマンドで計測しました

結果

Laravel 5.2     928.19 req/sec
Lumen 5.2     5589.13 req/sec
予想以上に差が出てしまいました。約6倍
機能の数が違うので、検討すべきことは多いですが、LumenはAPIサーバとかに向いているかも。オーバーヘッドの少ないWAFですね。
なかなか悩ましい結果となりました。

以上、簡易的なベンチマークでした。


Laravel 5.2

ab -c 100 -n 10000 http://laravel.local/
This is ApacheBench, Version 2.3 <$Revision: 1638069 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking laravel.local (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        nginx/1.9.3
Server Hostname:        laravel.local
Server Port:            80

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      100
Time taken for tests:   10.774 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      2580000 bytes
HTML transferred:       120000 bytes
Requests per second:    928.19 [#/sec] (mean)
Time per request:       107.737 [ms] (mean)
Time per request:       1.077 [ms] (mean, across all concurrent requests)
Transfer rate:          233.86 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     4  107  10.0    105     130
Waiting:        4  107  10.0    105     130
Total:          5  107  10.0    105     130

Percentage of the requests served within a certain time (ms)
  50%    105
  66%    113
  75%    114
  80%    115
  90%    117
  95%    125
  98%    128
  99%    128
 100%    130 (longest request)

Lumen 5.2

ab -c 100 -n 10000 http://lumen.local/
This is ApacheBench, Version 2.3 <$Revision: 1638069 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking lumen.local (be patient)
Completed 1000 requests
Completed 2000 requests
Completed 3000 requests
Completed 4000 requests
Completed 5000 requests
Completed 6000 requests
Completed 7000 requests
Completed 8000 requests
Completed 9000 requests
Completed 10000 requests
Finished 10000 requests


Server Software:        nginx/1.9.3
Server Hostname:        lumen.local
Server Port:            80

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      100
Time taken for tests:   1.789 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      2110000 bytes
HTML transferred:       120000 bytes
Requests per second:    5589.13 [#/sec] (mean)
Time per request:       17.892 [ms] (mean)
Time per request:       0.179 [ms] (mean, across all concurrent requests)
Transfer rate:          1151.67 [Kbytes/sec] received

Connection Times (ms)
             min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       2
Processing:     1   18   2.7     17      25
Waiting:        1   18   2.7     17      25
Total:          2   18   2.7     17      25

Percentage of the requests served within a certain time (ms)
 50%     17
 66%     18
 75%     18
 80%     19
 90%     22
 95%     24
 98%     24
 99%     24
100%     25 (longest request)

2015年10月14日水曜日

【Symfony2.7ドキュメント読んだ?】ルーティング

ルートの定義

# app/config/config.yml
framework:
    # ...
    router: { resource: "%kernel.root_dir%/config/routing.yml" }

# app/config/routing.yml
app:
    resource: "@AppBundle/Controller/"
    type:     annotation

基本的なルート設定

// src/AppBundle/Controller/MainController.php
// ...
class MainController extends Controller
{
    /**
     * @Route("/")
     */
    public function homepageAction()
    {
        // ...
    }
}

プレースホルダーを使ったルーティング

// src/AppBundle/Controller/BlogController.php

/**
 * @Route("/blog/{page}", defaults={"page" = 1})
 */
public function indexAction($page)
{
    // ...
}
URL Route Parameters
/blog blog {page}=1
/blog/1 blog {page}=1
/blog/2 blog {page}=2

プレースホルダーの値の条件

// src/AppBundle/Controller/BlogController.php
// ...
/**
 * @Route("/blog/{page}", defaults={"page": 1}, requirements={
 *     "page": "\d+"
 * })
 */
public function indexAction($page)
{
    // ...
}

/**
  * @Route("/blog/{slug}")
  */
public function showAction($slug)
{
    // ...
}
URL Route Parameters
/blog/2 blog {page}=2
/blog/my-blog-post blog_show {slug}=my-blog-post
/blog/2-my-blog-post blog_show {slug}=2-my-blog-post

ルーティングは、先に条件にマッチしたメソッドを実行する

// src/AppBundle/Controller/MainController.php
// ...
class MainController extends Controller
{
    /**
     * @Route("/{_locale}", defaults={"_locale": "en"}, requirements={
     *     "_locale": "en|fr"
     * })
     */
    public function homepageAction($_locale)
    {
    }
}
Path Parameters
/ {_locale} = "en"
/en {_locale} = "en"
/fr {_locale} = "fr"
/es won't match this route

HTTPメソッドの指定

/ src/AppBundle/Controller/MainController.php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;

class MainController extends Controller
{
    /**
     * @Route("/news")
     * @Method("GET")
     */
    public function newsAction()
    {
        // ... display your news
}
    /**
     * @Route("/contact")
     * @Method({"GET", "POST"})
     */
    public function contactFormAction()
    {
        // ... display and process a contact form
    }
}

ホスト名でコントローラを振り分け

# ホスト名を指定
mobile_homepage:
    path:     /
    host:     m.example.com
    defaults: { _controller: AcmeDemoBundle:Main:mobileHomepage }

homepage:
    path:     /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }

# プレースホルダーを用いる場合
projects_homepage:
    path:     /
    host:     "{project_name}.example.com"
    defaults: { _controller: AcmeDemoBundle:Main:mobileHomepage }

homepage:
    path:     /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }

# プレースホルダーを用いる場合(サブドメインを指定する)
mobile_homepage:
    path:     /
    host:     "{subdomain}.example.com"
    defaults:
        _controller: AcmeDemoBundle:Main:mobileHomepage
        subdomain: m
    requirements:
        subdomain: m|mobile

homepage:
    path:     /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }

# パラメータを用いる場合
mobile_homepage:
    path:     /
    host:     "m.{domain}"
    defaults:
        _controller: AcmeDemoBundle:Main:mobileHomepage
        domain: "%domain%"
    requirements:
        domain: "%domain%"

homepage:
    path:  /
    defaults: { _controller: AcmeDemoBundle:Main:homepage }

# ホスト名で読み込むルーティング定義ファイルを指定する
acme_hello:
    resource: "@AcmeHelloBundle/Resources/config/routing.yml"
    host:     "hello.example.com"

高度なルーティングの例

/ src/AppBundle/Controller/ArticleController.php
// ...
class ArticleController extends Controller
{
/**
* @Route(
*        "/articles/{_locale}/{year}/{title}.{_format}",
*        defaults={"_format": "html"},
*        requirements={
*            "_locale": "en|fr",
*            "_format": "html|rss",
*            "year": "\d+"
*        }
*)
*/
    public function showAction($_locale, $year, $title)
    {
    }
}

# マッチするURLの例
/articles/en/2010/my-post
/articles/en/2010/my-post.rss
/articles/en/2010/my-latest-post.html

コントローラのネーミングパターン

bundle:controller:action
Bundle Controller Class Method Name
AppBundle BlogController showAction

ルーティングのテスト

$crawler = $client->request(
    'GET',
    '/homepage',
    array(),
    array(),
    array('HTTP_HOST' => 'm.' . $client->getContainer()->getParameter('domain'))
);

ルートマッチングの条件指定

contact:
    path:     /contact
    defaults: { _controller: AcmeDemoBundle:Main:contact }
    condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.get('User-Agent') matches '/firefox/i'"

ルートの確認

# ルートの一覧
php app/console debug:router

#  詳細
php app/console debug:router homepage

# マッチするルートの確認
php app/console router:match /blog/my-latest-post

関連サイト


前の記事 | 次の記事

2015年10月13日火曜日

【Symfony2.7ドキュメント読んだ?】コントローラー

リクエスト、コントローラ、レスポンスのライフサイクル

リクエストは、フロントコントローラ(app.php, app_dev.php)からアプリケーションが実行され、 RouterがURIを元にマッチするルートのコントローラを実行する。 コントローラがレスポンスオブジェクトを返し、HTTPヘッダー情報とレスポンスオブジェクトの内容を クライアントへ返す。

開発用フロントコントローラのIP制限解除

app_dev.phpの次のようにコメントアウトする
ローカルで開発する場合は不要
/* IP制限解除
if (isset($_SERVER['HTTP_CLIENT_IP'])
    || isset($_SERVER['HTTP_X_FORWARDED_FOR'])
    || !(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', 'fe80::1', '::1')) || php_sapi_name() === 'cli-server')
) {
    header('HTTP/1.0 403 Forbidden');
    exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
*/

アノテーションによるURLとコントローラのマッピング

// src/AppBundle/Controller/HelloController.php
namespace AppBundle\Controller;

use Symfony\Component\HttpFoundation\Response;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

class HelloController
{
    /**
     * @Route("/hello/{name}", name="hello")
     */
    public function indexAction($name)
    {
        return new Response('Hello '.$name.'!');
    }
}

ベースコントローラの継承

よく使われそうなヘルパーメソッドが使えるようになる
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class HelloController extends Controller
{
    // ...
}

複数の引数

引数の順番は関係がなく、対応した変数名があることが重要
public function indexAction($firstName, $lastName, $foo = 'bar')
{
    // ...
}

リダイレクト

return $this->redirectToRoute('homepage'); // 引数はルート
// redirectToRoute is equivalent to using redirect() and generateUrl() together:
// return $this->redirect($this->generateUrl('homepage'), 301);

# デフォルトは302リダイレクト
return $this->redirect('http://symfony.com/doc');

return $this->redirectToRoute('homepage', array(), 301);

# 元はレスポンスオブジェクト
return new RedirectResponse($this->generateUrl('homepage'));

テンプレートのレンダリング

// renders app/Resources/views/hello/index.html.twig
return $this->render('hello/index.html.twig', array('name' => $name));

// renders app/Resources/views/hello/greetings/index.html.twig
return $this->render('hello/greetings/index.html.twig', array(
    'name' => $name
));

他のサービスのアクセス

$templating = $this->get('templating');

$router = $this->get('router');

$mailer = $this->get('mailer');

サービスの確認コマンド

cd project_name
php app/console debug:container

エラーと404レスポンスの管理

// 404
throw $this->createNotFoundException('The product does not exist');

// 500
throw new \Exception('Something went wrong!');

フラッシュメッセージ

# コントローラ
use Symfony\Component\HttpFoundation\Request;

public function updateAction(Request $request)
{
    $form = $this->createForm(...);
    $form->handleRequest($request);
    if ($form->isValid()) {
        // do some sort of processing
        $this->addFlash(
            'notice',
            'Your changes were saved!'
        );
        // $this->addFlash is equivalent to $this->get('session')->getFlashBag()->add
        return $this->redirectToRoute(...);
    }
    return $this->render(...);
}

# テンプレート
{% for flashMessage in app.session.flashbag.get('notice') %}
    
{{ flashMessage }}
{% endfor %}

リクエストオブジェクト

リクエストオブジェクトを使ってパラメータの値など取得できる
ルーティングパラメータにマッチしない変数名がある場合に、RuntimeExceptionが発生する
use Symfony\Component\HttpFoundation\Request;

// create a simple Response with a 200 status code (the default)
$response = new Response('Hello '.$name, Response::HTTP_OK);

// create a JSON-response with a 200 status code
$response = new Response(json_encode(array('name' => $name)));
$response->headers->set('Content-Type', 'application/json');
use Symfony\Component\HttpFoundation\Response;

public function indexAction(Request $request)
{
    $request->isXmlHttpRequest(); // is it an Ajax request?

    $request->getPreferredLanguage(array('en', 'fr'));

    $request->query->get('page'); // get a $_GET parameter

    $request->request->get('page'); // get a $_POST parameter
}

他のコントローラへフォワードする

public function indexAction($name)
{
    $response = $this->forward('AppBundle:Something:fancy', array(
        'name'  => $name,
        'color' => 'green',
    ));
    // ... further modify the response or return it directly
    return $response;
}

# forward先のコントローラ
public function fancyAction($name, $color)
{
   // 
}

関連サイト


2015年10月9日金曜日

【Symfony2.7ドキュメント読んだ?】パーミッションの設定

パーミッションの設定

Webサーバの実行ユーザーとディレクトリのパーミッションが同じ場合

特に設定変更なし

ACLをサポートしている場合

rm -rf app/cache/*
rm -rf app/logs/*
HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`
sudo chmod +a "$HTTPDUSER allow delete,write,append,file_inherit,directory_inherit" app/cache app/logs
sudo chmod +a "`whoami

ACLをサポートしている場合(chmod +aをサポートしていない場合)

# この記事ではこの方法で設定しました。
HTTPDUSER=`ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\  -f1`
sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs
sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:`whoami`:rwX app/cache app/logs

ACLが使えない場合

# 次のファイルを修正する
# app/console
# web/app.php
# web/app_dev.php

# コメントを外す
umask(0002); // This will let the permissions be 0775

# または
umask(0000); // This will let the permissions be 0777

関連サイト


2015年10月7日水曜日

【Symfony2.7ドキュメント読んだ?】ビルトインWebサーバの使い方

ビルトインWebサーバの起動、停止、確認コマンド

cd project_name
php app/console server:run

# Webサーバ起動後に次のURLにアクセスします。
# http://localhost:8000/

# IPアドレスおよびポート指定で起動
php app/console server:run 192.168.0.1:8080

# バックグラウンドで実行させたい場合
php app/console server:start
php app/console server:start 192.168.0.1:8080

# サーバの停止
php app/console server:stop
php app/console server:stop 192.168.0.1:8080

# サーバ状態の確認
php app/console server:status
php app/console server:status 192.168.0.1:8080

# 環境変数やルータースクリプトの指定
php app/console server:start --env=test --router=app/config/router_test.php

# ドキュメントルートを指定する
php app/console server:start --docroot=public_html

関連サイト


2015年10月6日火曜日

【Symfony2.7ドキュメント読んだ?】インストールと更新

Symfonyインストーラのインストール

Linux、MacOSの場合

sudo curl -LsS http://symfony.com/installer -o /usr/local/bin/symfony
sudo chmod a+x /usr/local/bin/symfony

Symfonyアプリケーションの作成

Linux、MacOSの場合

# [project_name]はプロジェクト名です。適宜変更してください。
# この記事ではこのコマンドを使用してインストールしました。
symfony new project_name

# インストールするSymfonyのバージョンを指定する場合
symfony new project_name 2.6
symfony new project_name 2.6.5

# LTSバージョンの場合 ※1
symfony new project_name lts

# composerを使ってSymfonyアプリケーションを作成する場合
composer create-project symfony/framework-standard-edition project_name

# バージョン指定の場合
composer create-project symfony/framework-standard-edition project_name "2.6.*"
※1 LTSは36ヶ月サポートするようです。 バージョン毎のサポート期間は、こちらで確認できます。

composerのインストール

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

1行の場合
curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
SymfonyはWebサーバ機能があるのでインストール後すぐに動作確認できます。

Symfonyアプリケーションの更新

# 依存関係ライブラリのインストール
cd  project_name
composer install

# 更新
cd  project_name
composer update

関連サイト



【Symfony2.7ドキュメント読んだ?】 動作検証環境

Symfony2.7の公式ドキュメントを読んでメモを残します。

公式ドキュメント


この記事は、次の環境で動作確認します。

  • CentOS 6.7

  • PHP 5.6.14

  • nginx/1.8.0

  • Symfony 2.7






2014年2月24日月曜日

最近気になるPHPフレームワークHelloWord性能比較大会

最近気になっているPHPフレームワークのベンチマークを取得してみました。
サーバやフレームワークなどのチューニングはほとんどしていないので、
結果は、あくまで参考程度としてください。

テスト環境

仮想環境 (1CPU memory 4GB)
PHP 5.5.9 (opcache使用)
NGINX 1.4.5

確認したコマンド※

ab -n 1000 -c 20 http://localhost.local/
※外部からではなく同じサーバで実施しています。

結果


Phalcon 1.2.6


Time taken for tests: 0.523 seconds
Requests per second: 1910.87 [#/sec]

FuelPHP 1.7


Time taken for tests: 1.704 seconds
Requests per second: 586.90 [#/sec]

Laravel 4.1


Time taken for tests: 6.171 seconds
Requests per second: 162.04 [#/sec]

php artisan optimizeで最適化
Time taken for tests: 4.925 seconds
Requests per second: 203.02 [#/sec]

Ruby on Rails 4.0.3 (特別ゲスト)


Time taken for tests: 2.851 seconds
Requests per second: 350.73 [#/sec]

Ruby On Rails4も含めてみました。
環境はPHPとは異なり次のとおりです。
NGINX 1.4.4
Passenger4.0.37
ruby 2.1.0

感想


Phalconが圧倒的な処理速度で1位です。
Laravelと比較すると約11倍以上速いですね。
FuelPHPはLaravel寄りではありますが、まずまずの性能です。

artisanコマンドで最適化されたLaravelでもそれほど大幅には変化がなかった(でもLaravel比だと25%アップ)ので、速度が出ないのは、autoloadが原因ということはなさそうです。
LaravelはIoC Containerというのが得意で、コードがきれいで書きやすいのですが、
それが原因かどうかはわかりませんがパフォーマンス面では他に劣るようです。
今のところPHPでもRailsと同様にパフォーマンスと便利な機能は相反するようですね。
またPhalconが速いのはC言語で実装されたフレームワークの部分だけなのでPHP部分はそんなに変わらないのではないかと思います。
結果はPhalconが目立ちすぎてますが、実際のロジックを実装した状態ではそこまでは差がないのではないかと考えています。
また、PhalconはC言語で実装されているので運用面でトラブルの際の調査も難しくなりそうで、
仕事に使うのはZephirで実装されるバージョン2.0までは様子をみようかと思っています。
Zephirは今後どうなるか気になるところです。
LaravelがZephirで実装されたりとか・・・、今のところその動きはなさそうですが。

Railsは、言語違いますがフルスタックのフレームワークの代表例として参考になるかと思って追加しました。
LaravelとFuelPHPの中間くらいで以前より速くなってますね。
RubyのVMが進化していたり、Rails自体もチューニングが進んでいるのかも。

いずれにせよ、現実的ではないHelloWorld程度の比較なので、
あまりこの結果を鵜呑みにしないようにご注意ください。



2014年1月23日木曜日

Vagrant環境でMySQL5.6が起動しない?

VagrantでCentOS6.5でMySQLインストールしても起動しない・・・、
MySQL5.6だから?とかmy.cnfの設定がダメ?とかいろいろ考えすぎましたが、
デフォルトでも起動しないためそんなことはないようです。
ログには Cannot allocate memory・・・・と、
空きメモリーあるんだけどなと思いつつもinnodb_buffer_pool_sizeを小さくしてもダメでした。
[Note] InnoDB: Initializing buffer pool, size = 128.0M
InnoDB: mmap(137363456 bytes) failed; errno 12
[ERROR] InnoDB: Cannot allocate memory for the buffer pool
[ERROR] Plugin 'InnoDB' init function returned error.
[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
[ERROR] Unknown/unsupported storage engine: InnoDB
[ERROR] Aborting

対策

メモリー(物理)を増やすほど富豪ではなかったのでswap領域を追加してみることにしました。

swap領域の確認

swapon -s
Filename    Type  Size Used Priority
確かにありません・・・。

スワップ領域作成

容量は環境に合わせて適宜変更してください。
sudo dd if=/dev/zero of=/swapfile bs=1024k count=512
sudo mkswap /swapfile
sudo swapon /swapfile
sudo chown root:root /swapfile
sudo chmod 0600 /swapfile

再起動しても反映されるように修正

sudo vi /etc/fstab
# 次の行を追記
/swapfile swap swap defaults 0 0 

OSのスワップの利用頻度を低くする

できるだけスワップしない用に設定する(0〜100) 100の方が多くスワップ領域を使用する
vi /etc/sysctl.conf
vm.swappiness=10
sysctl -p 

これで無事にMySQL5.6が起動したのでいろいろ検証できます。
ちなみにPHPでもワーニング出ていたのが解消しました。
 PHP Warning:  PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/gd.so' - libvpx.so.0: cannot map zero-fill pages: Cannot allocate memory in Unknown on line 0
ここにもさりげなくCannot allocate memoryが。
ワーニング?・・・レベルなのかな・・・

2012年10月15日月曜日

gettextインストールするのにこんなに時間かかるはずがない for MacPorts - その後cmakeも

久しぶりにosxにMacPortsでphpをインストールしようとしたら、
なぜかgettextがインストールできないすてきな罠に出会いましたのでメモを残します。

環境
OSX 10.8 (Mountain Lion)
MacPorts 2.1.2

お急ぎの方に先に結論を申し上げると、次の2行でインストールできました。

export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework
port install gettext

ログなど


sudo port install gettext
途中省略
---> Fetching archive for gettext
---> Attempting to fetch gettext-0.18.1.1_2.darwin_12.x86_64.tbz2 from http://packages.macports.org/gettext
---> Attempting to fetch gettext-0.18.1.1_2.darwin_12.x86_64.tbz2 from http://mse.uk.packages.macports.org/sites/packages.macports.org/gettext
---> Attempting to fetch gettext-0.18.1.1_2.darwin_12.x86_64.tbz2 from http://lil.fr.packages.macports.org/gettext
---> Fetching distfiles for gettext
---> Attempting to fetch gettext-0.18.1.1.tar.gz from ftp://ftp.dti.ad.jp/pub/GNU/gettext
---> Verifying checksum(s) for gettext
---> Extracting gettext
---> Applying patches to gettext
---> Configuring gettext

このまま数時間放置していたのに状況変わらず・・・
CPU利用率を見ても動いている気配がない・・・
ターミナルのメニューにjavacの文字が見えているので少し調べると

https://trac.macports.org/ticket/34221
どうもJAVA_HOME設定するとよいらしい。

export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework
port install gettext
---> Computing dependencies for gettext
---> Configuring gettext
---> Building gettext
---> Staging gettext into destroot
---> Installing gettext @0.18.1.1_2
---> Activating gettext @0.18.1.1_2
---> Cleaning gettext
---> Updating database of binaries: 100.0%
---> Scanning binaries for linking errors: 100.0%
---> No broken files found.

インストールできましたよ。

参考まで

ちなみにMac Developer Libraryを参考にした下記のパスでは動作しませんでした。


export JAVA_HOME=`/usr/libexec/java_home`

java_homeコマンドで設定されたパス
echo $JAVA_HOME
/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

その後cmakeもインストールできなかった・・・

次のようにmysql5.5をインストールしようとしたが、cmakeのビルドで止まり同様に動かない様子。

sudo port install mysql55-server

こちらもJAVA_HOMEと関係しているか不明のままですが、
次の手順でいったんcmakeを削除してから再度インストールできました。

参考
http://stackoverflow.com/questions/5576785/problem-installing-cmake-with-macports


sudo port clean cmake
sudo port install cmake

2012年3月22日木曜日

PHP 5.4.0 + APC 3.1.9でapacheが再起動できないらしい



PHP5.4.0の動作検証など行っていますが、
一見問題ないように見えます。
とはいえ、まだリリースしたばかりなのでいろいろあるものですね。

かゆいところで、Apacheが再起動(restart or graceful)できないという現象がありました。
ちなみに、停止(stop)、起動(start)は問題なくできます。
そんな環境はこちら


  • Cent OS 6.2

  • Apache HTTP Server 2.2.22

  • PHP 5.4.0 + APC 3.1.9



再起動すると次のログが出力されhttpdが起動しません。


[Thu Mar 22 10:32:38 2012] [notice] seg fault or similar nasty error detected in the parent process


stop、startでは問題なくhttpdの起動と停止ができます。
また、apcを外すとこちらも問題なかったためやはりapcが原因のようです。
念のため、pecl apcのリポジトリから最新版をインストールしてみました。

pecl apcをリポジトリからインストール




svn co http://svn.php.net/repository/pecl/apc/trunk/ apc-trunk
cd apc-trunk
phpize
./configure --enable-apc --with-php-config=/usr/local/php/bin/php-config
make
make install


すんなり再起動できました。
インストールしたapcの情報をphpinfo()で確認すると、













APC Supportenabled
Version3.1.9
APC DebuggingDisabled
MMAP SupportEnabled
MMAP File Maskno value
Locking typepthread mutex Locks
Serialization Supportphp
Revision$Revision: 324326 $
Build DateMar 22 2012 11:34:52

バージョンに変更はないですが、開発版なのでいろいろ違うのかと。

なんらかの事情?で、力技で乗り切るには、
apachectlに次の内容を追記します。

restart)
echo 'apache httpd stop'
$HTTPD -k stop
echo 'sleep 3'
sleep 3
echo 'apache httpd start'
$HTTPD -k start
ERROR=$?
;;


まあ、使わないと思いますが。




2011年12月30日金曜日

KyotoTycoon「memcachedプロトコルでメッセージキュー」を試す



最近低GIダイエットのブログを中心に書いている気がしますが、年末ということで少し時間ができたので前々から導入しようと思っていたKyotoTycoonのメッセージキューを試すことにしました。メッセージキューによる非同期処理といえば、Q4MとかActiveMQをよく使っていていますが、これもKyotoTycoonでいいんじゃない?と思うこの頃です。
何よりmemcachedプロトコルで動作するのがとても助かりますよね。

今回の内容はこちらです。


  • ktserver起動ファイル(マスター)

  • ktserver起動ファイル(スレーブ)

  • ジョブの登録(PHP)

  • ジョブの取得と削除(PHP)

  • ベンチマークの結果

  • テスト中に気になったこと

  • kctのデフラグ

  • Net_KyotoTycoonでキューの件数を取得する(PHP)




参考 memcachedプロトコルでメッセージキューを実現する
http://fallabs.com/blog-ja/promenade.cgi?id=133


テスト環境は、以前試したこちらですが、yum updateしてCentOS 6.2になりました。

ktserver起動ファイル(マスター)


まずは、damontoolsでktserverを起動します。
起動オプションですが、メッセージキューで動作させるには、「必ずツリー系のデータベース(GrassDB、TreeDB、ForestDB)のいずれかを指定してサーバを起動する必要がある」そうです。なので、オススメ通りTreeDBで。
thオプションは1でもよいそうですが、冗長構成のためレプリケーションの使用を前提に4にしました。


#!/bin/sh

PATH=/usr/local/bin:/usr/bin:/bin
PATH=$PATH:/usr/local/kyototycoon/bin
export PATH

exec env - PATH=$PATH \
ktserver \
-host 127.0.0.1 \
-port 10001 \
-th 4 \
-log /path/to/log/queue_master.log \
-ls \
-ulog /path/to/log/ulog_queue_master \
-ulim 256M \
-sid 1 \
-plsv /usr/local/kyototycoon/libexec/ktplugservmemc.so \
-plex 'port=11311#opts=fq' \
'/path/to/db/queue_master.kct#ktopts=p' 2>&1



ktserver起動ファイル(スレーブ)




#!/bin/sh

PATH=/usr/local/bin:/usr/bin:/bin
PATH=$PATH:/usr/local/kyototycoon/bin
export PATH

exec env - PATH=$PATH \
ktserver \
-host 127.0.0.1 \
-port 10002 \
-log /path/to/log/queue_slave.log \
-ls \
-ulog /path/to/log/ulog_queue_slave \
-ulim 256M \
-sid 2 \
-th 4 \
-mhost 127.0.0.1 \
-mport 10001 \
-rts /path/to/log/rts.log \
-plsv /usr/local/kyototycoon/libexec/ktplugservmemc.so \
-plex 'port=11312#opts=fq' \
'/path/to/db/queue_slave.kct#ktopts=p' 2>&1



ジョブの登録


このような非同期処理は、そもそもキューが溜まらないように処理していくはずなのですが、
性能評価なのである程度の件数(100万件×3の300万件)の平均値で計測します。

<?php

$data = array(
'name' => 'testname',
'testdata' =>
array(1,2,3,4,5,6,7,8,9,0,'abcdefghijklmnopqrstuvwxyz',
'userid' => 'testuserid',
'entry' => '2011-10-20 12:00:00'
)
);
$mem = new Memcached();
$mem->addServer('127.0.0.1', 11311);

$time_start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$mem->set('testkey', $data);
}
$time_end = microtime(true);
echo ($time_end - $time_start) . "\n";



ジョブの取得と削除


ジョブは取得してその情報を元した処理が成功した後に削除することが想定されるため、1件ずつgetとdeleteを繰り返して計測します。

<?php

$key = 'testkey';
$m = new Memcached();
$m->addServer('127.0.0.1', 11311);

$cnt = 0;
$time_start = microtime(true);
for ($i = 0; $i < 1000000; $i++)
{
$val = $m->get($key);
if ($val)
{
$res = $m->delete($key);
if ($res)
{
$cnt++;
}
}
}
$time_end = microtime(true);
echo ($time_end - $time_start) . "\n";
echo $cnt . "\n";



バッチ処理によるベンチマークの結果









method性能(qps)
ジョブの登録(set)13806
ジョブの取得と削除(get & delete)6956

速度的にも申し分無く、ktserverの使用物理メモリーサイズも162mと少なく、kctファイルサイズ(300万件)も774Mでした。
また、setが高速なのは非同期処理に向いていると思います。
ちなみにkctのオプションに「#bnum=6000000#msiz=2g#pccap=2g」を追加して試してみたところget, deleteが10%ほど速くなりましたが、そもそも用途として1回のみの「登録」、「取得」、「削除」が想定されるので、富豪的にしてもあまり意味ないですね。

テスト中に気になったこと




  • データ削除してもkctファイルサイズが小さくならない。むしろ813Mと少し大きくなった。

  • kcやktの管理コマンドでキューのリアルタイムの件数が取得できない。-onl付けても無理。

これらは次の方法でなんとかなりそうです。

kctのデフラグ


デフラグするには、ktserverを停止してからkyotocabinetのkctreemgrコマンドを実行します。


kctreemgr defrag /path/to/queue_master.kct


今回の環境では、800MB程度ならおそらく2秒くらいで完了します。
デフラグは、そんなに肥大化しないと思うのとパフォーマンスには影響がなさそうなので、わざわざ止めてまでやる必要ないかもしれません。また、どうしてもやりたい場合も、スレーブ側を止めて切り替えるとかいろいろ手はあると思います。

Net_KyotoTycoonでキューの件数を取得する


あとkctreemgr、kttimedmgr 、ktremotemgrなどでキューの件数を取得してみましたが、ktserverを停止しないと正しい値(count)は取れなかったためNet_KyotoTycoonで取得することにしました。スレーブ側なら停止して取得してもよいかもしれませんが、APIで取得できるのでそこまでしなくてもいいですね。



  • 必要なモジュールのインストール

pear channel-discover openpear.org
pear config-set auto_discover 1
pear install pear.phpunit.de/PHPUnit
pear install HTTP_Request2
pear install openpear/Net_KyotoTycoon-beta


<?php

require_once 'Net/KyotoTycoon.php';
$kt = new \Net\KyotoTycoon(array('host' => '127.0.0.1', 'port' => 10001, 'timeout' => 5));
$res = $kt->status();
echo $res['count'] . "\n";


もうこれは使うしかないですね。




2011年12月19日月曜日

CentOS 6.1でまだまだLAMP環境 PHP 5.3.8 インストール編



LAMPの「P」は、Perl、PHP、Pythonと様々なプログラミング言語ですが、今回はPHPをインストールします。
(これまでのインストールしたものは、CentOS 6.1Apache HTTP Server 2.2.21MySQL 5.5.19です。)
もうすぐバージョン5.4もリリースされそうですが、まだRC3なので安定板の最新バージョンである5.3.8をインストールします。ちなみにバージョン5.3.7のバグは、PHP界隈で今年の重大ニュースに入るのような・・・。

今回のphpインストール手順と同じ処理を行うバッチを作成しました。
管理者権限があれば次の1行でインストールできます。
ご使用になられた場合の損害は一切責任を負いませんのでご了承ください。


PHP 5.3.8 インストール(apc, xdebugなどの追加モジュールは含まず)
curl http://dl.dropbox.com/u/30648910/install/php/php.sh | env PHP_VERSION=5.3.8 sh



必要なモジュールのインストール




cd /usr/local/src
curl -L -o rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm
rpm -i rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm

yum install \
flex.x86_64 \
gd-devel.x86_64 \
libxml2-devel.x86_64 \
gettext-devel.x86_64 \
libxslt-devel.x86_64 \
libcurl-devel.x86_64 \
libtool-ltdl-devel.x86_64 \
re2c.x86_64 \
libmcrypt-devel.x86_64

ln -s /usr/local/mysql/lib /usr/local/mysql/lib64
ldconfig



ソースコードからPHP 5.3.8をインストールする




オプションはいろいろ付けてます。
開発環境ならいろいろ入れた方がよいかと思います。
本番環境では、必要なもの以外は除去してビルドするのがよいでしょう。
しかし、最近のサーバはメモリー容量も多いので、後で使うかも?とか、汎用的なサーバにしたいとか、開発環境と同じオプションでなければテストにならない!という心配性の方は、同じオプションでよいと思います。
ただし、AWS EC2(small,micro)やVPSのようなメモリーが少ない環境では、使うのもだけ付けるのがよいのは言うまでもありません。あとはお好みで。

cd /usr/local/src
curl -L -o php-5.3.8.tar.gz http://jp2.php.net/get/php-5.3.8.tar.gz/from/jp.php.net/mirror
tar zxfv php-5.3.8.tar.gz
cd php-5.3.8
./configure \
--prefix=/usr/local/php \
--with-apxs2=/usr/local/apache2/bin/apxs \
--enable-mbstring \
--enable-mbregex \
--enable-zend-multibyte \
--with-libdir=lib64 \
--with-mysql=/usr/local/mysql \
--with-mysqli=/usr/local/mysql/bin/mysql_config \
--with-pdo-mysql=/usr/local/mysql \
--with-gd \
--with-jpeg-dir=/usr \
--with-png-dir=/usr \
--with-xpm-dir=/usr \
--with-libxml-dir=/usr \
--with-freetype-dir=/usr \
--with-gettext \
--with-zlib \
--with-openssl \
--with-mcrypt \
--with-xsl \
--with-curl \
--enable-gd-native-ttf \
--enable-gd-jis-conv \
--enable-exif \
--enable-soap \
--enable-sockets \
--enable-zip

make
make install

cp php.ini-development /usr/local/php/lib/php.ini



パスの追加





  • bashの場合

echo "PATH=\$PATH:/usr/local/php/bin" >> $HOME/.bashrc
source $HOME/.bahrc


  • zshの場合

echo "PATH=\$PATH:/usr/local/php/bin" >> $HOME/.zshrc
source $HOME/.zshrc



コマンドでバージョンや設定を確認する





  • バージョン情報

php -v


PHP 5.3.8 (cli) (built: Dec 19 2011 12:34:56)
Copyright (c) 1997-2011 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2011 Zend Technologies



  • 設定情報

php -i | grep iconv


Registered Stream Filters => zlib.*, convert.iconv.*, mcrypt.*, mdecrypt.*, string.rot13, string.toupper, string.tolower, string.strip_tags, convert.*, consumed, dechunk
iconv
iconv support => enabled
iconv implementation => glibc
iconv library version => 2.12
iconv.input_encoding => ISO-8859-1 => ISO-8859-1
iconv.internal_encoding => ISO-8859-1 => ISO-8859-1
iconv.output_encoding => ISO-8859-1 => ISO-8859-1




ライブラリーや拡張モジュールのインストール


PHPでは、pear、peclコマンドを使用して標準ライブラリーや拡張モジュールをインストールします。
いくつかインストールしてみます。



  • apc (PHPアクセラレータ)

pecl install apc
デフォルトのまま[Enter]キーを押しつづければインストールできます。


  • xdebug (デバッグ用エクステンション)

pecl install xdebug


  • php.iniの修正

これらの拡張モジュールを有効にするには、php.iniに設定を追記します。

上記2つのモジュールを有効にする場合
vi /usr/local/php/lib/php.ini
extension=apc.so
extension=xdebug.so

php.iniを書き換えて保存したらapacheを再起動します。
/usr/local/apache2/bin/apachectl graceful


  • pearのアップグレード

pear upgrade PEAR
pear upgrade-all


  • Net_IPv4のインストール

pear install Net_IPv4




apacheの設定例




ここでは、VirtualHostに追加する場合の例です。
<VirtualHost *>
 ServerName www.example.com

 DocumentRoot /path/to/example/htdocs
 DirectoryIndex index.php index.html

 ErrorLog  "|/usr/local/sbin/cronolog /usr/local/apache2/logs/example/error_log.%Y-%m-%d"
 CustomLog "/usr/local/apache2/logs/example/access_log.%Y-%m-%d" combined

 <FilesMatch \.php$>
  SetHandler application/x-httpd-php
 </FilesMatch>

 <Directory /path/to/example/htdocs>
  Order Deny,Allow
  Deny from all
  Allow from all
      Options All -Indexes
 </Directory>
</VirtualHost>




インストールされるモジュール




freetype-2.3.11-6.el6_1.8.x86_64
fontconfig-2.8.0-3.el6.x86_64
libjpeg-6b-46.el6.x86_64
libpng-1.2.46-1.el6_1.x86_64
libICE-1.0.6-1.el6.x86_64
xorg-x11-proto-devel-7.4-35.el6.noarch
libSM-1.1.0-7.1.el6.x86_64
libtiff-3.9.4-1.el6_0.3.x86_64
freetype-devel-2.3.11-6.el6_1.8.x86_64
libXau-1.0.5-1.el6.x86_64
libxcb-1.5-1.el6.x86_64
libXau-devel-1.0.5-1.el6.x86_64
atk-1.28.0-2.el6.x86_64
libxcb-devel-1.5-1.el6.x86_64
fontconfig-devel-2.8.0-3.el6.x86_64
libpng-devel-1.2.46-1.el6_1.x86_64
libjpeg-devel-6b-46.el6.x86_64
jasper-libs-1.900.1-15.el6.x86_64
cvs-1.11.23-11.el6_0.1.x86_64
gettext-0.17-16.el6.x86_64
hicolor-icon-theme-0.11-1.1.el6.noarch
avahi-libs-0.6.25-11.el6.x86_64
gettext-libs-0.17-16.el6.x86_64
libtasn1-2.3-3.el6.x86_64
gnutls-2.8.5-4.el6.x86_64
cups-libs-1.4.2-39.el6_1.1.x86_64
libgpg-error-devel-1.7-3.el6.x86_64
libgcrypt-devel-1.4.5-5.el6_1.2.x86_64
alsa-lib-1.0.21-3.el6.x86_64
pixman-0.18.4-1.el6_0.1.x86_64
libXdmcp-1.0.3-1.el6.x86_64
libXdmcp-devel-1.0.3-1.el6.x86_64
libthai-0.1.12-3.el6.x86_64
libmcrypt-2.5.7-1.2.el6.rf.x86_64
zip-3.0-1.el6.x86_64
libart_lgpl-2.3.20-5.1.el6.x86_64
libxslt-1.1.26-2.el6.x86_64
libxml2-devel-2.7.6-1.el6.x86_64
libX11-common-1.3-2.el6.noarch
libX11-1.3-2.el6.x86_64
libXext-1.1-3.el6.x86_64
libXrender-0.9.5-1.el6.x86_64
libXfixes-4.0.4-1.el6.x86_64
cairo-1.8.8-3.1.el6.x86_64
libXrandr-1.3.0-4.el6.x86_64
libXi-1.3-3.el6.x86_64
libXpm-3.5.8-2.el6.x86_64
libX11-devel-1.3-2.el6.x86_64
gd-2.0.35-10.el6.x86_64
libXtst-1.0.99.2-3.el6.x86_64
libXcomposite-0.4.1-2.el6.x86_64
libXcursor-1.1.10-2.el6.x86_64
libXdamage-1.1.2-1.el6.x86_64
libXft-2.1.13-4.1.el6.x86_64
pango-1.28.1-3.el6_0.centos.5.x86_64
libXinerama-1.1-1.el6.x86_64
gtk2-2.18.9-6.el6.centos.x86_64
libgcj-4.4.5-6.el6.x86_64
libXt-1.0.7-1.el6.x86_64
libXpm-devel-3.5.8-2.el6.x86_64
gd-devel-2.0.35-10.el6.x86_64
gettext-devel-0.17-16.el6.x86_64
libxslt-devel-1.1.26-2.el6.x86_64
libmcrypt-devel-2.5.7-1.2.el6.rf.x86_64
re2c-0.13.5-1.el6.rf.x86_64
flex-2.5.35-8.el6.x86_64
libidn-devel-1.18-2.el6.x86_64
libcurl-devel-7.19.7-26.el6_1.2.x86_64
libtool-ltdl-2.2.6-15.5.el6.x86_64
libtool-ltdl-devel-2.2.6-15.5.el6.x86_64


Linux(CentOS)、Apache、MySQL、PHPのインストールが完了してLAMP構成となりました。
情報閲覧系のサイトならピュアPHPでもある程度作れる環境になったと思います。

ソースコードでインストールするといろいろなオプションがあることに気づくと思います。
また、1つではなく複合的な技術で成り立っているのもよくわかるのではないでしょうか。
実は、全部yumだけでインストール可能なんですが、あえてやらない方が仕様とか理解が深まりますね。




2011年12月11日日曜日

CentOS 6.1でまだまだLAMP環境 OSインストール編



Webサービスを構築するソフトウェアは、LAMP(Linux, Apache, MySQL, Perl or PHP or Python)がよく使われていますが、最近は、LAMP以外のプログラミング言語、データベース、KVS、キャッシュなどの様々な技術を用いることも多くなり、ここ数年で選択肢がかなり広がった印象があります。

nginxやnode.jsのように、イベント駆動やノンブロキッキングの処理に注目があつまっていたり、
HTML5を用いたリアルタイムWebなど新しい技術なしでは実装が難しいというのも理由かもしれません。

そんな状況で、LAMPという言葉自体はもう古いものですが、中身は古くなったというよりは、安定してかつ新しい機能やライブラリーも増えてより便利になったという印象です。また、他が注目されているとはいえ、まだまだ多くのWebサービスを支えている技術はLAMPであるのもまた事実です。これまでのノウハウが活用できるというのもメリットですぐにやめられない理由の1つだと思います。

そんな当たり前の技術となったLAMPですが、CentOS 6.1がリリースされたタイミングなので、
最近のバージョンで、LAMP構成のサーバを作成してみようと思います。
これからWebエンジニアを目指す人でも、クラウドの時代でも、最低限知っておいて損はないと思います。

まずは、CentOS 6.1のインストールから


  • CentOS 6.1 インストール事前準備

  • CentOS 6.1 インストール(最小構成)

  • よく使うコマンドのインストールと環境構築

  • sshの鍵作成

  • LAN以外からの22番ポート(ssh)へアクセスを不可にする

  • この手順でインストールしたモジュール(依存関係も含む)




CentOS 6.1 インストール事前準備



▼ファイルをダウンロードする
http://ftp.jaist.ac.jp/pub/Linux/CentOS/6.1/isos/x86_64/CentOS-6.1-x86_64-bin-DVD1.iso
http://ftp.jaist.ac.jp/pub/Linux/CentOS/6.1/isos/x86_64/CentOS-6.1-x86_64-bin-DVD2.iso
※以下の作業で必要なのは、CentOS-6.1-x86_64-bin-DVD1.isoのみ

▼ダウンロードしたファイルをDVD-Rに焼く
Macの場合は、標準のディスクユーティリティで作成可能
1. [アプリケーション]→[ユーティリティ]→[ディスクユーティリ]を開く
2. [ディスクを作成]をクリック
3. ダウンロードした[CentOS-6.1-x86_64-bin-DVD1.iso]を選択して[ディスクを作成]ボタンをクリック
4. DVD-Rをセットする
5. [ディスクを作成]ボタンをクリック

しばらく待てばできあがり。
必要であれば、[CentOS-6.1-x86_64-bin-DVD2.iso]も同様の手順で焼く



CentOS 6.1 インストール(最小構成)




▼インストールメディアから起動
1. サーバ電源ON
2. 先ほど焼いたメディア(DVD)をサーバにセットする
3. DVDから起動したら[Enter]キーを押す
※DVDで起動しない場合は、BIOSの設定変更が必要

4. Install or upgrade an existing systemを選択して[Enter]キーを押す
5. [SKIP]を選択して[Enter]キーを押す
※事前にDVDをチェック済みなので。メディアをチェックしたい場合はそのまま[OK]をクリック
6. [Next]を選択してクリック

▼インストールする言語の選択
7. [Japanese]を選択して[Next]をクリック
8. [日本語]を選択して[次へ]をクリック

▼インストールするストレージデバイスの選択
9. [基本ストレージデバイス]を選択して[次へ]をクリック
10. [新規インストール]を選択して[次へ]をクリック

▼ホスト名の設定(適宜変更してください)
11. ホスト名を入力して同じ画面の[ネットワークの設定]をクリック
例 sv.example.local

▼ネットワークの設定(適宜変更してください)
12. [有線]タブの[System eth0]を選択して[編集...]ボタンをクリック
13. [自動接続する]にチェックをつける

サーバ用途なのであまりないと思いますが、[DHCP]を使用する場合は14-16の手順は不要

14. [IPv4のセッティング]タブをクリックする
15. 方式を[自動(DHCP)]から[手動]に変更する
16. [追加]ボタンをクリックして次の項目を入力する


設定例 (環境にあわせて変更してください)
アドレス : 192.168.1.100
ネットマスク : 24 (または255.255.255.0)
ゲートウェイ : 192.168.1.1
DNSサーバ : 8.8.8.8 (例 Google Public DNS)
ドメインを検索:example.local


17. [適用]ボタンをクリック
18. [閉じる]ボタンをクリック
19. [次へ]をクリック

▼時間の設定(適宜変更してください)
20. [アジア/東京]を選択する
21. [システムクロックでUTCを使用]のチェックを外す
22. [次へ]をクリック

▼管理者パスワードの設定
23. [rootのパスワードと[確認]にパスワードを入力する
24. [次へ]をクリック

▼ディスク構成(適宜変更してください)
25. [すべての領域を使用する]を選択する
26. [パーティションのレイアウトをレビューまたは修正]を選択する
27. [次へ]をクリック
28. [lv_home]を選択して[削除]ボタンをクリック
29. [削除]ボタンをクリック
30. [lv_root]を選択して[編集]をクリック
31. サイズにし最大値を入力して[OK]ボタンをクリック
32. [次へ]ボタンをクリック
33. [変更をディスクに書き込む]ボタンをクリック
34. [次へ]をクリック

▼インストールオプションの選択(最小構成)
35. [Minimal]を選択して[次へ]をクリック
36. インストールが完了したら[再起動]ボタンをクリックする



よく使うコマンドのインストールと環境構築




ここからは外部(インターネットなど)からこのサーバへアクセスできない環境での作業を前提とする
▼セットアップ
ここからはリモートで作業する
ssh root@192.168.1.100
管理者用パスワードを入力してログインする

▼モジュールアップデート


yum -y update


▼SELinuxの無効化


setenforce 0

vi /etc/sysconfig/selinux
#SELINUX=enforcing
SELINUX=disabled

完全に無効化するには再起動が必要
reboot

再起動後にgetenforceコマンドでDisabledと表示されればOK


▼シェルをzshに変更する(zsh好きなら)


yum -y install zsh
chsh -s /bin/zsh

変更可能なシェル確認
chsh --list-shells


▼コピー関連コマンド(rsync, scp)のインストール


yum -y install \
rsync.x86_64 \
openssh-clients.x86_64


▼圧縮・解凍関連コマンド(unzip)のインストール


yum -y install \
unzip.x86_64


▼ネットワーク関連コマンド(dig, nslookup, whois, traceroute, tcpdump, telnet)のインストール


yum -y install \
bind-utils.x86_64 \
jwhois.x86_64 \
traceroute.x86_64 \
tcpdump.x86_64 \
telnet.x86_64


▼ソースのコンパイルに使用するモジュールのインストール


yum -y install \
autoconf.noarch \
automake.noarch \
cmake.x86_64 \
gcc.x86_64 \
gcc-c++.x86_64 \
make.x86_64 \
libtool.x86_64


あとはお好みで追加する。 wgetとか



sshの鍵作成




1. ssh-keygenコマンドを実行する
ssh-keygen -t rsa

下記のメッセージが表示される
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): [Enterキーを押す]
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase): [パスフレーズを入力してEnterキーを押す]
Enter same passphrase again: [再度パスフレーズを入力してEnterキーを押す]
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.

秘密鍵 : /root/.ssh/id_rsa
公開鍵 : /root/.ssh/id_rsa.pub

※scpコマンドなどで秘密鍵をリモートアクセスするPCに保存します。

3. 公開鍵authorized_keysに登録する
cat $HOME/.ssh/id_rsa.pub >> $HOME/.ssh/authorized_keys

4. アクセス権を変更する
chmod -R 700 $HOME/.ssh
chmod -R 600 $HOME/.ssh/*

5. 鍵のみの認証に変更(パスワード認証を許可しない)
vi /etc/ssh/sshd_config
PasswordAuthentication no

6. sshdを再起動する
/etc/init.d/sshd restart

以後、秘密鍵を使用してログインします。



LAN以外からの22番ポート(ssh)へアクセスを不可にする




vi /etc/sysconfig/iptables

次のように修正して保存する
修正前
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

修正後
-A INPUT -s 192.168.1.0/24 -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

iptablesを再起動する
/etc/init.d/iptables restart



この手順でインストールしたモジュール(依存関係も含む)




▼シェルをzshに変更する(zsh好きなら)


  • zsh-4.3.10-4.1.el6.x86_64



▼コピー関連コマンド(rsync, scp)のインストール


  • libedit-2.11-4.20080712cvs.1.el6.x86_64

  • openssh-clients-5.3p1-52.el6_1.2.x86_64

  • rsync-3.0.6-5.el6_0.1.x86_64



▼圧縮・解凍関連コマンド(unzip)のインストール


  • unzip-6.0-1.el6.x86_64



▼ネットワーク関連コマンド(dig, nslookup, whois, traceroute, tcpdump, telnet)のインストール


  • libpcap-1.0.0-6.20091201git117cb5.el6.x86_64

  • bind-libs-9.7.3-2.el6_1.P3.3.x86_64

  • bind-utils-9.7.3-2.el6_1.P3.3.x86_64

  • tcpdump-4.0.0-3.20090921gitdf3cb4.1.el6.x86_64

  • traceroute-2.0.14-2.el6.x86_64

  • jwhois-4.0-19.el6.x86_64

  • telnet-0.17-47.el6.x86_64

▼ソースのコンパイルに使用するモジュールのインストール


  • xmlrpc-c-1.16.24-1200.1840.el6_1.4.x86_64

  • mpfr-2.4.1-6.el6.x86_64

  • cpp-4.4.5-6.el6.x86_64

  • xmlrpc-c-client-1.16.24-1200.1840.el6_1.4.x86_64

  • perl-Pod-Escapes-1.04-119.el6_1.1.x86_64

  • perl-libs-5.10.1-119.el6_1.1.x86_64

  • perl-Pod-Simple-3.13-119.el6_1.1.x86_64

  • perl-Module-Pluggable-3.90-119.el6_1.1.x86_64

  • perl-version-0.77-119.el6_1.1.x86_64

  • perl-5.10.1-119.el6_1.1.x86_64

  • autoconf-2.63-5.1.el6.noarch

  • automake-1.11.1-1.2.el6.noarch

  • libgomp-4.4.5-6.el6.x86_64

  • kernel-headers-2.6.32-131.21.1.el6.x86_64

  • glibc-headers-2.12-1.25.el6_1.3.x86_64

  • glibc-devel-2.12-1.25.el6_1.3.x86_64

  • ppl-0.10.2-11.el6.x86_64

  • cloog-ppl-0.15.7-1.2.el6.x86_64

  • gcc-4.4.5-6.el6.x86_64

  • libstdc++-devel-4.4.5-6.el6.x86_64

  • gcc-c++-4.4.5-6.el6.x86_64

  • libtool-2.2.6-15.5.el6.x86_64

  • cmake-2.6.4-5.el6.x86_64

  • make-3.81-19.el6.x86_64



次回は、MySQLをインストールします。




2011年11月21日月曜日

apc_fetch() VS Memcached::get() - ローカル環境キャッシュパフォーマンス比較



ローカル環境でのキャッシュは、APCとMemcachedでどちらを使うか?
apc_fetchが手軽に利用できるのでこちらを使ってみましたが、
memcachedでいいんじゃないかと・・・気になったので計測してみました。
ただし、CLI環境です。
テスト環境(DELL PowerEdge R200改)









CPUIntel Xeon CPU X3360 2.83GHz (4core)
メモリ8GB
HDD1TB (Hitachi HDT721010SLA360)
OSCentOS 6.0 (2.6.32-71.29.1.el6.x86_64)


apcの設定



apc.enabled=On
apc.enable_cli=On
apc.shm_size="128M"



比較に使用したソースコード(PHP)


$id = 'testtest';
$test_data = array();
$mem = new Memcached();
$mem->addServer('/tmp/memcached.socket',0);

for ($i = 0; $i < 1000; $i++) {
$cur_array = array();
for ($j = 0; $j < 10; $j++) {
$cur_array[$j] = '0123456789abcdef';
}
array_push($test_data,$cur_array);
}

apc_store($id,$test_data,1000);
$mem->set($id,$test_data,1000);

$time_start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$res = apc_fetch($id);
}
$time_end = microtime(true);
$diff_apc = $time_end - $time_start;

$time_start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
$res = $mem->get($id);
}
$time_end = microtime(true);
$diff_mem = $time_end - $time_start;
echo 'APC : ' . $diff_apc . PHP_EOL;
echo 'Mem : ' . $diff_mem . PHP_EOL;



結果









関数平均処理時間(ms)
apc_fetch()10
Memcached::get5

結果は、memcachedが2倍速い
また、new MemcachedとaddServer()を毎回実行した場合でも、
0.5msほどしか影響しませんでした。
5msの違いでも、10000回実行すると50秒差が出ます。
パフォーマンス優先ならmemcachedですね。

ちなみにmemcachedでunix socketを使用していますが、
IPアドレス(127.0.0.1)でのアクセスでも同程度の処理速度となりました。
ローカル環境でtcpポートの枯渇が気になる場合は、unix socketがオススメです。




2011年11月5日土曜日

今さら人には聞けないMySQLの話(いにしえのold-passwordsオプション for MySQL5.5)



Perl使いもお世話になっていると思われるphpMyAdminで
MySQLにログインできないことが・・・・あった・・・。


#2000 MySQL サーバにログインできません


というわけで接続確認したところ


<?php
$dbh = mysql_connect("127.0.0.1","ユーザー名","パスワード") or die(mysql_error());


このようなエラーメッセージが、以下抜粋


mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication.
Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password').
This will store a new, and more secure, hash value in mysql.user.
If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords flag from your my.cnf file


つまり、MySQL4.1以前の古い安全ではない認証では接続できないので、
old-passwordsオプション外して、パスワード再設定してよ!ってことらしい。
http://dev.mysql.com/doc/refman/5.5/en/old-client.html

それならold-passwordsオプションで起動できないようにしてほしいような気もするが。
起動はできるしパスワードも設定できるんだな。
MySQL4.0など古いDBのデータ移行やmy.cnfの設定引き継いだ場合は注意が必要です。

というか、old-passwordsオプション使ってたんだ・・・。