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: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
总结:
- 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
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Hive任意命令/代码执行漏洞+渗透实例
Author: kindle Date: 2013-02-9 Hive是建立在 Hadoop 上的数据仓库基础构架。它提供了一系列的工具,可以用来进行数据提取转化加载(ETL),这是一种可以存储、查询和分析存储在 Hadoop 中的大规模数据的机制。Hive 定义了简单的类 SQL 查询语言,称为 QL,它允许熟悉 SQL 的用户查询数据。同时,这个语言也允许熟悉 MapReduce 开发者的开发自定义的 mapper 和 reducer 来处理内建的 mapper 和 reducer 无法完成的复杂的分析工作。 漏洞详情: HQL可以通过transform自定义Hive使用的 Map/Reduce 脚本,从而调用shell/python等语言,导致攻击者可以通过hive接口等相关操作方式直接获取服务器权限 测试代码: cat /root/test 1 test 创建测试表 create table if not exists kindle(id int,test string); 通过transform来自定义hive使用的shell命令,反弹shell select transfo...
- 下一篇
Session 0x0 for server null,HBase无法启动解决方法
碰到个怪问题,Master上的HMaster服务老是自动死掉, 看错误日志只是提示连接失败Session 0x0 for server null 解决方法: 1. 关闭IP6 , 修改/etc/hosts 注释以"::1 "开头的 2. 校准HBase集群Zookeeper集群机器的时间,误差30秒以内 重启机器.ok
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS关闭SELinux安全模块
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 设置Eclipse缩进为4个空格,增强代码规范
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7安装Docker,走上虚拟化容器引擎之路