2017年7月17日

使用 Tsung 測試 websocket

tsung是erlang開發的多協議分佈式負載測試工具,它能用來壓力測試HTTP, WebDAV, SOAP, PostgreSQL, MySQL, LDAP, webscoket 和 Jabber/XMPP 的 server。

安裝 Tsung

在 mac 安裝 tsung 可使用 macport

sudo port install tsung

安裝成功後,以 -v 測試

$ tsung -v
Tsung version 1.6.0

在這個路徑下面,有一些 perl script,接下來可以利用這些 script 產生報表

$ $ ls -m /opt/local/lib/tsung/bin/
log2tsung.pl, tsung-rrd.pl, tsung_percentile.pl, tsung_stats.pl

範例的路徑

/opt/local/share/doc/tsung/examples

我們可以將 websocket.xml 範例複製出來修改。

cp /opt/local/share/doc/tsung/examples/websocket.xml .

撰寫 test scenario

修改從範例複製的 websocket.xml

<?xml version="1.0"?>
<!DOCTYPE tsung SYSTEM "/opt/local/share/tsung/tsung-1.0.dtd" []>
<tsung loglevel="notice" version="1.0">
  <clients>
    <client host="localhost" use_controller_vm="true" maxusers="1000" />
  </clients>

  <servers>
    <server host="127.0.0.1" port="9000" type="tcp" />
  </servers>

  <load>
    <!-- phase 1: 0.1 usr per second in 10 minutes, max: 1000 -->
    <arrivalphase phase="1" duration="10" unit="minute">
      <users maxnumber="1000" arrivalrate="0.1" unit="second" />
    </arrivalphase>

    <!-- phase 2: 1 new user every second in 10 minutes -->
    <!--
    <arrivalphase phase="2" duration="10" unit="minute">
      <users interarrival="1" unit="second"></users>
    </arrivalphase>
    -->

    <!-- phase 3: 1 new usr every 0.1 second in 10 minutes -->
    <!--
    <arrivalphase phase="3" duration="10" unit="minute">
      <users interarrival="0.1" unit="second"></users>
    </arrivalphase>
    -->

    <!-- phase 4: 10 usrs per second in 10 minutes, the same as phase 3, max: 100 -->
    <!--
    <arrivalphase phase="4" duration="10" unit="minute">
      <users maxnumber="100" arrivalrate="10" unit="second"></users>
    </arrivalphase>
    -->
  </load>

  <options>
    <option name="file_server" id='userdb' value="usr.csv"/>
  </options>

  <sessions>
    <session name="websocket" probability="100" type="ts_websocket">
        <setdynvars sourcetype="file" fileid="userdb" delimiter=";" order="iter">
          <var name="usrid"/>
          <var name="pwd"/>
        </setdynvars>

        <request subst="true">
             <websocket type="connect" path="/msgsrv/ws"></websocket>
        </request>

        <thinktime min="2" max="5" random="true"></thinktime>

        <request subst="true">

            <websocket type="message">
{
  "task":1,
  "action":1,
  "serial":"01-01-%%_usrid%%",
  "rdata":{
    "userid":"%%_usrid%%",
    "userpwd":"%%_pwd%%"
  }
}
            </websocket>
        </request>

        <thinktime min="3" max="10" random="true"></thinktime>

        <request>
            <websocket type="message" >
{
  "task":3,
  "action":2,
  "serial":"03-02-%%_usrid%%",
  "rdata":{
    "areaseq":1
  }
}
            </websocket>
        </request>

        <thinktime value="30"></thinktime>

        <request>
            <websocket type="close"></websocket>
        </request>
    </session>
  </sessions>
</tsung>

以下說明每個部分的設定:

load 的部分是新連線產生的速度,下面有四個 phases,分別有不同的連線產生的速度

<load>
    <!-- phase 1: 0.1 usr per second in 10 minutes, max: 1000 -->
    <arrivalphase phase="1" duration="10" unit="minute">
      <users maxnumber="1000" arrivalrate="0.1" unit="second" />
    </arrivalphase>

    <!-- phase 2: 1 new user every second in 10 minutes -->
    <arrivalphase phase="2" duration="10" unit="minute">
      <users interarrival="1" unit="second"></users>
    </arrivalphase>

    <!-- phase 3: 1 new usr every 0.1 second in 10 minutes -->
    <arrivalphase phase="3" duration="10" unit="minute">
      <users interarrival="0.1" unit="second"></users>
    </arrivalphase>

    <!-- phase 4: 10 usrs per second in 10 minutes, the same as phase 3, max: 100 -->
    <arrivalphase phase="4" duration="10" unit="minute">
      <users maxnumber="100" arrivalrate="10" unit="second"></users>
    </arrivalphase>
  </load>

option 是定義一個外部 csv 檔案的 id,給後面參考使用

  <options>
    <option name="file_server" id='userdb' value="usr.csv"/>
  </options>

session 的一開始,先取得 userdb 對應的 csv 檔案,並取得兩欄資料,對應到 usrid 及 pwd 兩個變數。後面在 request 的地方,可以用 %%_usrid%% 參考到 csv 裡面的變數。

<session name="websocket" probability="100" type="ts_websocket">
        <setdynvars sourcetype="file" fileid="userdb" delimiter=";" order="iter">
          <var name="usrid"/>
          <var name="pwd"/>
        </setdynvars>

        <request subst="true">
             <websocket type="connect" path="/msgsrv/ws"></websocket>
        </request>

        <thinktime min="2" max="5" random="true"></thinktime>

        <request subst="true">

            <websocket type="message">
{
  "task":1,
  "action":1,
  "serial":"01-01-%%_usrid%%",
  "rdata":{
    "userid":"%%_usrid%%",
    "userpwd":"%%_pwd%%"
  }
}
            </websocket>
        </request>

        <thinktime min="3" max="10" random="true"></thinktime>
</session>

usr.csv 裡面就放兩欄,分別是 usrid 及 pwd

u0001;u0001pwd
u0002;u0002pwd
u0003;u0003pwd

進行 tsung 測試

啟動 tsung

tsung -f websocket.xml -l log start

產生的報告會放在 log 目錄下面,一個日期 timestamp的目錄中

tail -f log/20170324-1531/tsung.log

可以用 tsung_stats.pl 產生 html 的 report

mkdir report

cd report

/opt/local/lib/tsung/bin/tsung_stats.pl --stats ../log/20170324-1531/tsung.log chromium graph.html

最後可以看到一些統計報表

References

Install tsung centos 7

installing tsung in centos

CentOS下安裝 Tsung-壓力測試工具

CentOS壓力測試工具Tsung安裝和圖形報表生成

詳解CentOS下Tsung環境的搭建到跑通第一個測試用例

Load Testing using Tsung

tsung的使用筆記

Tsung’s documentation

tsung測試openfire時從CSV文件讀取user信息

2017年7月3日

使用 vim Plugins 改造 vim 為開發的 IDE

在使用 linux 一定知道要用 vim,vim 提供了很多 plugins 讓我們可以調整 vim,而一個大型的 programming IDE,核心也是從文字編輯器開始,延伸其他的功能,合併成一個完整的 IDE。

這麼多 plugins,如果要瞭解內容跟細節,還是一個一個慢慢安裝,閱讀文件才會比較清楚該 plugin 能做什麼事情,不過也要花時間慢慢去調整出適合自己的工作環境。

利用 vundle 快速設定 vim

ref: Configuring Vim as an IDE

Vundle是vim plugin的管理工具,利用 vundle 可以快速將很多 plugins 一次安裝起來。

首先將以下文件內容寫入 ~/.vimrc

syntax on

set nocompatible
set smartindent
set shiftwidth=4
set backspace=indent,eol,start
set ruler
set number
set showcmd
set incsearch
set hlsearch
set hls
set ic
set pastetoggle=<F12>
set enc=utf8

set mouse=a

filetype off 

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim



"-------------- PLUGINS STARTS -----------------
call vundle#begin()

Plugin 'VundleVim/Vundle.vim'
Plugin 'vim-airline/vim-airline'
Plugin 'vim-airline/vim-airline-themes'
Plugin 'altercation/vim-colors-solarized'
Plugin 'scrooloose/nerdtree'
Plugin 'jistr/vim-nerdtree-tabs'
Plugin 'scrooloose/syntastic'
Plugin 'xolox/vim-misc'
Plugin 'xolox/vim-easytags'
Plugin 'majutsushi/tagbar'
Plugin 'ctrlpvim/ctrlp.vim'
Plugin 'vim-scripts/a.vim'
Plugin 'airblade/vim-gitgutter'
Plugin 'tpope/vim-fugitive'
Plugin 'Raimondi/delimitMate'
Plugin 'christoomey/vim-tmux-navigator'
Plugin 'jez/vim-c0'
Plugin 'jez/vim-ispc'
Plugin 'kchmck/vim-coffee-script'
Plugin 'flazz/vim-colorschemes'

call vundle#end()  
"-------------- PLUGINS END --------------------
filetype plugin indent on



"----- GENERAL SETTINGS-------
set laststatus=2
let g:airline_powerline_fonts = 1
let g:airline_detect_paste=1
let g:airline#extensions#tabline#enabled = 1
let g:airline_theme='solarized'
set background=dark
let g:solarized_termcolors=256
colorscheme solarized


"---------NERD-TREE SETTINGS----------
nmap <silent> <leader>t :NERDTreeTabsToggle<CR>
let g:nerdtree_tabs_open_on_console_startup = 1


"-------- SYNTASTIC SETTINGS---------
let g:syntastic_error_symbol = '✘'
let g:syntastic_warning_symbol = "▲"

augroup mySyntastic
    au!
    au FileType tex let b:syntastic_mode = "passive"
augroup END


"-------- TAGS SETTINGS --------------------------------
let g:easytags_events = ['BufReadPost', 'BufWritePost']
let g:easytags_async = 1
let g:easytags_dynamic_files = 2
let g:easytags_resolve_links = 1
let g:easytags_suppress_ctags_warning = 1
let g:tagbar_autoclose=2

nmap <silent> <leader>b :TagbarToggle<CR>
"autocmd BufEnter * nested :call tagbar#autoopen(0)

"---------GIT SETTINGS--------------
hi clear SignColumn
let g:airline#extensions#hunks#non_zero_only = 1


"----------DELIMITEMATE SETTINGS-----------------
let delimitMate_expand_cr = 1
augroup mydelimitMate
    au!
    au FileType markdown let b:delimitMate_nesting_quotes = ["`"]
    au FileType tex let b:delimitMate_quotes = ""
    au FileType tex let b:delimitMate_matchpairs = "(:),[:],{:},`:'"
    au FileType python let b:delimitMate_nesting_quotes = ['"', "'"]
augroup END

"-----------TMUX SETTINGS--------------
let g:tmux_navigator_save_on_switch = 2

以 git 安裝 vundle

git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

在 CentOS 要安裝 ctags

yum install ctags

如果是 Debian 則是

sudo apt-get install exuberant-ctags

安裝字型 Menlo-for-Powerline

git clone https://github.com/abertsch/Menlo-for-Powerline.git

mkdir ~/.fonts
cd Menlo-for-Powerline/
cp "Menlo for Powerline.ttf" ~/.fonts/
fc-cache -vf ~/.fonts

安裝 color solarized

cd ~/.vim/bundle
git clone git://github.com/altercation/vim-colors-solarized.git

最後在 console 執行,花一點時間,就可以安裝 .vimrc 指定的所有 plugins

vim +PluginInstall +qall

透過以上方式,就安裝了

  1. Vundle
  2. vim-airline
  3. vim-airline-themes
  4. vim-colors-solarized
  5. nerdtree
  6. vim-nerdtree-tabs
  7. syntastic
  8. vim-misc
  9. vim-easytags
  10. ctrlp.vim
  11. a.vim
  12. vim-gitgutter
  13. vim-fugitive
  14. delimitMate
  15. vim-tmux-navigator
  16. vim-colorschemes

NERDTree

ref: 上古神器vim插件:你真的學會用NERDTree了嗎?

NERDTree 是安裝後進入 vim,馬上就會看到的介面,他是一個檔案管理員的功能。

使用 NERDTree 搭配 nerdtree-tabs,感覺就比較接近一般的 IDE。

NERDTree 的指令有這些,但其實只要用滑鼠,點擊目錄跟檔案,也可以打開檔案

?: 快速幫助文檔
o: 打開一個目錄或者打開文件,創建的是buffer,也可以用來打開書籤
go: 打開一個文件,但是光標仍然留在NERDTree,創建的是buffer
t: 打開一個文件,創建的是Tab,對書籤同樣生效
T: 打開一個文件,但是光標仍然留在NERDTree,創建的是Tab,對書籤同樣生效
i: 水平分割創建文件的窗口,創建的是buffer
gi: 水平分割創建文件的窗口,但是光標仍然留在NERDTree
s: 垂直分割創建文件的窗口,創建的是buffer
gs: 和gi,go類似
x: 收起當前打開的目錄
X: 收起所有打開的目錄
e: 以文件管理的方式打開選中的目錄
D: 刪除書籤
P: 大寫,跳轉到當前根路徑
p: 小寫,跳轉到光標所在的上一級路徑
K: 跳轉到第一個子路徑
J: 跳轉到最後一個子路徑
<C-j>和<C-k>: 在同級目錄和文件間移動,忽略子目錄和子文件
C: 將根路徑設置為光標所在的目錄
u: 設置上級目錄為根路徑
U: 設置上級目錄為跟路徑,但是維持原來目錄打開的狀態
r: 刷新光標所在的目錄
R: 刷新當前根路徑
I: 顯示或者不顯示隱藏文件
f: 打開和關閉文件過濾器
q: 關閉NERDTree
A: 全屏顯示NERDTree,或者關閉全屏

Java, Scala, Python...

以 java 開發為例,最基本就是要在編輯 .java 檔案時,填寫 System. 的時候,就要自動出現該 package 可以填寫的 package or class。

在 .vimrc plugins 區塊,call vundle#end() 的前面加上

" java import
Plugin 'javaimp.vim'
" java auto complete
Plugin 'javacomplete'

.vimrc 最後面加上 javacomplete 的設定

" ========== omnifunc:javacomplete 自動補全功能 =========
" 設定此行在 java 檔案中,就可按(ctrl + x) + (ctrl + o) 自動補全
setlocal omnifunc=javacomplete#Complete
" 當檔案為副檔名為 java 動作
" mode的狀態下,按"."會替換成以下指令,換言之,與ide相同當按"."會自動補全
autocmd Filetype java,jsp set omnifunc=javacomplete#Complete
autocmd Filetype java,jsp set completefunc=javacomplete#CompleteParamsInf
autocmd Filetype java,jsp inoremap <buffer> . .<C-X><C-O><C-P><DOWN>
" 設定額外 include 的 classpath
" let b:classpath="/opt/apache-tomcat-8.0.30/lib/*"

" ========== omnifunc:javacomplete2 自動補全功能 =========
autocmd FileType java setlocal omnifunc=javacomplete#Complete
let g:JavaComplete_MavenRepositoryDisable = 1
let g:JavaComplete_UseFQN = 1
let g:JavaComplete_ClosingBrace = 1
let g:JavaComplete_JavaviDebug = 1
let g:JavaComplete_ImportDefault = 0

再安裝一次

vim +PluginInstall +qall

編輯 .java 就可以出現這樣的功能

References

Scala development in Vim

Coding Scala with Vim

vim plugin 推薦 (For python and java )

用 Vim 寫 JAVA - 環境建立 與 Eclim

Coding Java with Vim, 打造自己的工作環境

vim 使用 javacomplete2 自動補齊功能,只有 root 權限能完全工作問題

vim plugin 推薦 (For python and java )

2017年6月28日

解決 homebrew 修正成不用 root 身份執行後,mysql 無法啟動的問題

最近手邊要管的機器太多了,想試試用 Ansible 來處理,查了一下如何安裝,網路上是推薦用 homebrew 來裝最簡單,但是在使用很久以前安裝的 homebrew 時,出現了以下錯誤訊息:

$ sudo brew update
Error: Running Homebrew as root is extremely dangerous and no longer supported.
As Homebrew does not drop privileges on installation you would be giving all
build scripts full access to your system.

上網查了一下相關討論,大意就是 homebrew 不要讓你用 root 執行了,網路上找到的解決辦法就是,更改 /usr/local 的權限,如下:

sudo chown -R $(whoami) /usr/local

這樣一來,homebrew 就能正常運作了,執行以下指令就不會出錯,再也不需要加上 sudo 指令了:

brew update

但是問題來了,如果原本透過 .pkg 檔案來安裝 MySQL 的話,這時 MySQL 就會無法使用了!

$ mysql -uroot -p
Enter password: 
mysql> show databases;
ERROR 1018 (HY000): Can't read dir of '.' (errno: 13)

問題確認:

先查看一下 /usr/local 底下的目錄:

$ ls -al /usr/local/
total 80
drwxr-xr-x   29 mayer  wheel   986  6 28 09:55 .
drwxr-xr-x@  13 root   wheel   442  2 24 15:07 ..
drwxr-xr-x   16 mayer  admin   544  6 28 10:19 .git
......
lrwxr-xr-x    1 mayer  wheel    27  1 28  2014 mysql -> mysql-5.1.72-osx10.6-x86_64
drwxr-xr-x   16 mayer  wheel   544 12 17  2014 mysql-5.1.72-osx10.6-x86_64
drwxr-xr-x   10 mayer  admin   340 12  8  2015 opt
......

可以看到,/usr/local/ 底下有 MySQL 的目錄,由於剛剛我們改了 /usr/local 目錄底下所有目錄 owner 的關係,很可能是因為這樣出了問題。

先進入 Mac 的系統偏好設定 -> MySQL,看到正常運作中:

然後點擊 Stop MySQL Server 按鈕,會看到 MySQL 服務停止了,並且出現警告訊息:

/usr/local/mysql/data 目錄的 owner 不是 mysql 或 _mysql,可能會出問題。

問題解決:

先查看機器上,系統上有什麼樣的 mysql 使用者:

grep mysql /etc/passwd
_mysql:*:74:74:MySQL Server:/var/empty:/usr/bin/false

這邊發現到,只有一個 _mysql 這個使用者,很顯然的是在安裝 mysql 套件時一併建立的,因此我們將 /usr/local/mysql 相關的目錄更改目錄的 owner:

sudo chown -R _mysql /usr/local/mysql*

之後,在點 Start MySQL Server 按鈕,就能看到 MySQL 正常啟動了。

最後,透過 mysql command line 確認是否能正常讀取 database 了:

$ mysql -uroot -p   
mysql> show databases;
+---------------------+
| Database            |
+---------------------+
| information_schema  |
| ..................  |
| ..................  |
| test                |
+---------------------+
27 rows in set (0.01 sec)

一切又恢復正常了!