distri.lua的web運維工具

個人新手遊項目很快就要進入到尋找發行商的環節,最近幾天相對較空閒,逐將工做重心轉移到服務器組運維工具的製做上.
回想一年以前經歷的那個不算成功的端遊項目,由於運維工具設計得不合理,使用十分不方便,遊戲上線以後搞得我焦頭爛額的.javascript

以前一直沒碰過web相關的技術,最近幾天猛看了下php和javascript相關的東西,逐決定用web的方式實現一套遊戲服務器的運維和gm管理工具.
這個系統的目標:php

  • 按邏輯和物理機器的方式管理服務(包括監控,啓動,關閉等)
  • 當機器或服務出現異常的時候自動向預先設定的郵件地址發送郵件
  • 控制目標機器執行版本升級任務
  • 提供gm管理工具以方便運維人員查看遊戲的運行情況,發送遊戲公告等.

下面是這套系統雛形的兩個截圖:html

Alt text

Alt text

這兩張截圖展現的是服務器的管理界面.左邊是一個有兩個標籤的樹形控件.第一個標籤是物理視圖,第二個是邏輯視圖.右邊是監控界面和3個控制按扭.
監控界面按用戶在左邊選擇的節點來展現監控信息.例如若是用戶選擇的是物理視圖中的一個根節點,如192.168.0.87.則右邊的界面上就會顯示目標機器的狀態以及運行在目標機器上進程的狀態.而控制按扭則分別用於啓動/關閉/強殺一個或一組服務.java

下面簡單的介紹下系統的實現.git

首先全部的監控數據,管理系統的用戶及權限數據,服務器配置數據都被保存到一臺中央ssdb服務上.github

每臺物理機器運行一個daemon服務,每隔一秒收集機器狀態信息和上面運行的服務信息並將信息發送到中心ssdb服務上.同時daemon上啓動一個簡單的http服務,用於處理髮送到這臺機器上的操做請求.web

下面是daemon的代碼:redis

local Sche = require "lua.sche"
local Redis = require "lua.redis"
local Cjson = require "cjson"

local deployment={
    {groupname="central",service={
                {type="ssdb-server",logicname="ssdb-server",conf="ssdb.conf",ip="192.168.0.87"},
        }
    },
    {groupname="group1",service={
            {type="groupserver",logicname="groupserver",ip="192.168.0.87",port="8010"},
            {type="gameserver",logicname="gameserver",ip="192.168.0.87",port="8011"},
            {type="gateserver",logicname="gateserver",ip="192.168.0.87",port="8012"},
        }
    },  
    {groupname="group2",service={
            {type="groupserver",logicname="groupserver",ip="192.168.0.88",port="8010"},
            {type="gameserver",logicname="gameserver",ip="192.168.0.88",port="8011"},
            {type="gateserver",logicname="gateserver",ip="192.168.0.88",port="8012"},
        }
    },
}

local function split(s,separator)
    local ret = {}
    local initidx = 1
    local spidx
    while true do
        spidx = string.find(s,separator,initidx)
        if not spidx then
            break
        end
        table.insert(ret,string. sub(s,initidx,spidx-1))
        initidx = spidx + 1
    end
    if initidx ~= string.len(s) then
        table.insert(ret,string. sub(s,initidx))
    end
    return ret
end

local err,toredis = Redis.Connect("127.0.0.1",6379,function () print("disconnected") end)
if not err then
    toredis:Command("set deployment " .. Cjson.encode(deployment))
    AddTopFilter("distrilua")
    AddTopFilter("ssdb-server")
    while true do
        local machine_status = Top()
        print(machine_status)
        local tb = split(machine_status,"\n")
        local machine = {}
        local i = 1
        while i <= #tb do
            if tb[i] ~= "process_info" then
                table.insert(machine,tb[i])
            else
                i = i + 1   
                break
            end
            i = i + 1
        end
        local process = {}
        while i <= #tb do
            if tb[i] ~= "" then
                local tmp = {}
                local cols = split(tb[i],",")
                for k,v in pairs(cols) do
                    local keyvals = split(v,":")
                    tmp[keyvals[1]] = keyvals[2];
                end
                table.insert(process,tmp)
            end
            i = i + 1   
        end


        local str = string.format("hmset MachineStatus 192.168.0.87 %s",CBase64.encode(Cjson.encode({machine,process})))
        toredis:Command(str)
        --toredis:Command("set machine " .. CBase64.encode(Cjson.encode(machine)))
        --toredis:Command("set process " .. CBase64.encode(Cjson.encode(process)))          
        Sche.Sleep(1000)
    end
else
    Exit()
end

daemon服務運行在distri.lua環境之上,因此是用lua編寫的.json

這段代碼首先定義了一個叫作deployment的lua表,這個表就是服務器組的邏輯和物理配置信息.這個配置表將會被轉換成json字符串並保存到ssdb的deployment字段中.以後嘗試鏈接ssdb服務,若是鏈接成功則添加兩個信息收集的過濾器ssdb-serverdistrilua添加了這兩個過濾器以後每輪循環調用Top函數收集信息的時候就只會收集進程名爲ssdb-serverdistrilua的進程的信息.收集到數據以後通過一些處理而後轉換成json字符串接着保存到ssdb的MachineStatus相關對象的ip下面.服務器

http相關的處理在這裏還沒有實現因此暫時不介紹.

接下來是manage.php,這個是用戶控制界面的文件.這個文件使用了名爲webix的js ui庫.

function fetchdata(){
            createXMLHttpRequest();
            var url="info.php";
            xmlHttp.open("GET",url,true);
            xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");        
            xmlHttp.onreadystatechange = callback;
            xmlHttp.send(null);
        }
        
        function callback(){
            if(xmlHttp.readyState == 4){
                if(xmlHttp.status == 200){
                    var info = JSON.parse(xmlHttp.responseText);
                    var deploydata = info.deployment;
                    var machinedata = info.machine_status;                                                              
                    if(firstrun){
                        webix.message("first");
                        buildDeployPhyTree(deploydata);
                        buildPhyTree(machinedata);
                        buildPhyView(); 
                        buildDeployLogTree(deploydata);
                        buildLogicalTree();
                        buildLogView();
                    }else{
                        buildPhyTree(machinedata);
                        buildLogicalTree();
                        updatePhyView();
                        updateLogView();
                    }
                    ShowStatus();               
                    firstrun = false;
                    setTimeout("fetchdata()",1000);
                }
            }
        }

這個文件的關鍵部分是這兩個函數,fetchdata用於向服務器請求數據.這個請求被髮往info.php頁面.數據受到以後在callback中將數據轉換成json對象而後根據數據構建視圖.最後設置一個1秒鐘的超時,超時以後繼續向服務器請求數據.

接下來咱們看下info.php:

<?php
header("cache-control:no-cache,must-revalidate");
header("Content-Type:text/html;charset=utf8");

function split_line($input,$separator){
    $ret = array();
    $line = strtok($input,$separator);
    while($line != ""){
        array_push($ret,$line);
        $line = strtok($separator);
    }
    return $ret;
}
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$deployment = $redis->get('deployment');
$machine_status = $redis->hGetAll('MachineStatus');
$outputstr = "{\"deployment\":$deployment,\"machine_status\":[";
$first = true;
while(list($ip,$info) = each($machine_status)){
    if($first){
        $first = false;
    }else{
        $outputstr = $outputstr + ",";
    }
    $outputstr = $outputstr . "{\"ip\":\"$ip\",\"status\":" . base64_decode($info) . "}";
}
$outputstr = $outputstr . "]}";
echo $outputstr;
?>

處理至關簡單,受到請求後向ssdb請求數據,而後將數據組合成一個json字符串返回給客戶端.

感興趣的朋友能夠關注https://github.com/sniperHW/distri.lua,在examples目錄下找到相關的文件.

相關文章
相關標籤/搜索