• 一些经验数据来探索在线服务


    本文根据一些经验数据提供在线聊天服务

    一个典型的场景:学生的数据,每天早上在设置Hive用户行为数据的基于历史数据的计算,通过工具将数据推HBase,通过业务合作伙伴RPC Service获取用户行为数据

    总体架构


    调度:启动计算/传输任务
    监控:监控任务执行(可视化界面)。异常报警
    质量:对核心数据质做质量检查
    传输:将数据从HDFS/HIVE导入HBase/Redis/Memcache/Mysql
    RPC Service:通过Service获取数据
    JDBC:获取Mysql中的数据
    Memcache:作为HBase/Redis的查询缓冲层


    业务接入存储选型

    一个新增的数据服务。在选取存储类型时,follow下面原则:
    1. 优先使用HBase/Redis。HBase/Redis无法支持的查询语义使用Mysql(分页查询,count)
    2. 小数据量(内存占用<10G量级)或者对查询响应时间要求非常高的应用使用Redis(user profile)
    3. 海量数据使用HBase(用户行为流水/消息)

    传输设计

    參考阿里DataX的设计,实现了点评的异构数据离线传输工具wormhole。支持HBase、Redis、Memcache、Mysql写入
    离线数据在计算完毕后,通过wormhole将数据从Hive导出到HBase、Redis、Memcache、Mysql
    遇到的问题:
    1. 数据在写入时影响查询性能
    方案:

    • 增量导入:在Hive上实现了一个数据对照工具,仅仅导入变更数据到线上服务存储
    • 限速导入:导的过程中限速
    2. 怎样保证数据导入过程数据的可用性
    对于Mysql:先将数据写入暂时表,再完毕切换
    对于HBase/Memcache/Redis:使用Update的方式写入。不影响数据可用性
    3. 传输任务失败怎么办?
    參考之前写的一篇Sqoop的容错方案。思路基本上就下面几种:
    对于一个传输工具/平台,传输任务失败不可怕,可怕的地方在于“脏数据”怎样处理。3种思路:
    1. 暂时表:使用暂时表缓存数据,然后在一个transaction中将暂时表的数据move到目的表
    2. 自己定义回滚:通过用户自己定义的语句/方法,在任务失败后。运行清数据操作
    3. 传输任务的幂等性:假设一个任务失败了,产生了脏数据。解决这个问题后,再跑一次任务。可以终于正确,比如hive写入使用INSERT OVERWRITE

    HBase方案设计

    HBase集群主要目标包含:
    1. 支持海量数据(数十亿级)快速存取
    2. 集群高可用
    3. 终于一致性
    方案:
    1. 两套HBaes集群。M-M做Replication
    2. 用户通过Service訪问
    3. 封装client。主要工作:易用性、集群切换
    演示样例,一个HBase查询API:
    	/**
    	 * 单个查询:依据表名、key、family、column返回value
    	 * 
    	 * @param tableName
    	 *            表名
    	 * @param key
    	 *            查询的key      
    	 * @param family
    	 *            列所在的family(规范定义:“dim”)
    	 * @param column
    	 *            列名
    	 * @return 
    	 *            返回指定列的value,  指定列不存在返回null
    	 * @throws 
    	 *            IOException 远程调用失败或网络异常
    	 */
    	public String query(String tableName, String key, String family,
    			String column) throws IOException;
    经验和问题:
    1. 两套集群怎样使用?
    • 正常情况下,訪问一个集群,假设集群出现故障,将请求手动切到还有一个集群
    • 在做集群变更的时候,backup集群承担了“预发环境”的职责
    • 个别高写应用和其它应用分布在不同的集群,在某个集群出问题的时候。切到一个集群,服务降级(响应时间变大)
    2. HBase遇到的问题
    • 不适合对响应时间要求非常严格的应用
    • 在做线上变更(配置改动。扩容等)时,风险非常大,慎重!慎重。
    3. 为什么通过RPC Service来请求
    • 提高易用性
    • 封装集群切换
    • jar包依赖耦合过高
    • Hadoop Kerberos安全机制令部署成本高,不利于业务扩张

    Redis集群方案

    因为需求原因,我们引入HBase比Redis更早,但HBase无法满足随机数据的快速读写需求。故而引入Redis。并做了集群方案
    其设计目标:
    1. 支持快速随机读写服务
    2. 高可用
    3. 终于一致性
    方案:

    • 通过RPC Service訪问
    • client屏蔽多个Reids Node
    • Sentine集群负责主从切换和向client汇报当前哪个结点为master结点
    • 读:轮询
    • 写/删:redis master
    • 批量写/删:部分失败则所有失败
    Redis部署
    • 线上採用128G内存的机器,每台机器8个Redis-Server结点,每一个结点内存使用量控制在10G以内,目标是减少Redis Servier结点fork子进程带来的影响
    • 考虑到我们的应用场景。线上关闭自己主动bgrewriteaof。每天凌晨同一台机器上的Redis-Server结点顺序做bgrewriteaof
    • 监控:zabbix+logscan

    Memcache:

    採用了公司现有方案
    封装了client,client採用一致性Hash,多台Memcache机器组成集群。提供超越单台机器内存的存储能力
    不保证可用性

    模型

    在我们的应用中,90%以上的请求为KV型的请求
    典型应用:
    通过userid查询这个用户的sex和age
    针对这类需求,我们统一了HBase/Memcache/Redis的查询模型为,目标是:
    数据开发同学在Hive上新增了一个字段。业务方线上能够请求到这个字段,而无需了解下层存储是什么
    模型:
    TableName Family Key Columns
    TableName:Hive中表名,包含模式名,演示样例:bi.dprpt_user_city_profile_service
    Family:列簇。一个Column Family中能够由随意多个Column组成
    Key:业务Key(比如userid,guid)
    Columns:Hbase中的qualifiers,在Redis/Memcache中被序列化为Json

    在HBase中,上述概念和HBase一致
    在Reids/Memcache中:
    TableName + Family + Key组织成为物理存储的Key
    Columns被序列化为Json
    从而统一查询接口:

    	/**
    	 * 单个查询:依据表名、key、family、column list返回value
    	 * 
    	 * @param tableName
    	 *            表名
    	 * @param key
    	 *            查询的key      
    	 * @param family
    	 *            列所在的family(默认:“dim”)
    	 * @param columnList
    	 *            列List
    	 * @return 
    	 *            返回指定列(json格式)
    	 * @throws 
    	 *            IOException 远程调用失败或网络异常
    	 */
    	public String query(String tableName, String family, String key,
    			List<String> columnList) throws IOException;

    演示样例,一张Hive中的表:
    HIVE > select * from bi.dprpt_user_city_profile_service limit 1;
    OK
    1_1     2010-09-02      2014-05-02      2010-09-02      2014-05-02      2011-06-01      2013-09-27      2010-06-08      2013-09-16      2012-08-29      2013-07-08      2       101     842
    在HBase中保存为:
    hbase(main):001:0> get 'bi.dprpt_user_city_profile_service','1_1'
    COLUMN                                             CELL                                                                                                                                              
     dim:first_app_tg_date                             timestamp=1400025620039, value=2012-08-29                                                                                                         
     dim:first_app_visit_date                          timestamp=1400025620039, value=2010-09-02                                                                                                         
     dim:first_tg_date                                 timestamp=1400025620039, value=2010-06-08                                                                                                         
     dim:first_tg_visit_date                           timestamp=1400025620039, value=2011-06-01                                                                                                         
     dim:first_visit_date                              timestamp=1400025620039, value=2010-09-02                                                                                                         
     dim:last_app_tg_date                              timestamp=1400025620039, value=2013-07-08                                                                                                         
     dim:last_app_visit_date                           timestamp=1400025620039, value=2014-05-02                                                                                                         
     dim:last_tg_date                                  timestamp=1400025620039, value=2013-09-16                                                                                                         
     dim:last_tg_visit_date                            timestamp=1400025620039, value=2013-09-27                                                                                                         
     dim:last_visit_date                               timestamp=1400025620039, value=2014-05-02                                                                                                         
     dim:prefer_tg_cat0                                timestamp=1400025620039, value=2                                                                                                                  
     dim:prefer_tg_cat1                                timestamp=1400025620039, value=101                                                                                                                
     dim:prefer_tg_region                              timestamp=1400025620039, value=842 

    在Redis/Memcache中保存为(7036447591228069586为tablename+family+key做MurmurHash之后的值):
    Redis > get 7036447591228069586
    "{"prefer_tg_cat0":"2","last_tg_date":"2013-09-16","last_tg_visit_date":"2013-09-27","last_app_visit_date":"2014-05-02","first_app_tg_date":"2012-08-29","first_visit_date":"2010-09-02","last_app_tg_date":"2013-07-08","prefer_tg_cat1":"101","prefer_tg_region":"842","first_tg_date":"2010-06-08","last_visit_date":"2014-05-02","first_app_visit_date":"2010-09-02","first_tg_visit_date":"2011-06-01"}"

    性能

    在我们的应用场景中:通过一个key,获取多个column
    各个存储响应时间(单位ms):

      AVG 95线 99.9线
    HBase 2.2 7.8 62.6
    Memcache 0.7 1.0 3.6
    Redis 0.3 0.6 1.2
    簇大小、QPS、场景是不一样的,会导致上述数据是不一样的,仅供参考


  • 相关阅读:
    centos7安装php7
    将centos7镜像源更新为阿里镜像源
    CentOS7 vscode连接本地虚拟机vsftp服务器
    php 查看扩展,配置文件路径命令
    centos查看程序监听的端口
    centos7搭建ftp服务
    redis-事务
    kettle 执行 kjb 临时文件夹 /tmp permission denied 问题
    Spring 声明式事务与编程式事务详解
    进程和线程的区别
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/5032854.html
Copyright © 2020-2023  润新知