2015年3月30日

Bootstrap Grid System

Bootstrap 以 grid system 提供網頁畫面版面切割的功能,官方手冊上 Grid system 這個段落,將此功能定義為 a responsive, mobile first fluid grid system,這表示 grid 是符合 Responsive Web Design 的系統,而且在行動版畫面是以比例的方式 fluid 為主,如果是一個設計良好的 fluid 頁面,那麼在手機瀏覽該頁面時,就不會看到水平方向有產生 scroll bar,該說明內容也明確地提供了使用 grid 要注意的設定。

要注意的是,bootstrap 的 grid system 在 v2 與 v3 有一些不同的地方,以下我們只討論 v3 的 grid system。

fixed/fluid/elastic layout

Fixed vs. Fluid vs. Elastic Layout: What’s The Right One For You?

fixed layout 是以固定的寬度 px 設定元件的寬度,而 fluid layout 是以總寬度的百分比例,設定元件的寬度。elastic 則是認為,要混合使用 fixed 與 fluid layout。

elastic layout 認為除了考慮螢幕寬度之外,還要考慮 resolution,低解析度的螢幕就該要配置較大尺寸的文字與圖片。

以 bootstrap grid system 來說,是使用 fluid layout 來設計頁面 layout。因為它只考慮了寬度,沒有考慮解析度。

grid system

以 Grid 的方式設計網頁,並不只有 bootstrap 才提供這樣的功能,目前在討論 Responsive Web Design 時,都已經習慣以 grid 的方式進行網頁設計,所以有很多 web framework 都支援 grid system,例如 960gssusyblueprint

當 web designer 與 programmer 都能以 grid 的方式,進行網頁設計,這樣就能對網頁 layout 能有共同的認知,而不會在 web desinger 切割的 layout 圖片在實際上放入網頁時,發生偏移無法對齊的問題。

不過同樣都是在使用 grid system,必須要注意的是,共用的 grid 規則為何,因為每個 framework 使用的 gutter 與 padding 不一樣。

  1. 頁寬共分為幾欄,bootstrap 為 12 欄
  2. 欄和欄之間的間距 gutter,bootstrap 的 column 前後的 padding 為 15 px,所以 gutter 就是 15+15 = 30 px
  3. 主要文本和邊緣的間距 grid padding

ref:
使用 grid system 來設計你的網頁
Grid 的運用:PS外掛
Using the 960 Grid System as a Design Framework

bootstrap grid system

grid system 是以 rows 與 columns 的組合,建立頁面的 layout。

  1. 假設每一頁可切割為 12 個 columns
  2. row (行) 必須放在一個有 .container (fixed-width) 或是 .container-fluid (full-width,滿版,以比例方式設定欄寬) 的 div 中

  3. 類似 col-xs-6 的 css class,用來定義 column寬度,並放在 row 裡面,網頁內容放在 column 裡面

  4. grid columns 總共有 12 個,可以指定 3個 .col-xs-4 用來填滿 12 個 columns
  5. 如果一個 .row 有超過 12個 columns,則超過的部份就會自動折行

Grid Options

-- Extra Small devices (Phones) (<768px) SMall devices (Tablets) (>=768px) Medium devices (Desktops) (>= 992px) LarGe devices (Desktops) (>=1200px)
Grid Behavior 永遠都是 horizontal 一開始是收合的,如果超過寬度的設定值,就會顯示出來 同左 同左
Container width none(auto) 750px 970px 1170px
Class prefix .col-xs- .col-sm- .col-md- .col-lg-
# of columns 12 同左 同左 同左
Column width auto ~62px ~81px ~97px
Gutter width 30px (15px on each side of a column) 同左 同左 同左
Nestable Yes 同左 同左 同左
Offset Yes 同左 同左 同左
Column ordering Yes 同左 同左 同左

Nestable 就是在 row, column 裡面,可再加入一層 rows, columns,就像是在一個 table 的 column 裡面再放進一個 table
Offset 就是位移,當設定了 .col-md-offset-4 ,這個區塊就會向右位移 4 格 columns,兩個 columns 中間多了一塊空白區域
Column ordering 就是可以改變 column 的前後順序,當設定了 .col-md-push-3 ,則會在 .col-md 有作用時,將該區塊往右邊 push 3 格

grid system 的範例

有關 grid system 的範例可查閱這兩個網址
bootstrap grid
bootstrap grid examples

接下來,列出一些簡短的範例紀錄使用方法

當 md 有作用時,分為 8:4 兩塊

<div class="container">
    <div class="row">
        <div class="col-md-8">.col-md-8</div>
        <div class="col-md-4">.col-md-4</div>
    </div>
</div>

同時支援 Mobile, Desktop 的樣式,Mobile 時為 12:6,Desktop 時為 8:4

<div class="row">
    <div class="col-xs-12 col-md-8">.col-xs-12 .col-md-8</div>
    <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
</div>

同時支援 Mobile, Tablet, Desktop 的樣式,Mobile 時為 12:6,也就是兩行,Tablet 時為 6:6,Desktop 時為 8:4

<div class="row">
    <div class="col-xs-12 col-sm-6 col-md-8">.col-xs-12 .col-sm-6 .col-md-8</div>
    <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
</div>

同時支援 Mobile, Tablet 的樣式,Mobile 時為 6:6,因為加上了 clearfix 與 visible-xs-block,所以 xs 的部份重設了,就不會折行,Tablet 時為 4:4:4

<div class="row">
    <div class="col-xs-6 col-sm-4">.col-xs-6 .col-sm-4</div>
    <div class="col-xs-6 col-sm-4">.col-xs-6 .col-sm-4</div>
    <!-- Optional: clear the XS cols if their content doesn't match in height -->
    <div class="clearfix visible-xs-block"></div>
    <div class="col-xs-6 col-sm-4">.col-xs-6 .col-sm-4</div>
</div>

支援 Tablet,第二區塊,會往右位移 4 格

<div class="row">
    <div class="col-md-4">.col-md-4</div>
    <div class="col-md-4 col-md-offset-4">.col-md-4 .col-md-offset-4</div>
</div>

Nesting columns,把 row 放入 col 裡面

<div class="row">
  <div class="col-sm-9">
    Level 1: .col-sm-9
    <div class="row">
      <div class="col-xs-8 col-sm-6">
        Level 2: .col-xs-8 .col-sm-6
      </div>
      <div class="col-xs-4 col-sm-6">
        Level 2: .col-xs-4 .col-sm-6
      </div>
    </div>
  </div>
</div>

Column Ordering: 利用 .col-md-push- 與 .col-md-pull- 改變區塊的順序,第一塊大小為 9,往右 push 3 格,第二塊大小為 3 ,往左 pull 9 格

<div class="row">
    <div class="col-md-9 col-md-push-3">.col-md-9 .col-md-push-3</div>
    <div class="col-md-3 col-md-pull-9">.col-md-3 .col-md-pull-9</div>
</div>

Responsive utilities: visible hidden

Responsive utilities 為了快速建立 mobile-friendly 的網頁,div 元件還可以根據 device 的狀態,來決定要 顯示 或是 隱藏。

css class devices
.visible-xs-* Extra small (less than 768px) visible
.visible-sm-* Small (up to 768 px) visible
.visible-md-* Medium (768 px to 991 px) visible
.visible-lg-* Larger (992 px and above) visible
.hidden-xs Extra small (less than 768px) hidden
.hidden-sm Small (up to 768 px) hidden
.hidden-md Medium (768 px to 991 px) hidden
.hidden-lg Larger (992 px and above) hidden
.visible-print-* Visible when print
.hidden-print Visible only to browser not to print

所有 .visible-device- 後面都可以加上 css 的 display property value: inline, block, inline-block,換句話說,.visible-xs-* 的設定就可以是 .visible-xs-inline 或是 .visible-xs-block 或是 .visible-xs-inline-block

References

Bootstrap Grid System in w3schools
Bootstrap 2.x 與 3 的重要差異(二):grid系統的變革
15 款相當不錯的 Twitter Bootstrap 開發工具

使用 Bootstrap 建置雛型網站
簡單的Bootstrap效果(v 3.0.0 / v 3.2.0版)與入門教學 (#2 範例修正與下載)

淺談CSS Grid system
《LayoutIt!》視覺化Bootstrap線上編輯器

Twitter Bootstrap 框架簡化網頁開發、兼容不同裝置,讓網頁工程師兼設計師!

2015年3月23日

RWD Responsive Web Design

RWD Responsive Web Design 中文翻譯為響應式網頁設計或是適應性網頁設計,由於行動裝置盛行,為了能夠同時讓手機、平板電腦、一般PC電腦的瀏覽器能夠在不同的螢幕大小的條件下,都能夠在不縮放以及橫向捲動畫面的要求下,以最佳瀏覽體驗瀏覽一個網頁,同樣的網頁內容必須再藉由 RWD 要求要注意的幾項設計重點。

但我們倒可以直接將 RWD 翻譯為「負責任」的網頁設計,因為如果使用者同時會有不同螢幕大小的設備瀏覽網頁,網站設計者就必須「承擔起責任」,讓使用者能以最佳瀏覽體驗瀏覽網頁。

Ethan Marcotte

RWD 最早是在 2010 年由 Ethan Marcotte: A List Apart 提出的一項概念。

在文章的結論中提到 Fluid grids, flexible images, and media queries 是進行 RWD 時最重要的三項技術。

什麼時候要注意 RWD

在進行網頁設計前,有幾項設計需求是要先確認的,否則就可以決定不需要多花時間與人力進行 RWD 開發。

  1. 網站有沒有行動版的需求?
    如果在開發時就已經確定這個網站面對的使用者會使用手機、平板或是PC這三種類形的設備的某一種的瀏覽器,那麼我們就沒有必要花時間進行RWD

  2. 行動版跟PC版的網頁內容重複很多嗎?
    在一個網頁上進行 RWD,就表示我們在處理一個網頁的內容,但不同設備的呈現方式的問題。如果行動版的網頁內容在設計初期就決定要給使用者完全不同的呈現方式,那倒不如在使用者進入網頁後,就根據 media query 的結果,直接將使用者導向到不同的兩個網頁,一個是進入 PC 的網頁,一個是進入行動版的網頁。

如何實踐 RWD

以下內容是從 九個適應性設計小撇步,把你的網站打造成變形金剛!(上篇) 以及 九個適應性設計小撇步,把你的網站打造成變形金剛!(下篇) 兩篇文章中精簡得來的筆記。

讓圖片維持比例自動縮放

  1. 使用 img 標籤放置圖片

    當外層元素寬度縮到小於圖片時,圖片會自動縮小,不設定 width 屬性(或設定為 auto ),讓圖片維持不超過原始大小的寬高。

     <img id="imageid" src="xxx.png"></img>
    
     #imageid {
         height: auto;
         max-width: 100%;
     }
    
  2. 使用 CSS background 屬性

    可彌補 img 無法針對螢幕大小指定合適圖片的缺點。background-size 內兩個值分別代表背景圖的寬高。background-position 的兩個數值則分別指定背景圖片的水平及垂直位置,50% 表示置中。

     <div id="divid"></div>
    
     #divid {
         background-image: url(xxx.png);
         background-position: 50% 50%;
         background-repeat: no-repeat;
         background-size: 100% auto;
         display: block;
         height: 100px;
         width: 100%;
     }
    

讓 div 區塊內容自動往下排列

用 float 讓 div 區塊由右至左排列

用 inline-block 讓 div 區塊由左至右排列

讓 div 區塊置中

  1. 使用 display: block 時-固定寬度加上 margin: auto 屬性
    適用單一區塊水平置中,區塊的寬度設定為某個「小於上層元素」的數值,加上 margin: auto

  2. 使用 display: inline-block 時-在外層設定 text-align: center
    同一行內的多個 inline-block 可以一起置中

  3. 使用絕對定位時-margin: auto 加上左右定位
    用 position: absolute 做絕對定位,固定寬度,再加上 margin: auto,再設定左右位置兩個數值- left: 0; right: 0;

文字對齊

text-align: center 可以置中文字
text-align: justify 可左右分散對齊一整段文字

只要將上層元素設定為 display: table ,並在文字區塊元素上設定 display: table-cell; vertical-align: center; 即可將多行文字垂直置中。

<div id="content">
    <div id="vertical-text">
        大量的文字。
    </div>
</div>
#content > #vertical-text {
    display: table-cell;
    vertical-align: middle;
}

#content {
    border: 1px dotted gray;
    display: table;
    height: 240px;
    width: 100%;
}

排版避免設定高度及絕對位置,寬度設定儘量集中

利用 media query 修改寬度的 css class,不設定高度可讓區塊的內容自動將元件高度撐開。

當螢幕寬度小於 540px 時,文字區塊的寬度就會縮成 400px

.container {
    width: 500px;
}

@media only screen and (max-width: 540px) {
    .container {
        width: 400px;
    }
}

@media only screen and (max-width: 440px) {
    .container {
        width: 300px;
    }
}

隱藏暫不需要的選單、點擊後展開隱藏的頁籤

寬度拉到小於 400px 時,原本左邊的綠色選單就不見了,縮成一個綠色選單鈕,滑鼠放上去時選單就會自動展開

展開頁籤的內容

因為手機上畫面空間不足,通常不適合使用頁籤,這時不如把內容直接展開來,寬度縮到 400px 以下時三個頁籤的內容就會展開來。

使用 Firefox 特有開發工具

Firefox 15.0 以後,按下快速鍵 Ctrl+Shift+M (Windows 及 Linux 平台) 就可以使用適應性設計檢視 (Responsive Design View)。

References

響應式網頁設計 wiki

RWD 流言終結者

2015年3月16日

HAProxy and sticky session

在處理 HTTP Load Balance 的時候,很多網路服務都必須考量需不需要使用者登入後才能使用,以往不是 connection oriented 的 HTTP 也因此發展出 HTTP Session Tracking 的技術,在導入 HAProxy 時,也必須考量到,要如何持續支援 Session Tracking 的技術。

HTTP session

以往的網站在處理 session 時,會將 user 相關的資料存放在 client 端的 cookie 裡面,但 cookie 會在每一次 http request 都放在 header 裡面,因此產生了資訊安全的疑慮。

後來就發展了 Server Side 的 Session,以 J2EE jsessionid 為例,就是將 user 相關資料存放於 Server 的記憶體中,由 browser client 端 將一個 session id 紀錄起來,藉由這個 session id,來讓每一次同一個 browser 的所有 request 都可認定為同一個 user。

session 在 J2EE Server 可設定其時效,通常是設定為 10-20分鐘,當 server side session 的資料逾時,session 就會被清除,user 也必須重新登入一次,才能再執行接下來的工作。

通常 browser client 都有 enable cookie 的功能,可以將 session id 存放在 cookie 裡面,比較古老的 browser 沒有支援 cookie,或是 user 刻意將 cookie 功能 disabled 了,這時候 J2EE Server 會自動改用 URL Rewrite 的方式,將 jesssionid 存在 url 上面。

sticky session

當 server 要進行 load balance 的時候,通常會導入硬體或軟體的 load balancer,因為 J2EE Server 有存放了 session 資料,我們可選擇將 server 藉由 cluster 的方式,將 session 互相複製,但這種作法會消耗掉過多的 server side 資源,server 之間互相 replicate session 的次數越多,只會讓 dirty data 與 traffic 更頻繁,發生 data 錯誤的機會也會變高。

sticky session 通常是指 load balancer 支援了 session id 的處理能力,可以認出 http request 裡面的 jsessionid 的資料,並將同一個 jsessionid 的多個 request 都導向到同一個後端的 server 上。

load balancer 可選擇使用 J2EE 的 jessionid,或是使用自訂的 SERVERID 作為 sticky session 的判斷基準。

sticky session in HAProxy

HAProxy 要能夠支援 session id ,可以在 backend 的設定中增加 Cookie 的設定值。

設定說明如下:

cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
  • name
    就是 Cookie 的名稱,會透過 HTTP response 的 "Set-Cookie" header 將 Cookie 設定於 browser client。

  • rewrite | insert | prefix
    rewrite 表示 backend server 會提供此 cookie,但 HAproxy 必須修改此值,並將 server 的 id 填寫進去。因為必須監控所有 response 封包,所以只能在 HTTP close mode 運作。

    insert 表示此 cookie 必須由 HAPRoxy 填寫進去。如果沒有設定 preserve,而 server 也設定了此 cookie,則會先被移除,然後再重新新增進去。通常建議要搭配設定 "nocache" 與 "postonly"

    prefix 表示透過既有的一個 cookie,server id 會填寫到該 cookie 的 prefix 中,當 client 端發送 requst,其夾帶的 cookie value 會有 haproxy 填寫的 prefix,但會被 haproxy 去掉,只保留原本 server 設定的 cookie value,然後再 forward 給 server。

  • indirect
    server 設定的 cookie 都不會送到 client,這可讓 server 完全不知道 haproxy 的 sticky session 機制。

    建議不要同時使用 prefix 與 indirect

  • nocache
    搭配 insert 使用,可讓 cachable respone 貼上 non-cacheable 選項。

  • postonly
    確保 cookie insertion 只會作用在 responses to POST requests,這是 nocache 的替代方案,因為 POST response 都是 not cachable 的,就可以確保 persistence cookie 永遠不會被 cache。

  • preserve
    只能搭配 insert 與 indirect 使用。在這樣的狀況下,haproxy 會保留不更動 response cookie。

    可用在 logout request 之後,要 end persistence的地方,通常 server 會將 cookie 設定為空值。

  • httponly
    當 haproxy 增加新 cookie 時,同時設定了 HttpOnly 的屬性。

  • secure
    當 haproxy 增加新 cookie 時,同時設定了 Secure 的屬性。

  • domain
    設定 cookie 的 domain

  • maxidle
    idle 時間逾時後,cookie 就會沒有作用,只能用在 insert-mode cookies

  • maxlife
    life time 逾時後,cookie 就會沒有作用,只能用在 insert-mode cookies

範例:

cookie JSESSIONID prefix
cookie SRV insert indirect nocache
cookie SRV insert postonly indirect
cookie SRV insert indirect nocache maxidle 30m maxlife 8h

實際上比較完整的範例為

backend web_server_cluster
    mode http
    balance roundrobin
    cookie SERVERID insert indirect nocache
    # Web Server Cluster
    server web1 192.168.1.10:80 check cookie s1
    server web2 192.168.1.20:80 check cookie s2

直接在 JSESSIONID 上加上 server id 的 prefix

frontend ft_web
  bind 0.0.0.0:80
  default_backend bk_web

backend bk_web
  balance roundrobin
  cookie JSESSIONID prefix indirect nocache
  server s1 192.168.1.10:80 check cookie s1
  server s2 192.168.1.20:80 check cookie s2

appsession

設定說明

appsession <cookie> len <length> timeout <holdtime> [request-learn] [prefix] [mode <path-parameters|query-string>]
  • cookie
    application 使用的 cookie name,可讓 haproxy 了解到該 application 處理 session 的 cookie。

  • length
    該 cookie value 儲存的最大字元長度。

  • holdtime
    該 cookie 值不被使用時,保留在 haproxy 記憶體中的時間

  • request-learn
    設定後,haproxy 會由 request 中發現新的 session

  • prefix
    設定 haproxy 將會認定的 cookie prefix

    範例

      appsession ASPSESSIONID len 64 timeout 3h prefix
    

    如果 cookie 是 ASPSESSIONIDXXXX=XXXXX,appsession 的 value 將會是 XXXX=XXXXX

  • mode
    修改 URL parser mode,目前有兩種

    • path-parameters
      這是預設模式,在 path parameter 的裡面尋找 appsession。適用於 JSESSIONID,通常會是在分號的後面。

      當 browser client 不支援 cookie 時,jsessionid 就會放在 url 上面

        a.jsp;jsessionid=5AC6256DD8D4D5D1FDF5D41E9F2FD900?param1=value1&param2=value2
      
    • query-string
      在 query string 裡面尋找 appsession

範例

# Load balancing PHP sessions:

appsession PHPSESSID len 64 timeout 3h request-learn prefix

# Load balancing ASP.Net sessions:

appsession ASP.NET_SessionId len 64 timeout 3h request-learn prefix

# Load balancing ASP sessions:

appsession ASPSESSIONID len 64 timeout 3h request-learn prefix

# Load balancing Java Server sessions:

appsession JSESSIONID len 52 timeout 3h request-learn prefix

比較完整的範例:

global
    maxconn 10000
    daemon

defaults
    log      global
    mode      http
    contimeout      5000
    clitimeout      50000
    srvtimeout      50000

listen webfarm 0.0.0.0:80
    mode http
    balance roundrobin
    option httpchk HEAD /index.html HTTP/1.0
    appsession JSESSIONID len 128 timeout 1m
    server serverA 192.168.1.10:80 check
    server serverB 192.168.1.20:80 check

結語

綜合兩個設定方式的說明,如果認定 browser 一定會支援 cookie,就可以利用 cookie 設定來處理 session id,但如果要同時支援 cookie 以及 url 形式的 session tracking ,就要使用 appsession。

網路上找到的實際範例,多數都是使用 cookie,而不是 appsession。目前除非使用者刻意 disable browser cookie 的機制,否則要遇到不支援 cookie 的 browser 也很困難了。

如果要用 haproxy 專用的 server id 機制,當然就選擇利用 cookie,設定自訂的 cookie name。但如果是要沿用標準的 ASPSESSIONID/PHPSESSID/JSESSIONID,就直接用 appsession 來設定就可以了。

References

富人用 L4 Switch,窮人用 Linux HAProxy!

Configuring haproxy to load balance multiple engine.io servers

Trick My Proxy: Front Apache Tomcat with HAProxy instead of Apache

Sticky Session Load Balancing with HAProxy

load balancing, affinity, persistence, sticky sessions: what you need to know

Haproxy 安裝手記,版本升級並追加 log 機制

HAProxy configuration

2015年3月10日

使用RequireJS進行模組化Web開發


什麼是RequireJS?

RequireJS是JavaScript檔的載入工具。 它能夠定義JavaScript檔案之間的相依性,讓瀏覽器以正確的順序載入JavaScript。 此外,它亦實作了AMD(Asynchronous Module Definition) API, 讓網頁開發者能將JavaScript程式碼進行良好的模組化設計。

為何需要RequireJS?

大型Web應用程式開發者時常會面臨到JavaScript程式碼的維護問題:
  1. 為了實作複雜的商業邏輯,JavaScript程式碼寫的又大又多。
  2. 使用了大量的第三方套件,套件之間還有相依性。
一旦商業邏輯有所異動,或是套件版本有更新, 都是令Web應用程式開發者相當頭疼的。
因此,Web應用程式的模組化設計,以及第三方套件的管理工具, 都是開發Web應用程式時需要審慎評估的。 而RequireJS正是一個不錯的選擇。

What is AMD?

AMD API定義了一個define方法, 旨在希望網頁開發者在撰寫一支JavaScript程式時, 能夠使用define方法來將其定義為一個「模組」, 一來避免大量的變數暴露在全域, 二來能使JavaScript的開發更為「模組化」。
一般習慣下,一個JavaScript檔案會對應到一個模組,
define方法有三個參數:
define(id, dependencies, factory)
參數說明如下:
id:模組名稱。一般習慣下,一個JavaScript檔案會對應到一個模組;此時通常會省略id。
dependencies:相依的模組名稱列表,為字串陣列型態。表示載入此模組載入前,需要先載入的模組。
factory:將此模組初始化或實例化的函式。此函式需要有回傳值,通常是代表此模組的物件,以讓其他模組使用該模組的方法。此外, 此函式的參數列, 將依序應到dependencies陣列中的模組。
以下以範例說明AMD API的使用, 假設有moduleA.js與moduleB.js兩個js檔,分別定義了兩個模組,內容如下:
moduleA.js
/* moduleA.js */
define([],           //dependencies陣列
    function() {    //factory函式
        var ModuleA = {
            testExec : function() {
                console.log("into ModuleA testExec");
            }
        };
        return ModuleA;
    }
);
moduleB.js
/* moduleB.js */
define(["moduleA","module1","module2","module3"], //dependencies陣列
    function(ModuleA,Module1,Module2,Module3) {   //factory函式
            var ModuleB = {
                testExec : function() {
                console.log("into ModuleB testExec");
                ModuleA.testExec();
            }
        };
        return ModuleB;
    }
);
moduleA不相依於任何模組,dependencies陣列為空;
moduleB相依於moduleA,module1,module2,module3, 注意其factory函式的參數,將依照順序對應到dependencies陣列中的模組。
此外,moduleB.js使用了moduleA.js中所定義的物件之方法, 其關係如下:

首先注意moduleB的factory函式中有一個參數,名為ModuleA, 其對應到dependencies參數中的模組名稱"moduleA"。 預設情況下,RequireJS將自動依當前相對路徑去尋找moduleA.js, 並將moduleA.js中的factory函式的回傳值載入。
同理,moduleB.js同樣地也可以使用module1.js,module2.js,module3.js中所定義的物件,此處就不再贅述。

如何使用在HTML檔中使用RequireJS載入JavaScript?

了解AMD API的使用方式後, 以下將說明如何使用RequireJS在HTML檔案中載入JavaScript程式。
RequireJS本身也是一個JavaScript檔案,可以在RequireJS官方網站下載。
在HTML中使用RequireJS的方式如下:
<script data-main="js/main" src="path_to_requirejs"></script>
src是require.js檔的路徑。 data-main則指向RequireJS需要用到的設定檔,透過此設定檔,可以依據載入JavaScript模組並執行。該設定檔也是一個js檔案,且.js可以省略。 data-main設定檔最簡單的範例如下:
main.js
require(['moduleB'], function(ModuleB){
    ModuleB.testExec();
});


使用require.config的path參數設定模組別名

data-main設定檔中,還可以透過require.configpath參數設定模組的別名。這個參數尤其適用於是第三方JavaScript套件,如:
main.js
require.config({
    paths : {
        'jquery' : 'lib/jquery-1.9.0'
    }
});

require(['testloadlibs','jquery'], function(TestLoadLibs,JQuery){
    TestLoadLibs.testExec();
});
testloadlibs.js
define(["jquery"],          
    function(jquery) {      
        var TestLoadLibs = {
            testExec : function() {
                console.log("into TestLoadLib testExec");
                $(function(){
                    $(document.body).append("Hello jQuery!");
                });
            }
        };
        return TestLoadLibs;
    }
);

如此一來,其他模組在需要使用jQuery的時候,不僅不需要打上詳細的lib/jquery-1.9.0相對路徑;更重要的是:當jQuery版本需要更動時,也只要修改main.js,而不需要修改其他模組

結語

RequireJS不僅僅是JavaScript檔的載入工具,更是協助Web應用程式開發模組化以及管理第三方套件的利器。本文僅以最簡單的範例介紹RequireJS
事實上,光是require.config就提供了多種參數,以因應Web開發所可能遇到的各種情況,像是載入不支援以非AMD API開發的第三方JavaScript套件。 因此,RequireJS無疑是開發Web應用程式必學的套件之一。

Reference

初探RequireJS - 網站製作學習誌
Javascript模块化编程(三):require.js的用法

2015年3月9日

HAProxy

Server提供網路服務時,面臨到一台 Server 的 capacity 瓶頸,這時候,就可以用 L4 Load Balancer 或是 HAProxy 來進行網路分流與 load balance。

HAProxy 目前主要支援兩種 traffic,http 以及一般的 tcp,http traffic 是最主要支援的部份,HAProxy 可深入到 HTTP Traffic 的封包內容,並根據設定的條件修改封包資料。

安裝

我們可以選擇直接用 yum 安裝,目前的版本為 haproxy-1.5.2-2.el6.i686

yum install haproxy

安裝完成後,執行檔會放在 /usr/sbin 目錄中。

也可以選擇直接從 source code 編譯。

tar -zxvf haproxy-1.5.11.tar.gz
cd haproxy-1.5.11

make clean

#  linux 核心為 2.6.x 可以用使用 TARGET=linux26 參數進行最佳化,如果真的不知道可以用 TARGET=generic 即可
make TARGET=linux26 USE_OPENSSL=1 ADDLIB=-lz
make install

安裝完成後,執行檔會裝在 /usr/local/sbin 目錄中。

自行編譯後,還需要製作 service 啟動檔,這也是從 yum 安裝的 haproxy 抄來的,改一下執行檔的路徑就可以用了。

vi /etc/init.d/haproxy

#!/bin/sh
#
# haproxy
#
# chkconfig:   - 85 15
# description:  HAProxy is a free, very fast and reliable solution \
#               offering high availability, load balancing, and \
#               proxying for TCP and  HTTP-based applications
# processname: haproxy
# config:      /etc/haproxy/haproxy.cfg
# pidfile:     /var/run/haproxy.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

exec="/usr/local/sbin/haproxy"
prog=$(basename $exec)

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

lockfile=/var/lock/subsys/haproxy

check() {
    $exec -c -V -f /etc/$prog/$prog.cfg
}

start() {
    $exec -c -q -f /etc/$prog/$prog.cfg
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi

    echo -n $"Starting $prog: "
    # start it up here, usually something like "daemon $exec"
    daemon $exec -D -f /etc/$prog/$prog.cfg -p /var/run/$prog.pid
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc $prog 
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    $exec -c -q -f /etc/$prog/$prog.cfg
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi
    stop
    start
}

reload() {
    $exec -c -q -f /etc/$prog/$prog.cfg
    if [ $? -ne 0 ]; then
        echo "Errors in configuration file, check with $prog check."
        return 1
    fi
    echo -n $"Reloading $prog: "
    $exec -D -f /etc/$prog/$prog.cfg -p /var/run/$prog.pid -sf $(cat /var/run/$prog.pid)
    retval=$?
    echo
    return $retval
}

force_reload() {
    restart
}

fdr_status() {
    status $prog
}

case "$1" in
    start|stop|restart|reload)
        $1
        ;;
    force-reload)
        force_reload
        ;;
    check)
        check
        ;;
    status)
        fdr_status
        ;;
    condrestart|try-restart)
      [ ! -f $lockfile ] || restart
    ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|try-restart|reload|force-reload}"
        exit 2
esac

設定

設定檔會放在 /etc/haproxy/haproxy.cfg,設定內容有兩大部份,global 以及 proxy,而 proxy 中,有四個主要項目:defaults, listen, frontend 以及 backend 的部份。

global

範例

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    nbproc        1

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

此區塊可使用的設定項目

  • chroot
  • daemon
    以 daemon 的方式運行
  • nbproc
    daemon mode 才能使用,設定 process 的數量
  • user/uid
  • group/gid
  • log
  • pidfile
  • stats

  • maxconn
    可接受最大的連線數量

  • noepoll
    不使用 linux 的 epoll
  • nokqueue
    不使用 BSD 的 kqueue polling
  • debug
    將所有訊息顯示到 console
  • quiet
    不顯示任何訊息

獨立的 haproxy logfile

我們必須調整一些 rsyslog 的設定,才能將 haproxy 的 log 放到獨立的 logfile 裡面。

vi /etc/rsyslog.conf

# 把這兩行的註解刪除
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# 限制 rsyslog UDP 只會用在 127.0.0.1
$UDPServerAddress 127.0.0.1

新增一個檔案 /etc/rsyslog.d/haproxy.conf

vi /etc/rsyslog.d/haproxy.conf

local2.*    /var/log/haproxy/haproxy.log

也可以用這個方式,將 log file 區分不同的 log level,要不然就放在同一個 log file 裡面就好了。

local2.=info     /var/log/haproxy-info.log
local2.notice    /var/log/haproxy-allbutinfo.log

重新啟動系統 log 記錄器

service rsyslog restart

編輯 haproxy.logrotate,讓 haproxy.log 檔案每天產生一個,然後保留 120 天的資料。

vi /etc/logrotate.d/haproxy.logrotate

/var/log/haproxy/haproxy.log {
    missingok
    notifempty
    sharedscripts
    rotate 120
    daily
    compress
    postrotate
        reload rsyslog >/dev/null 2>&1 || true
    endscript
}

proxy

proxy 設定是由 defaults, listen, frontend, backend 組成。

  • defaults name
    設定所有其他區塊的預設參數,如果設定檔中,後面又多了一塊 defaults 設定,後面的設定會覆蓋掉前面的設定。

  • frontend name
    描述接受 client 端 request 的 listening sockets。

  • backend name
    描述 proxy 會將 frontend 接收的 request 連線 forward 到後端的一組 servers。

  • listen name
    定義完整的 proxy,包含了 frontend 與 backend,這個部份的定義,通常用在設定一般的 TCP-only traffic。

proxy 定義的名稱 name ,必須要使用這些字元 upper and lower case letters, digits,
'-' (dash), '_' (underscore) , '.' (dot) and ':' (colon)。

HTTP traffic

HAProxy 針對 http traffic 提供了五種 mode

  • KAL: keep alive ("option http-keep-alive")
    這是預設值,所有處理中的 request, response 以及 connection 都會持續 idle 並保持連線。

  • TUN: tunnel ("option http-tunnel")
    只會處理第一個 request 與 response,其他封包都會直接 forward,不進行任何分析與處理,目前建議不使用這個模式,因為會對 logging 以及 HTTP processing 造成問題。

  • PCL: passive close ("option httpclose")
    就跟 tunnel mode 一樣,在處理完第一個封包後,會雙向加上 "conneciton: close",讓連線結束。

  • SCL: server close ("option http-server-close")
    在收到最後的 response 時,就會 close server-facing connection,但仍然持續保留 client-facing connection。

  • FCL: forced close ("option forceclose")
    在收到最後的 response 之後,就會關閉連線。

在一個 http connection 經過 frontend 與 backend 設定之後,可能會有兩段 proxy mode 的設定,最終這個 connection 的 mode 是由下表的規則決定,keep-alive 是最弱的設定值,而 force close 是最強的設定值。KAL < TUN < PCL < SCL < FCL

                          Backend mode

                | KAL | TUN | PCL | SCL | FCL
            ----+-----+-----+-----+-----+----
            KAL | KAL | TUN | PCL | SCL | FCL
            ----+-----+-----+-----+-----+----
            TUN | TUN | TUN | PCL | SCL | FCL
 Frontend   ----+-----+-----+-----+-----+----
   mode     PCL | PCL | PCL | PCL | FCL | FCL
            ----+-----+-----+-----+-----+----
            SCL | SCL | SCL | FCL | SCL | FCL
            ----+-----+-----+-----+-----+----
            FCL | FCL | FCL | FCL | FCL | FCL
defaults

這個區塊的參數,是設定檔後面所有參數的預設設定值,下面的設定值會蓋掉上面的。

範例

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

此區塊可使用的設定項目

  • balance
    選擇使用那一種 algorithm 來執行 load balance。
  • mode { tcp|http|health } (defaults 為 http)
  • log global
  • option httplog
    Enable logging of HTTP request, session state and timers
  • option http-server-close
    Enable or disable HTTP connection closing on the server side
  • option forwardfor except 127.0.0.0/8
    因為 X-Forwarded-For header 裡面會有 client 的 IP,HAProxy 會利用此 header,所以增加此設定,可讓 X-Forwarded-For header 都轉送到 後端的 server
  • option redispatch
    當 client 連到掛掉的機器時, 可重新再分配
  • retries 3
    失敗重試次數
  • timeout http-request 10s
    Set the maximum allowed time to wait for a complete HTTP request,等待 HTTP Request 完成的 timeout 時間
  • timeout queue 1m
    Set the maximum time to wait in the queue for a connection slot to be free,等待 queue 釋放空間的 timeout 時間
  • timeout connect 10s
    Set the maximum time to wait for a connection attempt to a server to succeed.
  • timeout client 1m
    Set the maximum inactivity time on the client side. 當有 long polling 時,這個參數在 frontend 要調長到 long polling 最大的等待時間
  • timeout server 1m
    Set the maximum inactivity time on the server side. 當有 long polling 時,這個參數在 backend 要調長到 long polling 最大的等待時間
  • timeout http-keep-alive 10s
    Set the maximum allowed time to wait for a new HTTP request to appear
  • timeout check 10s
    Set additional check timeout, but only after a connection has been already established.
  • maxconn 3000
    連線到某個 server 的最大連線數
backend balance mode

這是 balance 設定值可選填的 algorithm 項目。

  • roundrobin
    每個 server 依據權值 weight 依序選擇 servers,這是最快的 algorithm,server weight 會根據 instance slow start 的狀況而隨時變動。這個 algorithm 在每個 backend 最多可處理 4095 個 active server nodes。如果有個 server node 在 down 之後馬上又變成 active,可能會需要數百個 requests 之後,才會再 join 這個 server farm。

  • static-rr
    每個 server 根據 weight 依序選擇 server,類似 roundrobin,但權值 weight 是固定的。沒有 active server node 的處理數量上限。

  • leastconn
    目前處理最少連線數量的 server,作為下一個 connection 轉向的 server。建議在較長 tcp session 的服務中使用這個演算法,例如 LDAP, SQL, etc...,不適合用在類似 HTTP 這種短 sesion time 的 protocol。

  • first
    server nodes 之中,選擇第一個可使用的 server,當這個 server 連線處理數量達到 maxconn 時,就會選擇下一個 server,所以設定檔中一定要有 maxconn 設定值。

  • source
    source IP address 會 hashed 並除以 total weight of running serer,用這個結果來決定要選擇那一個 server,這可確保同一個 client IP 的 traffic 會連到同一個 server。如果 server nodes 數量改變了,就會因為重新計算 hash,造成 clients 連線到不同的 servers。

  • uri
    可用 uri 的 ? 前面的部份,或是整個 uri 進行 hash,可確保同一個 uri 會轉給同一個 server。這個設定通常用在 proxy caches 與 anti-virus proxyies,用以提高 cache hit rate。

    有兩個 optinal parameter: len 與 depth。len 就是使用 uri 裡面幾個字元,但因為 uri 通常是 / 開頭,所以不要將 len 設定為 1。

    depth 表示計算 hash 的 maxmimum directory depth,出現一個 / 代表多了一層 depth。

  • url_param
    使用 HTTP Get request URL 裡面的參數,如果用到了 "check_post",就會使用 POST request 裡面的參數。

  • hdr(name)
    會尋找名稱為 name 的 HTTP header 欄位。

    optonal 參數 "use_domain_only" 可用在指定 header 為 Host 的時候,如果 Host 為 "haproxy.1wt.eu" 就只會考慮 "1wt"

  • rdp-cookie, rdp-cookie(name)
    尋找設定的 cookie,通常就是 session ID,如果沒有 session ID 就會使用 roundrobin algorithm。

一些設定的參考範例

範例 1:雖然這個是 listen 區塊,但實際上是設定一個網頁 service,提供一個 HAProxy 網頁監控界面。

# HAProxy 網頁管理界面
listen stats *:2000
    mode http
    stats enable
    stats hide-version
    stats realm Haproxy\ Statistics
    stats uri /
    # 帳號密碼
    stats auth username:password
    stats refresh 10s

範例 2:

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
    timeout server  50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
     errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

frontend localnodes
    bind *:80
    mode http
    default_backend nodes

backend nodes
    mode http
    balance roundrobin
    option forwardfor
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }
    option httpchk HEAD / HTTP/1.1\r\nHost:localhost
    server web01 127.0.0.1:9000 check
    server web02 127.0.0.1:9001 check
    server web03 127.0.0.1:9002 check

範例 3:

defaults
    log    global
    mode    http
    option    httplog
    option    dontlognull
    retries    3
    option redispatch
    option httpclose
    maxconn    32768
    contimeout    5000
    clitimeout    50000
    srvtimeout    50000

listen www-balancer
    bind 0.0.0.0:80
    balance         roundrobin
    server          w1 192.168.1.10:80 weight 3 check
    server          w2 192.168.1.20:80 weight 3 check
    option          httpchk GET /robots.txt
    option          forwardfor

範例 4: DB1 與 DB2 設定為 Master-Master Replication

defaults
    mode tcp
    option redispatch   #連前當前配置失敗時,允許重新配發到他台機器
    option abortonclose
    timeout connect 5000ms
    timeout client 30000ms
    timeout server 30000ms
    log 127.0.0.1 local0
    balance roundrobin   #使用輪替演算法,分散主機流量

listen proxy
    bind *:3306  #綁定192.168.11.180的3306 Port為運行主機端口
    mode tcp
    server db1 192.168.1.10:3306  weight 1 check  

    #後端主機.178,179,權重值配置

    server db2 192.168.1.20:3306  weight 2 check  

    #check 參數檢查改主機是否Live

範例 5:

defaults
    timeout server 86400000
    timeout connect 86400000
    timeout client 86400000
    timeout queue   1000s

# [HTTP Site Configuration]
listen  http_web 192.168.10.10:80
    mode http
    balance roundrobin  # Load Balancing algorithm
    option httpchk
    option forwardfor
    server server1 192.168.1.10:80 weight 1 maxconn 512 check
    server server2 192.168.1.20:80 weight 1 maxconn 512 check

# [HTTPS Site Configuration]
listen  https_web 192.168.10.10:443
    mode tcp
    balance source# Load Balancing algorithm
    reqadd X-Forwarded-Proto:\ http
    server server1 192.168.1.10:443 weight 1 maxconn 512 check
    server server2 192.168.1.20:443 weight 1 maxconn 512 check

References

富人用 L4 Switch,窮人用 Linux HAProxy!

使用 HAProxy 完成 網站分流, 平衡負載

[FreeBSD & Linux]網站分流:簡易架設 HAProxy 伺服器

使用 Haproxy 搭建高可用與負載平衡叢集

2015年3月2日

redis HA sentinel

如果要建置 redis 的 HA 環境,有兩種選擇,第一種是基於 replication 的 sentinel,第二種則是還在 alpha 階段的 redis 3.0 提供的 cluster 功能。

redis cluster 目前還在 alpha 階段,他所提供最重要的功能,就是 auto sharding,

HA

考量到 HA 的議題,要思考兩點 (1) data availability (2) service availability,以目前 2.8 版的狀況,redis 支援 data replication,針對 service availabilty 也提供了sentinel做 redis daemon 的監控。

redis 與 sentinel 的關係可參考下圖,這兩個分別是獨立的 daemon,redis 服務的 port 為 tcp 6379,sentinel 是 tcp 26379。

當 master node 消失,sentinel 會自動將 slave node 改為 master,並繼續提供 redis 服務,如果 slave node 有多個,那麼 sentinel 只會自動將某一個 slave node 改為 master。

以下我們假設 master node ip 為 192.168.1.10,slave node 為 192.168.1.20

data replication

依照上圖,我們必須在 slave 的機器上,設定 replication,將資料由 master node 複製過來,這裡要注意的是,master node 不能填寫這個設定。

修改 192.168.1.20 機器上的 redis 設定檔

vi /etc/redis/6379.conf

slave of 192.168.1.10 6379

然後 restart redis

service redis restart

簡單的驗證方式如下,在 master node 寫入,在 slave node 讀取。

> redis-cli -h 192.168.1.10 -p 6379
192.168.1.10:6379> set hello world

> redis-cli -h 192.168.1.20 -p 6379
192.168.1.20:6379> get hello
"world"

Sentinel

根據 Sentinel 的文件,主要功能有四項

  1. Monitor
    sentinel 會持續檢查 master 與 slave redis server 的狀態
  2. Notification
    sentinel 會通知系統管理員或是透過 API 通知其他程式,監控的 redis server 發生故障的狀況。
  3. Automatic failover
    如果 master node 故障,sentinel 會自動找到一個 slave node 更改為 master,其他的 slave node 也會自動將 master 更改為新的 master node。
  4. Configuration provider
    sentinel 作為 client 端處理 service discovery 的功能,連接到 sentinel 的 clients 會詢問目前 redis 的 master node 的 ip,當 failover 發生時,會自動回報為新的 ip。

接下來要設定 sentinel,用來監控 redis server,設定檔內容如下

> vi /etc/redis/sentinel.conf
port 26379
dir /tmp

daemonize yes
pidfile /var/run/redis-sentinel.pid
loglevel verbose
logfile /var/log/redis-sentinel.log

# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor mymaster 192.168.1.10 6379 1
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

當 quorum 是 2,就表示需要有兩個 sentinels 回報 master node 失效時,才會進行 failover process。

vi /etc/init.d/redis-sentinel

#!/bin/sh
#
# sentinel - this script starts and stops the sentinel daemon
#
# chkconfig:   - 86 14
# description:  Redis Sentinel is monitor and aut-failover for redis.
# processname: redis-sentinel
# config:      /etc/redis/sentinel.conf
# config:      /etc/sysconfig/redis-sentinel
# pidfile:     /var/run/redis-sentinel.pid

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
[ "$NETWORKING" = "no" ] && exit 0

redis="/usr/local/bin/redis-sentinel"
prog=$(basename $redis)

REDIS_CONF_FILE="/etc/redis/sentinel.conf"

[ -f /etc/sysconfig/redis-sentinel ] && . /etc/sysconfig/redis-sentinel

lockfile=/var/lock/subsys/redis-sentinel

start() {
    [ -x $redis ] || exit 5
    [ -f $REDIS_CONF_FILE ] || exit 6
    echo -n $"Starting $prog: "
    daemon $redis $REDIS_CONF_FILE
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc $prog -TERM
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    sleep 1
    start
}

rh_status() {
    status $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    status)
        rh_status
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart}"
        exit 2
esac
chkconfig redis-sentinel on
service redis-sentinel start

當我們把 master node 的 redis service 停掉,就會在 sentinel 的 log 中看到 fail-over 的過程。

[2880] 03 Feb 15:28:37.861 * +slave slave 192.168.1.20:6379 192.168.1.20 6379 @ mymaster 192.168.1.10 6379

[2880] 03 Feb 15:39:24.062 # +sdown master mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:24.063 # +odown master mymaster 192.168.1.10 6379 #quorum 1/1
[2880] 03 Feb 15:39:24.063 # +new-epoch 1
[2880] 03 Feb 15:39:24.063 # +try-failover master mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:24.113 # +vote-for-leader bf0e42815cc599c9dc2b931b08342f3575767a23 1
[2880] 03 Feb 15:39:24.113 # +elected-leader master mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:24.113 # +failover-state-select-slave master mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:24.181 # +selected-slave slave 192.168.1.20:6379 192.168.1.20 6379 @ mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:24.181 * +failover-state-send-slaveof-noone slave 192.168.1.20:6379 192.168.1.20 6379 @ mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:24.284 * +failover-state-wait-promotion slave 192.168.1.20:6379 192.168.1.20 6379 @ mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:25.158 - -role-change slave 192.168.1.20:6379 192.168.1.20 6379 @ mymaster 192.168.1.10 6379 new reported role is master
[2880] 03 Feb 15:39:25.282 # +promoted-slave slave 192.168.1.20:6379 192.168.1.20 6379 @ mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:25.282 # +failover-state-reconf-slaves master mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:25.284 # +failover-end master mymaster 192.168.1.10 6379
[2880] 03 Feb 15:39:25.285 # +switch-master mymaster 192.168.1.10 6379 192.168.1.20 6379
[2880] 03 Feb 15:39:25.286 * +slave slave 192.168.1.10:6379 192.168.1.10 6379 @ mymaster 192.168.1.20 6379
[2880] 03 Feb 15:39:55.364 # +sdown slave 192.168.1.10:6379 192.168.1.10 6379 @ mymaster 192.168.1.20 6379

sentinel client

使用 sentinel ,需要搭配 client 的實做,讓 client 能夠自動尋找 master node 並 fail-over 到 backup node。

如果是使用 java,通常是用 jedis library,JedisSentinelTest 提供利用 jedis 連結 sentinel 的範例。

另外 jedis-sentinel-pool 則是提供了 jedis connection pool 的實做。

docker for redis cluster

我們也可以搭配 docker 建置 redis cluster 環境,這篇文章:用Docker構建分佈式Redis集群 提供了利用 docker 建置 redis cluster 環境的過程範例。