2016年4月28日 星期四

Singleton Design Pattern PHP 實作


突然發現自己關於 PHP 的部分寫得很少
補一篇 Singleton Pattern
最簡單也最實用

網路上有篇舉例得很好
說我們建立了一個類別 P
裡面可能呼叫(或載入)了其他的類別(如 C, D, E)
在某些情況下
我們並不希望類別 P 被重複呼叫多次時
類別 C D E 被重複建立
所以才會有這個 Singleton 的策略模式

實作如下
Controller
<?php
Class Test_Controller
{
public $load = null;
public $db = null;
public function __construct()
{
$this->init();
}

private function init()
{
# 載入共用的 loader
$this->load = load::instance();
# 取得 db 連線
$this->db = $this->load->database();
}

public function __destruct()
{
if(@$this->db) $this->db->close();
}
}


Loader
<?php
final class load
{
static $load = null;
static $db = null;
static $api = null;
public static function instance()
{
if(self::$load == null)
{
self::$load = new load();
}
return self::$load;
}
public static function database($host_name = 'test_cloud', $db_name = '')
{
if(self::$db == null)
{
self::$db = new db();
}
return self::$db->$host_name($db_name);
}
}


之後就可以測試看看
當你呼叫(或繼承) Test_Controller 多次之後
load 跟 db 應該都只會有一個實體

以前對於 Singleton 的認知
只是減少了一些不必要的呼叫
對於小公司而言
感受不大

直到目前轉到電商工作之後
才發覺
在大量被訪問的狀況之下
主機的記憶體與DB的連線數
是需要被嚴格控管的
不然硬體在怎麼擴充都不夠

尤其 database transaction 的問題
如果沒有用 Singleton 的話
commit 會亂七八糟的

所以認識 Singleton Pattern 真的是很重要的一件事情
提供給大家參考

2016年4月26日 星期二

RabbitMQ Cluster + HaProxy

RabbitMQ Cluster + HaProxy

套件版本
RabbitMQ 3.6.1
Erlang 18.3
Java JDK 8u91
HaProxy 1.5.14

4台主機
HaProxy   172.20.10.10
MQ_Master 172.20.10.11
MQ_Slave1 172.20.10.12
MQ_Slave2 172.20.10.13

# RabbitMQ Cluster 實作
請參考 RabbitMQ 3.6.1 Cluster 安裝

# HaProxy 安裝
yum install haproxy

# HaProxy 設定
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

frontend  RabbitmqWeb
    bind *:35672
    mode http
    default_backend             RabbitmqCluster:15672

backend RabbitmqCluster:15672
    log global
    balance     roundrobin
    cookie  SERVERID insert indirect nocache
    server  mq_master 172.20.10.11:15672 inter 10s check cookie s1
    server  mq_slave1 172.20.10.12:15672 inter 10s check cookie s2
    server  mq_slave2 172.20.10.13:15672 inter 10s check cookie s3

listen stats:8888
    bind *:8888
    mode http
stats enable
stats hide-version
stats realm Haproxy\ Statistics
stats uri /
stats auth admin:haproxy
stats refresh 10s

frontend RabbitmqServer
    log global
    bind *:45672
    mode tcp
option tcplog
option logasap
timeout client 168h
    default_backend  RabbitmqCluster:5672

backend RabbitmqCluster:5672
    mode tcp
timeout server 168h
    balance   roundrobin
    server mq_master 172.20.10.11:5672 check inter 1000 fall 3 rise 3
    server mq_slave1 172.20.10.12:5672 check inter 1000 fall 3 rise 3
    server mq_slave2 172.20.10.13:5672 check inter 1000 fall 3 rise 3

# 啟動 HaProxy
systemctl start haproxy
systemctl enable haproxy

# HaProxy 介面
172.20.10.10:8888

# RabbitMQ Web 登入介面
172.20.10.10:35672


# RabbitMQ amqp-lib 設定
define('HOST', '172.20.10.10');
define('PORT', 45672);


2016年4月21日 星期四

RabbitMQ 3.6.1 Cluster 安裝

預備三台機器做 RabbitMQ Cluster
IP 分別為 172.20.10.11~13

套件版本為
RabbitMQ 3.6.1
Erlang 18.3
Java JDK 8u91

# 修改三台 hostname
172.20.10.11$ hostnamectl set-hostname mq_master
172.20.10.12$ hostnamectl set-hostname mq_slave1
172.20.10.13$ hostnamectl set-hostname mq_slave2

# reboot 之後才會生效(以下 all 的動作包含全部的 master & slave)
all$ reboot

# 設定 hosts
all$ vi /etc/hosts

# 加上所有 nodes 的資料
172.20.10.11
172.20.10.12
172.20.10.13

# 安裝 rabbitmq, 作法請參考上一篇的 Centos7 + Rabbitmq
rabbitmq 3.6.1 安裝流程

# 啟動 rabbitmq
all$ rabbitmq-server -detached

# 備份 erlang cookie
all$ cp /root/.erlang.cookie /root/erlang.cookie.bak

# 關閉 rabbitmq(注意, 以下動作包含全部的 slave, 本文則是指 slave1 & slave2)
mq_slave1$ rabbitmqctl stop

# 將 .erlang.cookie 的資料從 mq_master 複製過來(必須是相同的 cookie, 才可加入同一個 cluster)
mq_slave1$ scp root@mq_master:/root/.erlang.cookie /root/

# 啟動 rabbitmq
mq_slave1$ rabbitmqctl start

# 啟動 rabbitmq_management
mq_slave1$ rabbitmqctl enable rabbitmq_management

# 停止 cluster node
mq_slave1$ rabbitmqctl stop_app

# 加入 mq_master 的 cluster
mq_slave1$ rabbitmqctl join_cluster rabbit@mq_master

# 啟動 cluster node
mq_slave1$ rabbitmqctl start_app

# 回到 mq_master 查看 cluster 狀態(重複處理其他的 slave)
mq_master$ rabbitmqctl cluster_status
 # 連到 rabbitmq_management 查看狀態

2016年4月19日 星期二

CENTOS 7 安裝 RabbitMQ 3.6.1

最近要重新架構系統
所以抓了新版的 RabbitMQ 來試試看
跟之前的安裝方式有點不同
不需要在編譯了
步驟簡單很多

安裝套件如下
erlang 18.3
rabbitMQ 3.6.1
php-amqplib 2.6.2

================= 安裝 erlang ==================
# 安裝 ncurses-devel / 核心依賴文件
yum install -y wget unixODBC-devel fop gcc-c++ ncurses-devel openssl-devel autoconf

# 透過 wget 下載 Java JDK(到 www.oracle.com 取得最新的 Java JDK)
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u91-b14/jdk-8u91-linux-x64.rpm"

# 安裝 Java JDK
rpm -ivh jdk-8u91-linux-x64.rpm

# 安裝 erlang / RabbitMQ伺服器是用Erlang語言編寫的 (連至 http://www.erlang.org/download.html 查看最新文件)
wget http://erlang.org/download/otp_src_18.3.tar.gz

# 解壓縮
tar zxvf otp_src_18.3.tar.gz
cd otp_src_18.3

# 組態(可看有那些沒裝好)
./configure

# 建立檔案與安裝(超久)
make && make install

# 測試 erlang 是否安裝成功, "." 為 erlang 的結束符號
erl
9+3.

# halt(). 結束執行
halt().

# 安裝 rabbitMQ
wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.1/rabbitmq-server-generic-unix-3.6.1.tar.xz
xz -d rabbitmq-server-generic-unix-3.6.1.tar.xz
tar -xvf rabbitmq-server-generic-unix-3.6.1.tar

# 搬移到 /usr/local/bin 底下管理
mv rabbitmq_server-3.6.1 /usr/local/bin

# 加到 bin 方便操作
ln -s /usr/local/bin/rabbitmq_server-3.6.1/sbin/* /usr/bin

================== rabbitMQ 指令 ==================
# 啟動 rabbitmq-server
rabbitmq-server

# 背景執行
rabbitmq-server -detached

# 新增使用者
rabbitmqctl add_user admin 12345

# 設定管理者權限
rabbitmqctl set_user_tags admin administrator

# 給予管理者權限
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"

================== 安裝 rabbitMQ Management ==================
# 啟動 rabbit_management
rabbitmq-plugins enable rabbitmq_management
rabbitmq-plugins enable amqp_client

# 打開 rabbitmq management 的 port 15672
firewall-cmd --zone=public --add-port=15672/tcp --permanent
firewall-cmd --reload

# 開啟網頁
http://127.0.0.1:15672

================== 安裝 php-amqplib ==================
# 先安裝 php 依賴文件 composer
curl -sS https://getcomposer.org/installer | php

# 安裝 php-bcmath php-mbstring
yum install php-bcmath php-mbstring

# 建立 composer.json
vi composer.json
內容如下
{
  "require": {
      "php-amqplib/php-amqplib": "2.6.*"
  }
}

# 安裝
php composer.phar install


新版的 rabbitmq 畫面保持一貫的簡潔