おぼえがき

おぼえがき

redisクラスタxマスタースレーブ構成でリアルタイムアクセス解析

2015-06-16 | php
redis cluster を マスタースレーブ構成でレプリケーション張って、php-redisを利用した、リアルタイムアクセス解析を作ってみた。





■構成

サーバー全部で6台
3台でクラスタ構成その下にスレーブをぶら下げる


■永続性

まだ、怖いから1日に1回データをフラッシュさせる

■データ構成

データ型 sorted set
キー access_monitor:id:${ユーザーID}
スコア unixtime
バリュー アクセスされたURL\x09リファラ\x09アクセスしてきたID\x09unixtime(タブ区切り)

スコアに、unixtimeを入れることにより、最新のアクセス順みたいな感じでデータが取れる

■インストール

redis 3.01
php-redisは、クラスタ構成 に対応していないから(2015/06/16現在)、ここから、もってきてクラスタ構成用の、RedisClusterが動くように無理やりやる

他にも、jemalloc-devel(3.6.0.1)も入れた

■クラスタを作る

sudo ./redis-trib.rb create --replicas 1 IPアドレス:ポート IPアドレス:ポート IPアドレス:ポート
※redis-trib.rbは、redis本家のソースコードの中に入ってる。

初めは、sudo gem install redisしてあげる必要がある。

□クラスタが上手く作れないその1

こんなエラーが出たときは、

client.rb:113:in `call': ERR Slot 16011 is already busy (Redis::CommandError)

redis-cli -c
>select 0
>flushdb
>flushall
をやると、クラスタ作れる。 
ただし、対象クラスタ全部やったほうが良い

□クラスタが作れないその2

クラスタを作るとき、nodes.confを作ると思うけど、再構築する際は、こいつの中身消したほうが良い

他にも、
17067: * Increased maximum number of open files to 10032 (it was originally set to 1024).
17067: * Node configuration loaded, I'm xxxxxe94c3dc311e558e3015ff1e51fe362c530d
17067: # Creating Server TCP listening socket *:16379: bind: Address already in use
とか、出たけど

全体の流れとして、
slect 0
flusdb
flushall
とかで、データ全部消して、
/etc/init.d/redis restart
:>nodes.conf (ファイルの中身消す)

で、
sudo ./redis-trib.rb create --replicas 1 IPアドレス:ポート IPアドレス:ポート IPアドレス:ポート IPアドレス:ポート IPアドレス:ポート IPアドレス:ポート

こんな感じで作れるはず

■redis.conf

こんな感じにした(自信なし)
=====
daemonize no
pidfile /var/run/redis.pid
port 6379
tcp-backlog 511
timeout 300
tcp-keepalive 60
loglevel notice
logfile /var/log/redis/redis.log
databases 16
### SNAPSHOTTING
save ""
dir /var/lib/redis/
####REPLICATION
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync yes
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
### SECURITY
### LIMITS
maxclients 10000
maxmemory 1g
maxmemory-policy volatile-ttl
maxmemory-samples 5
###APPEND ONLY MODE
appendonly no
appendfsync no
no-appendfsync-on-rewrite no
###LUA SCRIPTING
lua-time-limit 5000
###REDIS CLUSTER
cluster-enabled yes
cluster-config-file /etc/redis/nodes.conf
cluster-node-timeout 5000
###SLOW LOG
slowlog-log-slower-than 10000
slowlog-max-len 128
####LATENCY MONITOR
latency-monitor-threshold 0
###EVENT NOTIFICATION
notify-keyspace-events ""
### ADVANCED CONFIG
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
#client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync no
=====

■php-redisを利用してみる

define('REDIS_CONNECT_PORT' , 'srv101:6379,srv102:6379,srv103:6379,srv104:6379,srv105:6379,srv106:6379');

#アクセス情報をredisクラスタに格納
$port=explode( ',' , REDIS_CONNECT_PORT );
$redis_obj = new RedisCluster('cluster', $port);
$redis_obj->zadd(${KEY}, $unixtime_now, $value);

#最新のアクセス順で取得(スコアも一緒に取得)
$redis_obj->zrangebyscore(${KEY}, $unixtime_from, $unixtime_to, array('withscores' => TRUE));

■tips

・php-redis入れたら、apacheリスタート

・データの一括投入(クラスタ構成だと、一部しかはいらないよ)
 perl -pe "s/\n/\r\n/g" ファイル | redis-cli --pipe -c
 上記コマンド、ファイルの中身
 set key_1 val1
 set key_2 val2

・フェイルオーバー
 マスターのクラスタの一台が死んだ場合、対応しているスレーブが自動でマスターに昇格。
 死んだマスターを復活させたら、今度は、スレーブとして起動するようになる(すごいね)

・クラスタの構成確認
 cluster nodes

・メモリ使用量の確認
 infoで、used_memoryを確認

・日本語入れてみる
 redis-cli -c
  127.0.0.1:6383> get title
  "\xa4\xa4\xa4\xa4\xa4\xa4"
  ってなかんじで、日本語が文字化けてしまう
 redis-cli -c --raw
  127.0.0.1:6383> get title
  いいい
 ちゃんと出る

・hash型にデータの一括投入
 $filed_values = array(
  'id' => ${id},
  'title' => ${title}
 );
 $redis_obj->hmset(${KEY}, $filed_values);


■アクセス解析に使った他のredisの型

zincrby(${KEY} . YYYYMMDDHH, 1, "/ページのurl");
これで、○時のアクセスランキング作れちゃう


以上、redis cluster x m-s構成でphp-redisを利用した、リアルタイムアクセス解析を作ってみる。でした。おしまい



fuelphpでバッチ処理(oil refineを利用する)

2013-04-17 | php
oil refineをちゃんと見る

バッチ処理を動かすときは、oil refineを利用するんだが、
ちょいとハマったところもあるので、まとめておく

バッチ処理は、全て、fuel/app/tasks/ここのディレクトリ
配下に配下に置くようになっている。


2 namespace Fuel\Tasks;
3 class Hoge
4 {
5 public static function run()
6 {
7 echo "hoge";
8 }
9 }


これを実行するには、oil refine hoge
runメソッドが実行される


2 namespace Fuel\Tasks;
3 class Hoge
 4 {
5 public static function run()
6 {
7 echo "hoge";
8 }
9 public static function sample()
10 {
11 echo "this is sample";
12 }
13 }


これを実行するには、oil refine hoge:sample
runメソッドではなく、オリジナルのメソッドが実行される


2 namespace Fuel\Tasks;
3 class Hoge
4 {
5 public static function run($a,$b)
6 {
7 echo $a;
8 echo $b;
9 echo "hoge";
10 }
11 public static function sample()
12 {
13 echo "this is sample";
14 }
15 }


これを実行するには、oil refine hoge AAA BBB
これで、runメソッドに引数を渡すことができる

そんざいする、タスクをタスクを確認する
Available tasks:
php oil refine install
php oil refine migrate:help
php oil refine session
php oil refine session:create
php oil refine session:remove
php oil refine session:clear
php oil refine session:help
php oil refine fromdb
php oil refine fromdb:help
php oil refine fromdb:scaffold
php oil refine fromdb:model
php oil refine hoge <------ お!入っている
php oil refine hoge:sample <------ お!入っている
php oil refine robots
php oil refine robots:protect


modelとかパッケージがなぜか呼べなかったが、
\モデル名
\Email::forge()

ってやればちゃんと呼ぶことができた。


ちなみに、oilコマンドでタスクの生成ができる(これ、ヘルプ oil g help に載ってない気がする)
oil g task test
ってやったら、tasks/配下にtest.phpとrunメソッドのスケルトンが生成されて
oil g task test2 subtest
ってやったら、tasks/配下にtest2.phpとrunメソッドとsubtestのスケルトンが生成される

おしまい。

fuelphp最小構成

2013-04-17 | php
インストール後に、welcomeページ出るんだけど、それを出すために
最低限必要なファイルは何なんだろうか。
コアクラス追っかけてみた。

結果は・・・
./app/bootstrap.php
./app/classes/controller/welcome.php
./app/config/config.php
./app/config/crypt.php
./app/config/routes.php
./app/logs/
./app/views/welcome/index.php
./core/base.php
./core/bootstrap.php
./core/classes/arr.php
./core/classes/asset.php
./core/classes/asset/instance.php
./core/classes/autoloader.php
./core/classes/config/file.php
./core/classes/config/ini.php
./core/classes/config/interface.php
./core/classes/config/json.php
./core/classes/config/php.php
./core/classes/config/yml.php
./core/classes/config.php
./core/classes/controller.php
./core/classes/cookie.php
./core/classes/event.php
./core/classes/event/instance.php
./core/classes/finder.php
./core/classes/fuel.php
./core/classes/inflector.php
./core/classes/input.php
./core/classes/module.php
./core/classes/profiler.php
./core/classes/route.php
./core/classes/request.php
./core/classes/response.php
./core/classes/router.php
./core/classes/security.php
./core/classes/uri.php
./core/classes/view.php
./core/config/asset.php
./core/vendor/phpquickprofiler/console.php
./core/vendor/phpquickprofiler/display.php
./core/vendor/phpquickprofiler/phpquickprofiler.php
./packages/log/

これらのファイルを通って、呼ばれて、welcome画面が表示される


基本的には、index.phpで
$response = Request::forge()->execute()->response();
ってやって、
$response->send();
で表示されるだけ。

なんか、何でこのクラスが必要なんだところもあるが、
もうちょい追っかければ分かると思う

fuelphpとビルトインウェブサーバー

2013-04-14 | php

FuelPHPをビルドインウェブサーバー(PHP5.4以上)で動かそうとしたら、

この辺をみて、mod_rewrite的なものを実装する必要があったけど、

fuelphp1.6-develop眺めてると、
fuelphpをビルドインウェブサーバーで動かすことができそうな予感。

やってみる。

1.6-developのoilパッケージをダウンロードしてくる

今、自分の環境はFuelPHPの1.5を使っている。

XXX/fuel/packages/oil
このoilディレクトリの1.6のoilに入れ替える。
(オリジナルをmvして、githubのやつをDLしてoilに置き換えただけ)

じゃぁー実際動かしてみる

$ls
 CHANGELOG.md CONTRIBUTING.md README.md TESTING.md build.xml
 docs fuel/ oil public/

$oil help
Usage:
 php oil [cell|console|generate|package|refine|help|server|test]

 お!serverオプションがある
 じゃぁ、起動してみる

$oil server
1
Listening on http://localhost:8000
Document root is public/
Press Ctrl-C to quit.

これで、ビルドインウェブサーバーが立ち上がった。
実際アクセスしてみる

wget http://localhost:8000/hello/hoge

うごいたうごいた。

oil/server.phpみると、まぁ、ただのラッパーだな

fuelphpでAssetsを利用して画面特有のcss,jsなどを呼び込む

2013-03-17 | php
前回、fuelphpでpjaxを扱うである画面だけ、pjaxのjsライブラリが必要だった。

テンプレートのベースである、templateファイルにpjaxのライブラリのパスを
書いてしまうと、使ってない画面までこのライブラリが呼ばれて無駄。
かと言って、個別テンプレートでそのライブラリを呼ぶのもいけてない。

assetsを利用してこの問題が解決できる。


■コントローラー

class Controller_Welcome extends Controller_Template
{
 public function action_index()
 {
  Asset::css(array('bootstrap.min.css', 'bootstrap-responsive.min.css','bootswatch.css'), array(), 'add_css', false);
  $this->template->content = View::forge('welcome/index');
 }

※ここで、'add_css'っていうグループを登録しておく


■テンプレート

<!DOCTYPE html>
<html lang="ja">
 <head>
  <meta charset="utf-8">
  <?php echo Asset::css('全てのテンプレートで呼ぶ.css'); ?>
  <?php echo Asset::js('全てのテンプレートで呼ぶ.js'); ?>
  <!-- 画面固有のCSS -->
  <?php echo Asset::render('add_css');?>


これで、コントローラー側で、add_cssグループに、CSSファイルがアサイン
されているときだけ、画面固有のCSSが表示されるようになる。

ちなみに、
<?php echo Asset::render('add_css',true);?>
ってやると、外部ファイルを呼ぶのではなくて、外部ファイルがここに
展開される

なるほどね