C++ FFLIB之ffcount:通用数据分析系统
时间:2022-05-03
本文章向大家介绍C++ FFLIB之ffcount:通用数据分析系统,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
摘要:
数据分析已经变得不可或缺,几乎每个公司都依赖数据分析进行决策。在我从事的网游领域,数据分析是策划新功能、优化游戏体验最重要的手段之一。网游领域的数据分析有如下特点(开发角度):
- 数据量大;网游用户量大,用户行为多,存储数据量较大。
- 实时性要求高;比如新上的游戏功能,玩家体验和反馈希望尽快的被分析出来。
- 需求变化快。网游的需求变化日新月异,故要求数据分析系统能够快速的响应需求变化。
常见的数据分析系统
数据分析系统应该分为数据存储和数据分析,常见的数据分析架构有:
- 直接在逻辑服务中定制数据分析;这种情况往往使用mysql或这mongodb作为数据存储,优点是定制化的数据存储更加节省空间,缺点是mysql和mongodb的数据存储服务器往往成本更高,并且若增加新需求,定制化需要的开发量极大,并且维护老的数据分析代码往往十分困难,因为是高度定制化的,往往会绑定在特殊的应用背景下。
- 使用scribe做数据存储,使用hadoop分析数据。Facabook scribe server 可以利用hadoop分布式文件系统来存储大数据,电子商务或者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 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:10241n");
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
总结:
- 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
- Reporting Service报表开发
- 不要信任云:这不只是安全的问题
- C#温故而知新—闲话.Net
- c# IO&&线程 打造 定时打开指定程序
- 前FDIC主席:比特币政策不应打击加密货币发展
- 任何人都不应该控制区块链供应链
- c# IO操作(带进度的文件复制器,读取文本文件的指定行)
- 高科技来了!玩游戏一样开船的时代来了……
- C++库大全
- 人工智能行业前景预测 全球市场或超2700亿元
- Arxiv网络科学论文摘要14篇
- 工信部:网络强国建设2018年重点工作任务
- 刚刚!张小龙再出重磅!微信小程序掀起新零售红利狂潮!
- 无人驾驶系列——深度学习笔记:Tensorflow的安装-windows系统
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 自研网关:多项目的swagger聚合功能
- Prometheus 如何做到“活学活用”,大牛总结的避坑指南
- 文档驱动 —— 表单组件(一):表单元素组件 优点缺点选择文本类的Inputcheck 多选value的类型问题
- Vue3.0源码结构分析
- 【每周一库】- cached - 缓存结构型、辅助函数记忆化
- meta生成器 —— 表单元素组件 meta表单代码meta的模板data变幻
- 不用写代码也能做表单 —— 加载meta即可 菜单表单加载json运行效果。ModelAbout
- 从0到1,手把手教你入门 etcd
- 数据结构:手把手带你了解 ”图“ 所有知识!(含DFS、BFS)
- 设计模式之单例模式
- AndroidStudio创建JNI 工程与调用
- Java 版植物大战僵尸思路和源码分享!
- 你好MyBatis 入门篇
- 你好MyBatis 中级篇
- 你好MyBatis 中高级篇