摘要:
数据分析已经变得不可或缺,几乎每个公司都依赖数据分析进行决策。在我从事的网游领域,数据分析是策划新功能、优化游戏体验最重要的手段之一。网游领域的数据分析有如下特点(开发角度):
常见的数据分析系统
数据分析系统应该分为数据存储和数据分析,常见的数据分析架构有:
确定需求:
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 0
int 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客户端
<?php
function 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
总结:
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