阿里巴巴菜鸟级数据产品经理半年回顾总结篇
干货教程:如何绘制业务流程图(二)
干货教程:如何绘制业务流程图(一)
技术贴:如何在数据库中秘密地查询隐私数据
攻略教程:信息图(infographic)是怎么做出来的?
分析师一定要看!用数据讲故事的五个步骤
技术篇:怎样玩转千万级别的数据?
北漂书生:大数据时代SEO数据如何搜集和分析
干货,从十大问题重新认识并读懂互联网
相似图片搜索、算法、识别的原理解析(下)
相似图片搜索、算法、识别的原理解析(上)
制作信息图时请遵循这10条原则
提高表格可读性的一些技巧,适用于Excel、PPT等数据报表
实用教程:如何让Excel图表更具“商务气质”?
一张数据信息图是这样制作完成的
菜鸟读财报,如何从上市公司财报中挖情报?
北大数据分析老鸟写给学弟们一封信
如何一步一步制作出高品质数据信息图?
总结:海量数据分析处理的十个方法
【实战经验】数据分析师如何了解老板真正想法?
零售业数据分析那些事儿
数据分析时l常用电子表格公式【大全】
用数据来告诉你 上市公司财报的秘密
这12个数据能 帮你搞定淘宝店铺
首席工程师揭秘:LinkedIn大数据后台是如何运作的?(四)
首席工程师揭秘:LinkedIn大数据后台是如何运作的?(三)
首席工程师揭秘:LinkedIn大数据后台是如何运作的?(二)
首席工程师揭秘:LinkedIn大数据后台是如何运作的?(一)
淘宝网店从激活到挽留,4步走玩转数据营销
文案怎样写才有意思、不空洞、打动人?
入门级扫盲贴:数据分析的步骤有哪些?
关系即数据,论社交媒体的关系转换
数据的力量,苹果教你用数据鄙视竞争对手
谁说文科生不能做数据分析?数据分析入行→技能提升→优势
产品运营数据分析——SPSS数据分组案例
如何追踪iPhone和iPad等移动设备的用户行为数据?
阿里巴巴中国站:用户满意度指标权重计算方法
广告中的AdNetwork、AdExchange、DSP、SSP、RTB和DMP是什么?
信息图制作教程:关于数值的表现
为什么大数据会如此轰动?(值得深度的文章)
多图技术贴:深入浅出解析大数据平台架构
面板数据分析中标准误的估计修正——根据Peterson (2009)的归纳
财务官、投资人、CIO看过来:给企业数据定价
推荐系统中常用算法 以及优点缺点对比
探索Weotta搜索引擎背后的大数据技术
如何识别虚假数据?
为什么我们像驯化小狗那样驯化算法
程序员必须知道的10大基础实用算法及其讲解
电子商务:最影响转化率的九大要素
如何迅速成为一名数据分析师?
想从事大数据、海量数据处理相关的工作,如何自学打基础?
如何用亚马逊弹性MapReduce分析大数据?
译文:机器学习算法基础知识
给hadoop新手的一封信:Hadoop入门自学及对就业的帮助
从入门到精通,我是这样学习算法的
小商家,从老客户身上获取的数据才更有意义
13页PPT讲述:大数据下网站数据分析应用
40页PPT详解:京东大数据基础构架与创新应用
67页PPT解密搜索引擎背后的大技术:知识图谱,大数据语义链接的基石
营销洞察力——10个营销度量指标
技术篇:前端数据之美如何展示?
董飞:美国大数据工程师面试攻略【PPT】
easel:如何制作好的信息图——来自专家的顶级技巧
大数据实操:以3D打印机为例,如何知道卖点有没有市场需求?
大数据建模 需要了解的九大形式
用户画像数据建模方法
从规划开始,公司or企业如何入手和实施大数据?
干货:商品信息数据分析和展现系统的设计与开发
高手教你用Excel制作百度迁徙数据地图
50篇干货:淘宝店/电子商务如何玩转数据分析?
精华索引:大数据实际应用案例50篇
验证最小化可行产品 (MVP) 的 15 种方法
干货:数据分析师的完整知识结构
大数据技术Hadoop面试题,看看你能答对多少?答案在后面
用SPSS做数据分析?先弄懂SPSS的基础知识吧
怎样做出优秀的扁平化设计风格PPT? 扁平化PPT设计手册#3
解答│做大数据过程中遇到的13个问题
40页PPT│社交网络发展的新动力:大数据与众包
以Amazon、豆瓣网为例,探索推荐引擎内部的秘密#1
怎样做出优秀的扁平化设计风格PPT?#2
怎样做出优秀的扁平化设计风格PPT?#1
36页PPT│大数据分析关键技术在腾讯的应用服务创新
如何丰满地做SWOT分析?
【35页PPT】TalkingData研发副总阎志涛:移动互联网大数据处理系统架构
27页PPT|以珍爱网为例,如何构建有业务价值的数据分析系统?
国外数据新闻资源分享
21页PPT重磅发布:Mariana——腾讯深度学习平台的进展与应用
从0到100——知乎架构变迁史
PPT解读:百度大数据质量保障方案探索
45页PPT|大数据环境下实现一个O2O通用推荐引擎的实践
从数据看豆瓣兴衰
深度学习系列:解密最接近人脑的智能学习机器——深度学习及并行化实现(四)
重磅推荐:129页PPT讲述移动时代创业黄金法则 via:腾讯企鹅智酷
重磅推荐:大数据工程师飞林沙的年终总结&算法数据的思考
OpenKN——网络大数据时代的知识计算引擎
大数据下城市计算的典型应用
技术贴:大数据告诉你,如何给微信公众号文章取标题?
你的QQ暴露了你的心——QQ大数据及其应用介绍PPT
如何从企业报表看企业的生存能力?
实用的大数据技巧合集
技术帝揭秘:充电宝是如何盗取你的个人隐私的?
重磅!50页PPT揭秘腾讯大数据平台与推荐应用架构
原创教程:饼图之复合饼图与双层饼图(1)
PPT:大数据时代的设计特点——不了解这个你做不了今天的设计
教程贴:如何用方程式写春联?
原创教程:如何用Excel制作简易动态对比图
深度译文:机器学习那些事
教程帖:数学之美——手把手教你用Excel画心(动态图)
董老师走进斯坦福,聊聊硅谷创业公司和大数据的事儿(附课件PPT下载)
【限时】年度钜献,108个大数据文档PDF开放下载
董飞专栏:大数据入门——大数据相关技术、Hadoop生态、LinkedIn内部实战
亿级用户下的新浪微博平台架构
一张图了解磁盘里的数据结构
浅析数据化设计思维在阿里系产品的应用
美团推荐算法实践
一个P2P创业公司有哪些部门,都是做什么的?
一个P2P平台的详细运营框架是怎样的?
机器学习中的算法——决策树模型组合之随机森林与GBDT
神经网络简史
58页PPT看懂互联网趋势,大数据/物联网/云计算/4G都有了
广点通背后的大数据技术秘密——大规模主题模型建模及其在腾讯业务中的应用(附PPT)
微信红包之CBA实践PPT——移动互联网海量访问系统设计
一文读懂机器学习,大数据/自然语言处理/算法全有了……
搜狐新闻客户端的背后大数据技术原理——推荐系统(PPT)
原创教程:用Excel做动态双层饼图
半小时读懂PMP私有广告交易市场
怎样分析样本调研数据(译)
PPT:支付宝背后的大数据技术——DataLab、Higo的实践及应用
大数据技术人员的工具包——开源大数据处理工具list(限时下载)
计算机视觉:随机森林算法在人体识别中的应用
24页PPT:机器学习——支持向量机SVM简介(附下载)
互联网高手教你如何搜集你想要的信息
深度:对地观测大数据处理、挑战与思考
原创教程:用Excel做饼图之复合饼图与双层饼图(2)
移动大数据时代: 无线网络的挑战与机遇(附pdf下载)
Excel使用技巧——25招必学秘技
【年度热门】加上这些 Excel 技能点,秒杀众人(多图)
原创教程:用Excel做纵向折线图
知识图谱——机器大脑中的知识库
何明科专栏:用数据化的方式解析投资条款
DT时代,如何用大数据分析创造商业价值(23页PPT)
MIT牛人梳理脉络详解宏伟现代数据体系
你的老婆是怎么算出来的?揭秘佳缘用户推荐系统
飞林沙:商品推荐算法&推荐解释
PPT:如何成为真正的数据架构师?(附下载)
开源大数据查询分析引擎现状
董飞专栏:打造数据产品必知秘籍
译文:如何做强大又漂亮的信息图
如何使用Amazon Machine Learning构建机器学习预测模型
如何运用数据协助货架管理(内附26张PPT)
SVM算法
主流大数据系统在后台的层次角色及数据流向
PPT:阿里全息大数据构建与应用
人脸识别技术大总结——Face Detection & Alignment
教程:用Excel制作成对条形图
易观智库:大数据下的用户分析及用户画像(18页PPT附下载)
技术向:如何设计企业级大数据分析平台?
电商数据分析基础指标体系
IBM SPSS Modeler 决策树之银行行销预测应用分析
拓扑数据分析与机器学习的相互促进
基于 R 语言和 SPSS 的决策树算法介绍及应用
用php做爬虫 百万级别知乎用户数据爬取与分析
另类新浪微博基本数据采集方法
以10万+阅读的文章为例 教你做微信公众号的运营数据分析
破解数据三大难题:变现?交易?隐私?
微店的大数据平台建设实践与探讨
阿里巴巴PPT:大数据基础建议及产品应用之道
基于社会媒体的预测技术
人工智能简史
技巧:演讲中怎样用数据说话
马云和小贝选谁做老公?写给非数据人的数据世界入门指南
掘金大数据产业链:上游资源+中游技术+下游应用
原创教程:手把手教你用Excel做多层折线图
销售分析:如何从数据指标发现背后的故事
如何一步步从数据产品菜鸟走到骨干数据产品
也来谈谈微博的用户画像
行走在网格之间:微博用户关系模型
如何拍出和明星一样美爆的自拍照?斯坦福大学用卷积神经网络建模告诉你
运营商如何玩转大数据? 浙江移动云计算和大数据实践(PPT附下载)
大数据分析的集中化之路 建设银行大数据应用实践PPT
腾讯防刷负责人:基于用户画像大数据的电商防刷架构
创业提案的逻辑
友盟分享 | 移动大数据平台架构思想以及实践经验
寻路推荐 豆瓣推荐系统实践之路
“小数据”的统计学
重磅!8大策略让你对抗机器学习数据集里的不均衡数据
小团队撬动大数据——当当推荐团队的机器学习实践
微博推荐架构的演进
科普文 手把手教你微信公众号数据分析
信息图制作的六个注意点
【权利的游戏】剧透新玩法:情理之中?意料之外
推荐系统(Recommender System)的技术基础
核心算法 谷歌如何从网络的大海里捞到针
Quora数据科学家和机器学习工程师是如何合作的
阿里巴巴PPT:大数据下的数据安全
数据建模那点事儿
全民拥抱Docker云–Lhotse系统经验分享
实时股票分析系统的架构与算法
架构师必看 京东咚咚架构演进
什么叫对数据敏感?怎样做数据分析?
推荐系统基础知识储备
刘德寰:数据科学的整合与细分 数据科学的七个危险趋势(视频)
实际工作中,如何做简单的数据分析?
分布式前置机器学习在威胁情报中的应用(附PPT下载)
数据科学 怎样进行大数据的入门级学习?
扛住100亿次请求 如何做一个“有把握”的春晚红包系统?(PPT下载)
从 LinkedIn 的数据处理机制学习数据架构
大数据会如何改变管理咨询公司(I)
优秀大数据GitHub项目一览
生硬的数字和数据新闻:这么近,那么远
经典大数据架构案例:酷狗音乐的大数据平台重构(长文)
揭秘中兴大数据在银行领域的系统部署
基于大数据的用户画像构建(理论篇)
【R】支持向量机模型实现
数据图处处有陷阱?五个例子教你辨真伪
如何用R绘制地图
你确定你真的懂用户画像?
数据模型需要多少训练数据?
【接地气】01 数据报表的颜色怎么配
游戏价值和数据分析新思路
【R】异常值检测
快的打车架构实践
豆瓣还是朋友圈:大数据、新方法和日常问
PPT数据图表,怎么做才好看?
大道至简的数据体系构建方法论
数据的误区及自身业务
新浪微博的用户画像是怎样构建的?
面试干货!21个必知数据科学面试题和答案part1(1-11)
易观智库:中国大数据产业生态图谱2016(附下载)
Airbnb的数据基础架构
50PB海量数据排序,谷歌是这么做的
大数据时代工程师如何应对–今日头条走进硅谷技术讲座
D3.js教学记(下)
D3.js教学记(上)
飞林沙:企业级服务公司如何赚钱?只有平台级产品才有大数据的理论
一个母婴电子商务网站的大数据平台及机器学习实践
7大板块 组成数据分析师的完整知识结构
干货:SaaS领域如何分析收入增长?
学术 | 词嵌入的类比特性有实用意义吗?
6个用好大数据的秘诀
一个数据库外行眼中的微信优化 (附专家补充)
大数据调研,如何实现快全准?
数据大师Olivier Grisel给志向高远的数据科学家的指引
数据堂肖永红:数据交易的是使用权或数据的增值,而不是数据本身(PPT附下载)
淘宝商品详情平台化思考与实践
刘译璟:百分点大数据理念和实践(图文+PPT下载)
如何快速搞定一份看起来还不错的演示文档?
【BABY夜谈大数据】决策树
数据驱动设计:数据处理流程、分析方法和实战案例
美图数据总监:Facebook的法宝,我们在产品中怎么用?
树的内核:量化树结构化数据之间的相似性
拿到用户数据之后,LinkedIn怎么赚钱?
GrowingIO张溪梦:增长黑客的核心 企业应该重视产品留存率(附PPT下载)
[译]Airbnb是如何使用数据理解用户旅行体验的?
微博推荐数据服务代理: hyper_proxy的设计和实现
星图数据谷熠:消费领域DaaS 大数据重构未来商业游戏规则(附PPT下载)
鲍忠铁:TalkingData大数据技术与应用实践(PPT下载)
【干货教材】数据分析VS业务分析需求
九枝兰专访:数字营销的核心—企业如何使用数据管理平台(DMP)进行精准营销
我们的应用系统是如何支撑千万级别用户的
R应用空间数据科学
Excel进行高级数据分析(上)
Excel进行高级数据分析(下)
国内各大互联网公司2.0版技术站点收集
网站数据分析思路导图
大数据分析报表设计开发要素
大数据需要的12个工具 推荐
YARN/MRv2 Resource Manager深入剖析—NM管理
YARN/MRv2 Resource Manager深入剖析—RMApp状态机分析
Hadoop 1.0与Hadoop 2.0资源管理方案对比
Hadoop 2.0中单点故障解决方案总结
Hadoop 2.0 (YARN)中的安全机制概述
Hadoop 新特性、改进、优化和Bug分析系列1:YARN-378
Hadoop 新特性、改进、优化和Bug分析系列2:YARN-45
Hadoop 新特性、改进、优化和Bug分析系列3:YARN-392
Hadoop版本选择探讨
探究提高Hadoop稳定性与性能的方法
《Effective C++》读书笔记(第一部分)
Hadoop分布式环境下的数据抽样
Hadoop计算能力调度器算法解析
如何编写Hadoop调度器
数据结构之红黑树
Hadoop pipes设计原理
《C++ Primer plus》学习笔记之”类”
《C++ Primer plus》学习笔记之”类继承”
《C++ Primer plus》学习笔记之”C++中的代码重用”
《C++ Primer plus》学习笔记之”异常”
《C++ Primer plus》学习笔记之”RTTI”
Hadoop pipes编程
Hadoop Streaming高级编程
《C++ Primer plus》学习笔记之”标准模板库”
《C++ Primer plus》学习笔记之”输入输出库”
Linux Shell 命令总结
算法之图搜索算法(一)
awk使用总结
素数判定算法
《C++ Primer plus》学习笔记之“函数探幽”
使用Thrift RPC编写程序
如何在Hadoop上编写MapReduce程序
怎样从10亿查询词找出出现频率最高的10个

微博推荐数据服务代理: hyper_proxy的设计和实现

于2017-04-01由小牛君创建

分享到:


1. 背景

数据是微博推荐引擎的基础, 无论是未加工,过滤的由微博平台部门推送过来的原始数据还是由推荐引擎实时,准实时,离线计算出的微博关键词,推荐候选集等非原始数据, 在整个微博推荐引擎运作的过程中, 数据的读写操作随处可见.

推荐引擎在不断的进化过程中, 也逐步将数据层单独剥离开, 抽象出数据导入, 存储和对外访问的业务模型. 数据导入部分(Rin)已经较为完善, 采用消息中间件解决了经典的削峰填谷(发布, 订阅吞吐能力不对等)和上下游解耦问题, 统一采用memcache协议发布订阅; 存储部分则是主要依赖于Redis和Lushan; 数据的对外访问业务则采用了twemproxy做代理的解决方案.

代理在目前的互联网行业中应用十分广泛, 本文所关注的是7层业务代理, 即将访问请求按照一定策略路由到后端是App Server或者Data Server集群的一类服务, 换句话说, 所有叫云DB或者分布式DB的服务, 流量一定是经由此类代理来转发的, 这里不再赘述, 有兴趣的同学自行google学习.

2. 问题

在微博业务增量发展的过程中, 使用twemproxy遇到了如下的一些场景:

  1. 推荐的Lushan存储服务采用了memcache协议, twemproxy自身是支持此类协议的, 但是Lushan特有的键名格式包含db号(以微博用户为例, 键名会是”$db-$uid”,详见Lushan文档), db号依据于约定的hash规则产生, twemproxy可以自写hash模块解析键名计算路由方案, 但需要上游调用方在进行数据读取时自行hash并拼接出完整key名, 从功能划分上来说, 没有解耦, 如果hash规则有改变, 例如存储进行了扩缩容, 业务方也要更新相应代码.
  2. twemproxy目前只支持redis,memcache两种协议, 对于有其它存储服务(例如MySQL,MongoDB,http等)的业务需求, twemproxy还需要扩展, 且扩展成本较高.
  3. twemproxy的高并发异步回调模型和业务代码有很强的关联, 尤其是存储代理这种更特殊的情况(向前接收的请求和向后转发的请求都得是异步): 异步回调的模型需要定义一个精巧的struct conn(其中的一个field要还包含一个任务链表), 依靠网络IO来触发任务状态检查和next action操作, 完整的业务逻辑被打散在不同的地方
  4. twemproxy的路由转发功能是单层, 即配置中会写好代理实例对应的后端集群是redis还是memcache, twemproxy根据key值hash, 然后转发汇总结果. 对于微博推荐, 有一类业务场景是某类关键数据(例如用户取消关注)会用Mysql存储, Mysql的读性能对于推荐计算层的高并发访问显然不能够胜任. 大家立马能想到的是加缓存服务, 先读缓存, 读不到读Mysql. 这个逻辑放到计算层来去做可行但不合适(再默念一遍:IO密集型的操作很多DB Client Lib都没有考虑到, 基本实现就是一个网络封包请求加阻塞式的等待应答, 即便实现了异步接口, 基于历史原因调用方也仍然大量使用同步请求方式), 由代理层屏蔽上述流程整个架构才会解耦.

同时, 从纯技术角度来看, twemproxy也存在一些问题:

  1. twemproxy主干逻辑采用的是单进程, 异步I/O的方案去解决高并发, 同样是单核的场景, twemproxy理论上会是最快的解决方案. 不过目前的服务器大都在8核以上, 想要充分利用CPU, 就需要单机多进程的部署, 从运维角度而言, 增加了不必要的复杂度.
  2. twemproxy采用C语言开发, 如果对源码有过了解, 就知道twemproxy自己实现了数组, string, 红黑树, 队列等基础数据结构, 对于二次开发而言, 非语言built-in层面或者有专门社区维护的稳定库层面的数据结构库都会引发风险; 基于异步回调的并发编程模型, 导致其核心代码量也较大, 难于理解, 不易吃透.

PS: twemproxy已经不再作为twitter公司内部的数据访问解决方案

3. 技术调研

在有了业务需求和技术驱动的双重push下, 接下来要做的很明显: 实现一个支持高并发, 易扩展, 易维护的代理.

首先从业界开源的代理服务来着手, 除了前文说的twemproxy, 这里另外着重调研了两个:

  1. McRouter 由Facebook开源的代理, 用C++0x开发, 只支持memcache协议, 相比twemproxy的异步回调模型, McRouter自行开发了轻量级协程(fiber), 以期达到one fiber per connection的易编程模型, 这点很赞. 同时, 在业务层面, McRouter还考虑了跨机房的容错, 日志持久化等功能.

由于McRouter大量采用了Facebook自己二次开发的库, 所以整个代码量较之twemproxy更为庞大, 虽然已经声明此开源软件FB公司内部一直在用, 也在不断维护, 不过从我们自身的项目需求而言, 依然不是一个清爽的解决方案, 更倾向于把其当做一个良好的学习用的开源框架.

  1. Codis 由豌豆荚开源的代理, 用Golang开发, 只支持Redis协议, 但在架构上引入了zookeeper做配置管理, 同时对redis也进行了fork开发, 结合代理做了透明,自动化数据的sharding,resharding等, 目标是朝着Cloud key-value DB的方向迈进!

再次结合twemproxy来看, 三种开源的代理各自有一些技术上或者业务上胜出的地方, 但直接在其之上做二次开发的可行性必要性均不高, 微博推荐业务的需求需要一个从零开始的特色代理.

经过调研以及和同事们的技术讨论, 最终决定用Golang进行开发, 原因如下:

  1. Golang的开发周期相当快, demo大概一周左右实现, 很快就可以和twemproxy做benchmark对比, 如果性能成为瓶颈,很快可以重选技术方案返工:)
  2. 从易维护的角度考虑, Golang相比写高并发的C/C++, 语言层面已经提供了良好的支持, 完全同步化的代码和思路, 最终实现的却是异步I/O的性能.
  3. 单从实现扩展技术的角度而言, 静态编译的Golang相比于C/C++没有明显优势, 但是结合易维护的扩展角度考虑, Golang的协程模型让其再次胜出.
  4. High Concurrency和High Performance最大的区别在于高并发引入了IO密集型操作, IO操作的时延和Go VS C/C++的性能差距完全不是一个量级, 所以引入Golang做代理理论上不会造成qps数量级的差异.

4 .代理设计

从业务需求出发, 主干功能如下:

访问协议支持redis,memcache,http, 后端服务支持redis,memcache,mysql(有需求可添加新货), 按照定义的hash规则(取余, 一致性hash等), 路由请求到对应后端服务器.

给代理定的目标是支持到二级数据服务集群管理, 即缓存数据服务层当做第一层存热点数据, 持久化数据服务层当做第二层存全量数据(事实证明, 这个二层的设计很快就被用到了)

支持双机房自动切换, 目前组内的数据都会是双机房全量保存, 减轻跨机房调用, 一旦出现单点故障, 心跳检测会触发对等节点构建连接池, 并对请求进行响应.

回写功能, 即一级缓存层不命中, 从二级获取到数据要回写入缓存层, 由此还要解决掉因为通常数据库有的主从读写权限引发的问题.

除去主干功能, 配置,日志和监控也是做为24*7代理服务的不可或缺的部分, 这里花些时间描述下

4.1 配置

由于最先接触的是twemproxy的线上环境, 对其配置格式(yaml)和规范印象较深, 在设计代理配置时也借鉴了其一些声明规范, 最终拍板用toml格式, 相比yaml的好处不多言, 样例配置如下:

toml配置
上图中需要特殊说明的是连接池列表, 实例中用连续四个中划线分隔开, 是为了表明左右的服务分别属于不同机房, 数据通常是全量备份, 这样可以有效预防单机房硬件网络故障导致的服务不可用, 代理会透明切换到另一个机房上去. 当然如果某类存储服务就是一个单机房的单点, 删除掉四个中划线及其以后的部分就可以了

4.2 日志

IO密集型的日志本身需要缓冲+异步写的功能, 防止日志写性能影响qps, 这里Golang原生的日志库是无法满足需求的, 自己也没有从头造轮子, 直接捡了现成的库seelog, 功能很强大, 除了异步, 还支持日志按大小, 或者日期(比如一小时切分一次)切分, 还会自行维护最大日志数(再也不用维护crontab+logrotate了), 样例配置如下:

样例配置
4.3 监控

因为要保证24*7, 代理的工作状态是需要及时汇报给监控平台的, 例如当前连接数, qps请求数, 已经请求的连接数等等. 这里采用了一个简单的方式, 直接暴露一个监控http服务, 监控平台直接可以进行抓取.

有一些开源代理, 例如codis, 会在代理中嵌入一个大的Web MVC框架(martini), 结合js做一个漂亮的dashboard, 除了代理本身, 无状态代理自身的peer node(zookeeper协同), 代理管理的后端存储节点状态都会进行展示, 考虑到组内已经有相关的监控平台, 这个包袱就不扛了~

4.4 代理模块

代理在设计上大致划分为四层, 每层包含若干个模块, 模块在Go项目中体现为一个个单独的package, 即同一类功能的代理放置到一个folder下, 具体划分见下图:

代理模块划分
这里着重介绍其中一些:

协议模块protocol: 包含redis和memcache两类, 因为Golang的net.conn可以绑定bufio.Reader, redis和memcache的协议解析函数入参均为bufio.Reader, 可以方便进行流式网络数据读取. 解析协议的函数配合官方协议描述即可看懂(操作符 操作数\r\n ), 目前还没有考虑支持二进制协议.

hash模块: 目前抽象了一个hash函数类型 type HashFunc func(key string) (dbIndexNum int, serverPosition int, err error). 包含db索引是因为最早的需求里组内的Lushan服务是需要有DB号来进行访问的, 如果是像redis服务, 可以忽略db号, 目前支持的hash规则除了较为简单的取模取余还包括一致性Hash支持.

tunnel模块: 这里指的是与上游客户端的一个物理连接建立后, 不断侦听通道数据, 做解析, 处理以及回复的处理函数. 注意只有同步编程模型才能够抽象出一个理解完整的通道函数, 通道里的处理函数也是整个代理的核心, 充分利用了多协程+本地map reduce的模型来处理一次请求, 这个后文会加以说明.

entry模块: 由于proxy支持http,redis,memcache, 而后两者是直接基于tcp连接的编程, 所以这里抽象了两类入口服务, tcp和http, 其中tcp采用了任务队列加协程池的方式来避免协程在运行期的大量创建和销毁, 占用内存, 影响性能; http是golang内建的功能, 这里做封装, 主要是加入对gzip,deflate请求的数据压缩, 以及平滑关闭http服务, 同时封装一个context上下文, 让tunnel模块中的业务处理函数能够得知某一个请求对应的实例名, 对应后端连接池等信息

conn-pool模块: 连接池模块是用来维护初始固定长度的和后端数据存储服务的连接资源, 避免每一次client请求触发一个和后端DB服务的新连接, 除此之外, 连接池模块还要做是应对DB服务不稳定, 超时等带来的连接失效问题, 以及跨机房切换, 心跳检测. 这里涉及最多的就是锁的运用, 例如心跳检测失败事件导致的连接池资源关闭,重置和不断来的获取连接池资源请求的race condition, 让获取连接池资源变得透明(例如:后端机器无响应能很快实时返回; 有跨机房节点, 返回跨机房的连接; 本机房数据服务恢复后能再次切换回来)

common模块: common模块就是上图中的蓝色基础层, 此模块的子模块包含了封装日志;配置;Mysql DB操作(因为目前没有支持mysql协议代理的需求, 只是后端存储可能会用到, 所以直接用了现成稳定的client库);监控服务;异常库;util工具库, 看似此模块最边缘, 其实起的作用非常大, 没好轮子的车绝对跑不快.

业务逻辑模块: 上图中最上层标黄的业务层对应代理main函数所在的hyper_proxy package, 完成的事情包括但不限于: 加载外部配置文件; 启动监控以及调试服务; 初始化连接池并绑定实例; 启动对应实例; 在程序结束时, 走关闭实例监听连接, 关闭对应连接池的操作.

4.5 业务

在立项之初, 能够完成一次典型的multi-key读操作就是代理业务层(tunnel模块)的设计核心, 考虑到Golang的并发模型, 采用层次化的多协程worker协同工作对于此类需求易理解, 易开发, 易扩展(见下图) 其它的写操作, 获取DB状态操作或者取single-key的操作会自动收敛成单任务链完成.

层次化的多协程worker
例如, 上游的推荐计算层需要一次性的获取多个key(可能是用户uid或者是微博mid)的内容, 返回结果内容后应用计算策略计算并生成推荐结果. 如果是走redis协议, 命令会是mget key1,key2,key3…keyN, 这N个键值会hash到不同的后端DB服务上去, 我们的处理流程如下:

将N个key利用配置Hash方法, 计算出K个集合, 集合1代表落到后端DB服务器1上的key set, 以此类推, 集合K代表落到后端DB服务器K上的key set;

针对步骤1中的K个集合, 创建K个goroutine, 每个goroutine针对自己对应的集合对后端DB服务进行mget读操作, 读完结果后push到Go channel中, 这里要注意的一点是, push的结构体里要包含key在客户请求中的原始位置, 方便汇总时拼接返回结果; 在此之后, 不断的从Go channel中读取数据, 汇总结果;

步骤2中的K个goroutine都完成各自任务后, 关闭步骤2中的channel.

以上的三个步骤看似简单, 用分治的方法去各自解决问题, 实际上背后还隐藏着Golang语言的同步编程模型+异步IO高性能的特性, 不过这是另一个话题, 不在本文的讨论范围之内.

其实以上的处理流程很容易扩展成解决多层次存储的代理解决方案, 例如步骤2中可以递归嵌套下一层中相似的1,2,3的处理逻辑, 这也是@传鹏一直强调的分形(fractal)设计思想. 如果还不大明白, 请看下图:

分形(fractal)设计思想
上图是一个推荐业务中常见的面向二级存储的代理工作流, 比如一级存储是有热点数据的内存数据库, 二级存储是有全量数据的传统关系型数据库.

外部请求对应的goroutine协程(一级控制逻辑)首先通过对键名集合的一级Hash, 分成若干个key子集合, 每个子集合都会落在同一台一级存储的物理节点上, 一级控制逻辑会启动专门的goroutine协程去和对应的节点请求数据. 如果有查询不到的非命中key, 跳转到步骤2, 嵌套走一个分形的解决方案; 如果都能过查询到, 把结果push到一级的channel中, 一级控制逻辑做整合输出.

步骤1中一级控制逻辑启动的goroutine(二级控制逻辑)通过对一级非命中键名集合做二级Hash, 分成若干个key子集合, 每个子集合都会落在同一台二级存储的物理节点上, 二级控制逻辑会启动专门的goroutine协程去和对应的节点请求数据. 如果能查询到数据结果, 把结果push到二级的channel中, 二级控制逻辑做整合输出, 并再次把结果push到一级channel中.

从工程实现的角度来说, worker是一个goroutine(轻量级线程), 数目小于等于存储节点, channel就是一个线程/协程安全的先进先出队列(语言层面已经实现), 不同的worker取完后端数据就会push进当前层队列, 整合数据的逻辑则是不断从队列里尝试取数据(没有的话, 会阻塞等待, 所以不影响性能)

上图中workerN是一个无法在一级存储查询中命中的goroutine, 一旦遇到这种情况, workerN必须先计算非命中keys在二级存储中的内容, workerN通过二级channel的数据汇总, 把二级查询到的keys内容填充到打算反馈给一级channel的数据单元中, 然后再push进一级channel, 最终handler2会处理一级worker 1到N的所有push消息, 因为消息次序依赖于下游数据存储服务的响应, 所以汇总的时候要根据事先绑定key的offset来将内容在对应位置填充, pack完毕后返回给上游.

5 性能

整个代理的开发过程中, 从一开始的demo压测(redis-benchmark, memtier_benchmark)到后期代理原型完成后进行的python脚本高并发压测一直贯穿. 最终的吞吐性能瓶颈依赖于后端数据存储的类型, 内存数据库的IO要明显高于文件系统的IO, 而代理的目标是让业务层直接访问数据存储服务和访问代理的请求耗时没有量级差距

6 总结

目前新代理在线上的部署已经覆盖了很多业务线, 从主干功能开发完成后, 应对业务变化的上线业务基本可以在不改动代码或者少量修改的前提下完成.

问题和不足:

在业务抽象和框架化方面还存在很大不足, 参照hadoop的MR模型, 一个技术上无可挑剔的代理应该是让二次开发人员只关注在写serialize, unserialize(协议扩展), split, hash, map(拆分请求), reduce(整个请求结果)逻辑上, 其余的部分完全不必关心

代理不该被永久性的隔离为一个请求路由服务, 站在云存储和云数据库的角度来说, 请求路由只是一个基本功能, 数据自动分片(sharding),分布式的事务, 锁等一系列需求涉及到的业务和技术上的难点只会更多.

via:微博推荐

End.