C++ FFLIB之ffcount:通用資料分析系統

來源:互聯網
上載者:User

摘要:

資料分析已經變得不可或缺,幾乎每個公司都依賴資料分析進行決策。在我從事的網遊領域,資料分析是策劃新功能、最佳化遊戲體驗最重要的手段之一。網遊領域的資料分析有如下特點(開發角度):

  • 資料量大;網遊使用者量大,使用者行為多,儲存資料量較大。
  • 即時性要求高;比如新上的遊戲功能,玩家體驗和反饋希望儘快的被分析出來。
  • 需求變化快。網遊的需求變化日新月異,故要求資料分析系統能夠快速的響應需求變化。

常見的資料分析系統

資料分析系統應該分為資料存放區和資料分析,常見的資料分析架構有:

  • 直接在邏輯服務中定製資料分析;這種情況往往使用mysql或這mongodb作為資料存放區,優點是定製化的資料存放區更加節省空間的,缺點是mysql和mongodb的資料存放區伺服器往往成本更高,並且若增加新需求,定製化需要的開發量極大,並且維護老的資料分析代碼往往十分困難,因為是高度定製化的,往往會綁定在特殊的應用背景下。
  • 使用scribe做資料存放區,使用hadoop分析資料。Facabook scribe server 可以利用hadoopDistributed File System來儲存大資料,電子商務或者sns網站往往使用這種可擴充的成熟的方案,缺點是部署和維護成本較高,中小型團隊要建立hadoop叢集無論從人力還是物力都相對困難。

確定需求:

  • 資料存放區盡量簡單和低成本,由於日誌資料的讀取效率要求並不高,所以使用普通機器一般磁碟儲存即可,而不需要另外使用mysql及其他nosql等。
  • 資料分析盡量簡單易開發,目前來講,sql查詢是最方便最基礎的方式,所以資料應該是sql結構化的。
  • hadoop的部署對於中小團隊仍然是望而生畏的,故要求資料分析系統部署要簡單,配置容易。

ffcount 的架構

 

內部工作機制

時序圖說明內部工作機制:

 

樣本C++用戶端代碼:

 

#include "count/ffcount.h"#include "rpc/broker_application.h"#include "base/daemon_tool.h"#include "base/arg_helper.h"using namespace ff;#include <stdio.h>#define NUM 0int main(int argc, char* argv[]){    arg_helper_t arg_helper(argc, argv);    if (false == arg_helper.is_enable_option("-l"))    {        printf("usage: app -l tcp://127.0.0.1:10241\n");        return 1;    }        assert(0 == singleton_t<msg_bus_t>::instance().open(arg_helper.get_option_value("-l")) && "can't connnect to broker");        assert(singleton_t<msg_bus_t>::instance().get_service_group("event_log_service") && "event_log_service group not exist");    assert(singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0) && "event_log_service 0 not exist");        event_log_t el("test"/*dbname*/,"dumy"/*tablename*/, "A,B,C"/*fields name*/);el.def(100, "p\"T'p", 5.4);    singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el);    for (int i = 0; i < NUM; ++i)    {        char buff[64];        snprintf(buff, sizeof(buff), "dumy_%d", i%8);        event_log_t el(buff, "A,B,C");el.def(100, "pp", 5.4);        singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el);    }        event_queryt_t::in_t in_msg;    in_msg.db_name = "test";    in_msg.sql = "select * from dumy";        struct lambda_t    {        static void callback(event_queryt_t::out_t& msg_)        {            printf("=====>>>>> callback dump data [%s]<<<<<<=======\n", msg_.err_msg.c_str());            ffdb_t::dump(msg_.ret_data, msg_.col_names);                        event_log_t el("test", "dumy", "A,B,C");el.def(100, "p\"T'p", 5.4);            singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el);            for (int i = 0; i < NUM; ++i)            {                char buff[64];                snprintf(buff, sizeof(buff), "dumy_%d", i%8);                event_log_t el(buff, "A,B,C");el.def(100, "pp", 5.4);                singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(el);            }            sleep(1);                        event_queryt_t::in_t in_msg;            //in_msg.str_time = "2013/2";//! 查詢1月的資料            in_msg.db_name = "test";            in_msg.sql = "select * from dumy order by logtime desc limit 5";            singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(in_msg, &lambda_t::callback);        }    };        singleton_t<msg_bus_t>::instance().get_service_group("event_log_service")->get_service(0)->async_call(in_msg, &lambda_t::callback);    signal_helper_t::wait();    singleton_t<msg_bus_t>::instance().close();    return 0;}

 

樣本php用戶端

<?phpfunction ffcount_query($host, $port, $str_time, $db_name, $sql){    //以下為引用的內容:    // 1. 初始化    $ch = curl_init();    // 2. 設定選項,包括URL    $url = "http://".$host.":".$port."/".$str_time."/".$db_name."/".rawurlencode($sql);    //echo $url."\n";    curl_setopt($ch, CURLOPT_URL, $url);    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);    curl_setopt($ch, CURLOPT_HEADER, 0);    // 3. 執行並擷取HTML文檔內容    $output = curl_exec($ch);    // 4. 釋放curl控制代碼    curl_close($ch);    if ($output === FALSE) {        //echo "cURL Error: " . curl_error($ch);        $ret = array("err_msg" =>"http request failed by curl", "col_names"=>array(), "ret_data"=>array());    }    else    {        $ret = json_decode($output);        if (!$ret)        {            $ret = array("err_msg" =>$output, "col_names"=>array(), "ret_data"=>array());        }    }    return $ret;}$host = "127.0.0.1";$port = 8080;$str_time = "2013/2";$db_name = "test";$sql = "select * from dumy";$ret = ffcount_query($host, $port, $str_time, $db_name, $sql);print_r($ret);?>

 

 樣本C++ server啟動:

./app_count -l tcp://127.0.0.1:10241 -http tcp://127.0.0.1:8080

總結:

  • ffcount 根本上提供的是資料日誌儲存
  • ffcount 使用sql來組織記錄檔,從而擁有了sql資料分析能力
  • ffcount 資料檔案按照每月歸檔
  • ffcount 自動建立表和欄位,預設建立autoid和logtime兩欄位,前者為自增主鍵,後者為timestamp類型,預設為目前時間
  • ffcount 支援http查詢,資料存放區介面已經有C++ 類庫介面

build server:

git clone https://github.com/fanchy/fflib

cd fflib/example/book/count && make && ./app_count -l tcp://127.0.0.1:10241 -http tcp://127.0.0.1:8080

build client:

cd fflib/example/book/count_client && make && ./app_client -l tcp://127.0.0.1:10241

php client:

cd fflib/example/book/count_client/php && php test.php

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.