关于架构:基于Nodejs打造Web架构中间层

前言Node.js自2009年诞生以来,倒退速度相当惊人,目前各种开发框架层出不穷,国内外各大公司都在应用,如国内的阿里的淘宝、天猫、阿里云、蚂蚁金服,腾讯视频、携程、百度、网易、苏宁、京东、爱奇艺、去哪儿、有赞、贝壳找房等等好多企业都在应用,大部分企业把Node.js作为中间层去利用,明天和大家简略说说对于基于Nodejs打造Web架构中间层的一些常识。 一、中间层与中间件1、什么是中间层中间层(Middle Tier)也称作应用程序服务器层或应用服务层,是用户接口或 Web 客户端与数据库之间的逻辑层。典型状况下 Web 服务器位于该层,业务对象在此实例化。中间层是生成并操作接管信息的业务规定和函数的汇合。它们通过业务规定(能够频繁更改)实现该工作,并由此被封装到在物理上与应用程序程序逻辑自身相独立的组件中。 1.1 Node作为中间层模式以Node作为中间层,当客户端关上一个网站时,先申请到node服务器这一层,通过node服务器转发申请到后端的服务器,获取数据,而后返给node的模板引擎,依据视图模板渲染好模板字符串页面,再返回给客户端,间接展现页面,如图: 1.2 负载均衡器-NginxNginx是一个高性能的WEB服务器和反向代理服务器,最罕用的软件负载均衡器。 当访问量比拟大时,频繁的申请,会给服务带来很大压力,通过负载平衡、分流,加重服务器的压力;另一方面,网站部署在多台服务器,当某台服务器故障的时候,能够马上切换到其它服务器,还能保障网站能失常拜访,这就是负载平衡的劣势。 2、什么是中间件2.1 中间件概念中间件(MiddleWare)是一种独立的系统软件服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源,中间件位于客户机服务器的操作系统之上,治理计算资源和网络通信。从这个意义上能够用一个等式来示意中间件:中间件=平台+通信,这也就限定了只有用于分布式系统中能力叫中间件,同时也把它与撑持软件和实用软件辨别开来。 在NodeJS中,中间件次要是指封装所有Http申请细节解决的办法。一次Http申请通常蕴含很多工作,如记录日志、ip过滤、查问字符串、申请体解析、Cookie解决、权限验证、参数验证、异样解决等,但对于Web利用而言,并不心愿接触到这么多细节性的解决,因而引入中间件来简化和隔离这些基础设施与业务逻辑之间的细节,让开发者可能关注在业务的开发上,以达到晋升开发效率的目标。中间件能够了解为一个对用户申请进行过滤和预处理的货色,它个别不会间接对客户端进行相应,而是将解决之后的后果传递上来。简略来说就是实现某种性能的函数。 Express是一个本身性能极简,齐全是路由和中间件形成一个web开发框架:从实质上来说,一个Express利用就是在调用各种中间件,中间件机制如图所示: 2.2 中间件机制外围实现中间件是从Http申请发动到响应完结过程中的解决办法,通常须要对申请和响应进行解决,因而一个根本的中间件的模式如下: `const middleware = (req, res, next) => { // TODO next()}` 二、中间层的意义Node.js是一个Javascript运行环境。Node.js 应用事件驱动, 非阻塞I/O 模型而得以轻量和高效,非常适合在分布式设施上运行数据密集型的实时利用。Node.js是单过程、单线程运行机制,通过事件轮询(event loop)来实现并发操作,而且性能很好。 Node.js最大的改进架构就是"减少了中间层",前后端拆散,应用Node.js来做‘BBF(backend of frontend)’在传统后端退出了Node.js这一层,通过此有两点益处,前端接管了view层,后端渲染也开始全副由前端掌控,另一个就是接口层减少了一层。在前后端拆散的人造抉择下,Node.js中间层能够承当更多的责任。 1、Node.js中间层可做的工作代理:在开发环境下,咱们能够利用代理来,解决最常见的跨域问题;在线上环境下,咱们能够利用代理,转发申请到多个服务端。缓存:缓存其实是更凑近前端的需要,用户的动作触发数据的更新,Node.js中间层能够间接解决一部分缓存需要。限流:Node.js中间层,能够针对接口或者路由做响应的限流。日志:相比其余服务端语言,Node.js中间层的日志记录,能更方便快捷的定位问题(是在浏览器端还是服务端)。监控:善于高并发的申请解决,做监控也是适合的选项。鉴权:有一个中间层去鉴权,也是一种繁多职责的实现。路由:前端更须要把握页面路由的权限和逻辑。服务端渲染:Node.js中间层的解决方案更灵便,比方SSR、模板直出、利用一些JS库做预渲染等等。2、Node.js中间层带来的益处通过PC Web本人的中间层,能够依照业务定制化接口,扩充前端展示的能力和范畴;中间层接口由应用接口的前端工程师开发,对展示和接口的性能更加相熟,防止了以前的工作模式中接口方跟各方的需要对接、沟通、联调工夫,这样使得我的项目的推动更加顺利,我的项目迭代会更快;中间层应用NodeJS,开发语言是JavaScript,跟当初前端工程师的工作语言一样,缩小了学习老本;中间层接口的开发由前端工程师同时负责开发,既节俭了人力老本,同时又进步了前端开发人员的技术能力,使得前端工程师向全栈工程师迈进。3、Node.js中间层的劣势性能拆散,加重板块累赘;跨零碎、跨终端均可重用页面数据校验、逻辑代码,无需因为新零碎、终端的接入而重写校验;只在中间件中做一次数据校验,防止了前端做数据校验的同时后端也要做校验的反复,在无效保证数据的有效性的同时升高了团队整体的工作量;解决数据逻辑,解放了前端既要做页面渲染又要写简单的逻辑,使得页面开发人员专一于页面渲染,不仅使得分工更为明确,我的项目合作效率更高,更重要的是疾速响应页面使得页面加载更快,用户体验更好,防止了浏览器长时间显示空白页面的不敌对体验,真正的前后端拆散。三、中间层的实现后面写了很多实践方面的常识,接下来本人手动来简略实现Node.js基于Koa框架实现的中间层。 1、后端提供的接口先理解一下后端提供的一个接口,依据前端页面输出不同账号信息,后端接口会返回不同的值,如图: 这段PHP代码是依据前端传给不同的用户名和明码状态返回不同的状态码。 2、搭建前端页面前端页面用了ejs模板引擎采纳服务端渲染形式来进行。前端页面次要有三个代码的文件,app.js,admin.js,admin.ejs。 2.1 我的项目代码构造 2.2 我的项目代码展现1、是app.js代码 `const Koa = require('koa');// 路由const Router = require('koa-router');// 模板引擎const ejs = require('koa-ejs');// 数据解析const body = require('koa-bodyparser');// 解决动态文件const static = require("koa-static");const path = require('path');const app = new Koa();ejs(app,{ ...

July 31, 2020 · 2 min · jiezi

关于架构:保障服务稳定之服务限流

一、前言对于一个零碎而言,最重要的要求之一必定就是服务的稳定性了,一个不稳固的零碎可能给企业带来微小的损失,包含经济和品牌等等方面的损失。 咱们都心愿零碎能稳固牢靠地对外提供服务,响应快,不宕机,不故障,然而在理论状况中,经常会遇到一些异样的状况,这就考验咱们零碎的稳定性了。 明天就来讲讲保障服务稳定性的伎俩之一的服务限流。 二、解决的问题咱们零碎运行过程中有时候可能会遇到突发异样大流量,如果零碎无奈正确处理这些忽然涌入大量申请,就会导致系统轻则响应慢,常常超时,重则导致整个零碎宕机,因而这就要求咱们零碎能以肯定的策略解决大流量的涌入,这样才不对被突发大流量压垮,导致齐全无奈对外提供服务。 留神,这里大流量说的是突发异样大流量,是非正常状况,所以咱们的解决策略是对局部申请进行抛弃或者排队解决,保障咱们零碎对外还是可用的,而非全副申请都须要解决完。而对于零碎失常的一般流量来说,如果其申请量逐步达到了咱们零碎的负载能力的下限的话,这时候须要进行的就是服务的扩容,而不是限流并抛弃申请了。 咱们零碎可能遇到的突发大流量的场景有很多,但对立的体现都是,某些接口申请量激增,导致超过了零碎的解决能力了,例如: 突发热点事件(例如微博热搜)爬虫歹意攻打歹意刷单(如12306)··· 面对突发大流量,咱们零碎能应用的伎俩之一就是服务限流了。限流是通过对一个时间段解决内的申请量进行限度来爱护零碎,一旦达到限度速率则能够抛弃申请,从而管制了零碎解决的申请量不会超过其解决能力。 限流可能在整个网络申请过程的各个层面产生,例如nginx,业务代码层等,这里次要介绍的是限流的思维,也就是限流算法,并给出业务层的代码实现例子。 三、限流算法1、计数器算法计数器限流算法是比较简单粗犷的算法,次要通过一个或者多个计数器来统计一段时间内的申请总量,而后判断是否超过限度,超过则进行限流,不超过则对应的计数器数量加1。 计数器限流算法又能够分为固定窗口和滑动窗口两种。 固定窗口固定窗口计数器限流算法是统计固定一个工夫窗口内的申请总数来判断是否进行限流,例如限度每分钟申请总数为100,则能够通过一个计数器来统计以后分钟的申请总数,每来一个申请判断以后分钟对应的计数器的数量,没有超过限度则在以后分钟对应的计数器加1,超过则拒绝请求。 PHP实现逻辑如下: /** * 固定窗口计数器限流算法 * @param $key string 限流根据,例如uid,url等 * @param $time int 限流时间段,单位秒 * @param $limit int 限流总数 */function limit($key, $time, $limit) { //以后工夫所在分片 $current_segment=floor(time() / $time); //按以后工夫和限流参数生成key $current_key = $key . '_' . $time . '_' . $limit . '_' . $current_segment; $redis = new Redis(); //key不存在才设置,且设置过期工夫 $redis->set($current_key, 0, ['nx', 'ex' => $time]); $current = $redis->incr($current_key); //为了解决申请并发的问题,代码实现上要先加再判断 if ($current > $limit) { return false; } return true;}毛病 ...

July 28, 2020 · 2 min · jiezi

关于架构:来聊一聊前端架构之一前端架构认知

没有一种架构是能够满足所有迭代的需要的前言架构并不是只限于技术选型是架构设计作为软件生命周期的一部分,并不是说开始的时候 设计实现后就会变化无穷,软件的生命周期蕴含了迭代、保护、重构等过程,架构设计亦是如此,所以说架构是须要变动的,目标就是适应当前情况的开发场景。 而架构产生的工夫,必然是受到过后的约束条件,如人力、团队技术积攒、工夫、业务定位等等需要。所以,以后架构可能并不能满足将来的需要,咱们要凋谢看待这个问题,只有以后的架构合乎肯定的设计准则,将来进行架构的演进就不是问题。 “架构”这个词解释也没有一个明确的定义,每个层级,每个场景都有本人的解释,所以到底什么是架构呢? 软件架构的定义软件架构(software architecture),是一系列相干的形象模式,用于领导大型软件系统各个方面的设计。-摘自百度百科其实软件开发和盖一栋大楼一样,都须要布局、设计、施行等一系列的阶段,最开始设计修建图纸,主体架构,还要思考绿化、资料、平安等因素。通过一系列的决策,才有一套成熟的建筑施工计划,依照标准建造,能力保证质量和速度。 而开发一个软件或前端工程也是一个“修建”的过程,咱们要通过业务来定位系统间的关系,探讨技术栈和框架的选用,依据以后团队的技术水平进行技术的选型、思考各个模块间的界线和交互,上线部署策略,问题回滚策略等一系列的决策能力设计出合乎当前情况的技术架构。 前端开发过程中须要怎么的架构大体来看根本要求点如下: 合乎以后的业务定位前端架构必须具备可施行性必须匹配以后技术储备有足够的人力资源去实现具备可伸缩、可扩展性【就地取材】应该是开始设计架构的基本准则,每套架构的产生都有他的外界因素影响,所以,各个公司,各个团队之间的架构不能照搬,如果强制搬过去,可能会事与愿违,就像你那 alibaba 的技术架构去搬到 初创 公司,那是基本行不通的,人员,资源不匹配,是没方法去施行架构的。 因而咱们在我的项目前端开发的生命周期中冀望的架构应该具备哪些要点呢? 精确的业务定位,业务可能是影响架构的次要因素之一,所以咱们要找准业务上的定位明确与其余零碎之间的关系,确定与其余零碎的档次关系,相互间的通信依赖等设计好零碎内子模块之间的关系,如A业务模块须要与B模块交互,该采取怎么的形式根底模块明确,我的项目中,必然含有根底模块去提供一些专用的办法,数据去提供给各个子模块组件布局,这就是再细一层的布局了,制订组件的交互方式,开发范式开发标准和上线流程,用于领导开发中的过程架构设计 setp设计须要进行一系列的技术及非技术的相干工作 收集利益相关者的需要,产品经理、业务人员、我的项目负责人等与相应技术人员进行探讨,确定架构上的潜在限度和要求寻找可行性的技术计划细化技术计划细节,确定一些性能列表中的技术可行性确定危险点与技术人员重复探讨,汇合大家意见对技术计划进行demo的概念验证联合以后业务,细化架构的局部施行细节进行排期架构设计准则不同的架构师可能会有不同的观点,然而能被人大多数架构师认同的有一下三点 不多也不少:不做多余的设计,也不短少外围局部设计过少则为设计有余,会使一个框架的伸缩性和扩展性不强,不能灵便的面对行将产生的业务需要的迭代。设计适度也不肯定是件坏事,针对将来的技术框架或者需要的变更,咱们不能保障目前的架构就肯定能兼容这些变动,适度设计反而会让咱们一会的架构重构产生很多无用的开发变更,减少老本反而得不到相应的输入价值。 演进式:一直的演进以架构适应以后的环境适应环境可能生存下来的物种,并不是那些最强的,也不是最聪慧的,而是那些对变动做出疾速反映的。 -达尔文 演进事架构是指在开发过程中,事后设计好重要的局部如零碎模块通信,功能模块划分,具体组件颗粒度等,而后在编码过程中,再进行细颗粒度的划分,遇到不适宜的中央,进行疾速的反馈,找到最优解,最现实的状态是,20%的打算,80%的演进设计 持续性:长期的架构的改良持续性和演进式有肯定的共同性,演进式的指标是在开发过程中进行架构的细化,持续性则指在迭代过程中进行框架的进阶,在迭代过程中,难免会呈现架构不合乎当前状况的状况,咱们要灵便应答,进行持续性的优化,这样能力在迭代开发过程中,做到最优框架的目标 【提早决策】有时候“迁延症”也并不一定是害处,哈哈,开个玩笑,在咱们设计架构的时候,会经验一系列的方向决策,然而一个框架的倒退并不是总是一帆风顺,当遇到演进方向决策的时候,没有找到最优解,咱们能够进行提早决策,等等,兴许就会有答案,这样兴许会比过后匆忙做出的决定要更合乎预期。 前端架构设计的档次不同阶段形成架构的因素是不同的,基于这个思路,架构设计能够分为四个层级 1.零碎级 对于其余业务零碎,咱们该如何设计之间的通信、合作、交互。比方A零碎承载了内容库模块,B零碎须要用其中的抉择内容组件,咱们设计了一套csi。去托管通信 对于前后端的服务通信形式。ws or http,鉴权,config记录等对于报错收集解决的根底信息建设是否采纳微前端等架构2.利用级 利用级是指多个子利用间接的关系设计,可能是子利用,子模块,lib包、共享模块等,也就是架构设计的进一步细化 脚手架的设计,能够标准利用的根底,有利于疾速的构建子模块或者子利用,退出一些格式化插件,能够无效的避免一些不符合要求的代码上传到近程仓库lib包设计,能够把一些专用的,细颗粒度,反复利用性高的作为一个lib包抽取组件零碎模板,根底组件设计好模板,有利于进步开发效率3.模块级 模块级是深刻到子利用的级别的档次,颗粒度更加细化,蕴含一些设计模式和UI层面的规定,比方,单项还是双向数据流,采纳的UI模板,公共css等 4.代码级 代码级的层级用于标准开发人员的代码,进步代码品质,此档次要做的工作有: 初期的开发领导文档开发过程中的 codeReview定期的技术交换分享开发文档或代码正文的生产【小结】本文在作为一个引子,先介绍了对于架构的一个认知,简略的阐明了在开发过程中咱们须要怎么的步骤去设计一个架构,以及架构设计中咱们应该留神什么,及架构设计者应该关注的档次,接下来的文章会更深刻的介绍下前端架构 继续更新 【来聊一聊前端架构之二】前端架构的落地施行【来聊一聊前端架构之三】构建合乎以后我的项目的架构开发流程【来聊一聊前端架构之四】前端脚手架在我的项目中的利用【来聊一聊前端架构之五】前端架构中组件化的拆分【来聊一聊前端架构之六】微前端架构在我的项目中利用关注一波哦~

July 17, 2020 · 1 min · jiezi

揭秘Java架构技术体系值得一看

能够说,Java是现阶段中国互联网公司中,覆盖度最广的研发语言,把握了Java技术体系,不论在成熟的大公司,疾速倒退的公司,还是守业阶段的公司,都能有立足之地。 有不少敌人问,除了把握Java语法,还要零碎学习哪些Java相干的技术? 明天,就为大家整顿一份目前互联网公司最支流的技术选型: 想要理解更多Java架构技术的,能够关注我一下,我后续也会整顿更多对于架构技术这一块的知识点分享进去,外面会分享一些:spring,MyBatis,Netty源码剖析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化,并发编程这些成为架构师必备的常识体系.想要获取学习zl的能够微我哦:xuanwo013 一、浏览源码 程序员每天都和代码打交道。通过数年的基础教育和职业培训,大部分程序员都会「写」代码,或者至多会抄代码和改代码。然而,会读代码的并不在少数,会读代码又真正读懂一些大我的项目的源码的,少之又少。这也造成了很多谬误看源码的形式。 那要如何正确的剖析源码呢? 二、分布式架构 随着咱们的业务量越来越大和越重要,单体的架构模式曾经无奈对应大规模的利用场景,而且零碎中决不能存在单点故障导致整体不可用,所以只有垂直或是程度拆分业务零碎,使其造成一个分布式的架构,利用分布式架构来冗余零碎打消单点的故障,从而进步整个零碎的可用性。同时分布式系统的模块重用度更高,速度更快,扩展性更高是大型的我的项目必不可少的环节。 三、微服务 对于微服务架构的取舍 1、在适合的我的项目,适合的团队,采纳微服务架构收益会大于老本。 2、微服务架构有很多吸引人的中央,但在拥抱微服务之前,也须要认清它所带来的挑战。 3、须要防止为了“微服务”而“微服务”。 4、微服务架构引入策略 – 对传统企业而言,开始时能够思考引入局部适合的微服务架构准则对已有零碎进行革新或新建微服务利用,逐渐摸索及积攒微服务架构教训,而非全盘施行微服务架构。 四、性能优化 咱们不仅仅对我的项目要指挥若定,还要能解决所有性能问题。只有深刻学习JVM底层原理,Mysql底层优化以及Tomcat调优,能力达到知其然,知其所以然的成果。除了性能优化之外,也能提供通用的常见思路以及计划选型的思考点,帮忙大家造就在计划选型时的意识、思维以及做各种衡量的能力。 五、并发编程 次要造就编程者深刻理解最底层的运作原理,增强编程者逻辑思维,这样能力写出高效、平安、牢靠的多线程并发程序。 六、开发工具 通过一小段形容信息来治理我的项目的构建,报告和文档的软件项目管理工具。用于监控继续反复的工作,旨在提供一个凋谢易用的软件平台,使软件的继续集成变成可能。 能够无效、高速的解决从很小到十分大的我的项目版本治理 七、我的项目实战 要想立足于互联网公司,且能在互联网浪潮中不被吞没,对于我的项目的开发实战演练是不用可少的技能,也是对本身能力的一个掂量,有多少的量对等于取得多少的回报。看似简略的一个我的项目需要图谱,其中的底层原理,实现原理又能晓得多少? 以上这些如何学习,有没有收费材料? 对Java技术,架构技术以及算法内容感兴趣的同学,微我xuanwo013,一起学习,相互讨论。 想要理解更多Java架构技术的,能够关注我一下,我后续也会整顿更多对于架构技术这一块的知识点分享进去,外面会分享一些:spring,MyBatis,Netty源码剖析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化,并发编程这些成为架构师必备的常识体系.微微:xuanwo013

July 9, 2020 · 1 min · jiezi

什么才是真正的架构设计你又知道多少

一. 什么是架构和架构本质(文末有惊喜)在软件行业,对于什么是架构,都有很多的争论,每个人都有自己的理解。此君说的架构和彼君理解的架构未必是一回事。因此我们在讨论架构之前,我们先讨论架构的概念定义,概念是人认识这个世界的基础,并用来沟通的手段,如果对架构概念理解不一样,那沟通起来自然不顺畅。 Linux有架构,MySQL有架构,JVM也有架构,使用Java开发、MySQL存储、跑在Linux上的业务系统也有架构,应该关注哪一个?想要清楚以上问题需要梳理几个有关系又相似的概念:系统与子系统、模块与组建、框架与架构: 1.1. 系统与子系统 系统:泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能独立完成的工作能力的群体。 子系统:也是由一群关联的个体组成的系统,多半是在更大的系统中的一部分。 1.2. 模块与组件 都是系统的组成部分,从不同角度拆分系统而已。模块是逻辑单元,组件是物理单元。 模块就是从逻辑上将系统分解, 即分而治之, 将复杂问题简单化。模块的粒度可大可小, 可以是系统,几个子系统、某个服务,函数, 类,方法、 功能块等等。 组件可以包括应用服务、数据库、网络、物理机、还可以包括MQ、容器、Nginx等技术组件。 1.3. 框架与架构 框架是组件实现的规范,例如:MVC、MVP、MVVM等,是提供基础功能的产品,例如开源框架:Ruby on Rails、Spring、Laravel、Django等,这是可以拿来直接使用或者在此基础上二次开发。 框架是规范,架构是结构。 我在这重新定义架构:软件架构指软件系统的顶层结构。 架构是经过系统性地思考, 权衡利弊之后在现有资源约束下的最合理决策, 最终明确的系统骨架: 包括子系统, 模块, 组件. 以及他们之间协作关系, 约束规范, 指导原则.并由它来指导团队中的每个人思想层面上的一致。涉及四方面: 系统性思考的合理决策:比如技术选型、解决方案等。明确的系统骨架:明确系统有哪些部分组成。系统协作关系:各个组成部分如何协作来实现业务请求。约束规范和指导原则:保证系统有序,高效、稳定运行。因此架构师具备能力:理解业务,全局把控,选择合适技术,解决关键问题、指导研发落地实施。 架构的本质就是对系统进行有序化地重构以致符合当前业务的发展,并可以快速扩展。 那什么样的系统要考虑做架构设计 技术不会平白无故的出和自驱动发展起来,而架构的发展和需求是基于业务的驱动。 架构设计完全是为了业务, 需求相对复杂.非功能性需求在整个系统占据重要位置.系统生命周期长,有扩展性需求.系统基于组件或者集成的需要.业务流程再造的需要.二. 架构分层和分类架构分类可细分为业务架构、应用架构、技术架构, 代码架构, 部署架构 业务架构是战略,应用架构是战术,技术架构是装备。其中应用架构承上启下,一方面承接业务架构的落地,另一方面影响技术选型。 熟悉业务,形成业务架构,根据业务架构,做出相应的应用架构,最后技术架构落地实施。 如何针对当前需求,选择合适的应用架构,如何面向未来,保证架构平滑过渡,这个是软件开发者,特别是架构师,都需要深入思考的问题。 2.1. 业务架构(俯视架构): 包括业务规划,业务模块、业务流程,对整个系统的业务进行拆分,对领域模型进行设计,把现实的业务转化成抽象对象。 没有最优的架构,只有最合适的架构,一切系统设计原则都要以解决业务问题为最终目标,脱离实际业务的技术情怀架构往往会给系统带入大坑,任何不基于业务做异想天开的架构都是耍流氓。 所有问题的前提要搞清楚我们今天面临的业务量有多大,增长走势是什么样,而且解决高并发的过程,一定是一个循序渐进逐步的过程。合理的架构能够提前预见业务发展1~2年为宜。这样可以付出较为合理的代价换来真正达到技术引领业务成长的效果。 看看京东业务架构(网上分享图): 2.2. 应用架构(剖面架构,也叫逻辑架构图): 硬件到应用的抽象,包括抽象层和编程接口。应用架构和业务架构是相辅相成的关系。业务架构的每一部分都有应用架构。 类似: 应用架构:应用作为独立可部署的单元,为系统划分了明确的边界,深刻影响系统功能组织、代码开发、部署和运维等各方面. 应用架构定义系统有哪些应用、以及应用之间如何分工和合作。这里所谓应用就是各个逻辑模块或者子系统。 应用架构图关键有2点: ①. 职责划分: 明确应用(各个逻辑模块或者子系统)边界 逻辑分层子系统、模块定义。关键类。②. 职责之间的协作: ...

July 7, 2020 · 1 min · jiezi

架构设计模式策略模式

俗话说:条条大路通罗马。在很多情况下,实现某个目标的途径不止一条,例如我们在外出旅游时可以选择多种不同的出行方式,如骑自行车、坐汽车、坐火车或者坐飞机,可根据实际情况(目的地、旅游预算、旅游时间等)来选择一种最适合的出行方式。在制订旅行计划时,如果目的地较远、时间不多,但不差钱,可以选择坐飞机去旅游;如果目的地虽远、但假期长、且需控制旅游成本时可以选择坐火车或汽车;如果从健康和环保的角度考虑,而且有足够的毅力,自行车游或者徒步旅游也是个不错的选择。 在软件开发中,我们也常常会遇到类似的情况,实现某一个功能有多条途径,每一条途径对应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。我们将介绍一种为了适应算法灵活性而产生的设计模式——策略模式。 概述在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。 策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合“依赖倒转原则”。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。策略模式定义如下: 策略模式(Strategy Pattern):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。策略模式结构并不复杂,但我们需要理解其中环境类Context的作用,其结构如图所示: 在策略模式结构图中包含如下几个角色: Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列具体策略类里面,作为抽象策略类的子类。在策略模式中,对环境类和抽象策略类的理解非常重要,环境类是需要使用算法的类。在一个系统中可以存在多个环境类,它们可能需要重用一些相同的算法。 在使用策略模式时,我们需要将算法从Context类中提取出来,首先应该创建一个抽象策略类,其典型代码如下所示: abstract class AbstractStrategy{ abstract public function algorithm(); //声明抽象算法}然后再将封装每一种具体算法的类作为该抽象策略类的子类,如下代码所示: class ConcreteStrategyA extends AbstractStrategy{ //算法的具体实现 public function algorithm() { //算法A }}其他具体策略类与之类似,对于Context类而言,在它与抽象策略类之间建立一个关联关系,其典型代码如下所示: class Context{ /** * 维持一个对抽象策略类的引用 * @var AbstractStrategy */ private $strategy; /** * @param AbstractStrategy $strategy */ public function setStrategy(AbstractStrategy $strategy) { $this->strategy = $strategy; } //调用策略类中的算法 public function algorithm() { $this->strategy->algorithm(); }}在客户端代码中只需注入一个具体策略对象,可以将具体策略类类名存储在配置文件中,通过反射来动态创建具体策略对象,从而使得用户可以灵活地更换具体策略类,增加新的具体策略类也很方便。策略模式提供了一种可插入式(Pluggable)算法的实现方案。 案例Sunny软件公司为某电影院开发了一套影院售票系统,在该系统中需要为不同类型的用户提供不同的电影票打折方式,具体打折方案如下: 学生凭学生证可享受票价8折优惠;年龄在10周岁及以下的儿童可享受每张票减免10元的优惠(原始票价需大于等于20元);影院VIP用户除享受票价半价优惠外还可进行积分,积分累计到一定额度可换取电影院赠送的奖品。该系统在将来可能还要根据需要引入新的打折方式。 为了实现打折算法的复用,并能够灵活地向系统中增加新的打折方式,Sunny软件公司开发人员使用策略模式对电影院打折方案进行设计,基本结构如图所示: ...

July 5, 2020 · 1 min · jiezi

架构设计模式观察者模式

在软件系统中,有些对象之间存在类似交通信号灯和汽车之间的关系,一个对象的状态或行为的变化将导致其他对象的状态或行为也发生改变,它们之间将产生联动,正所谓“触一而牵百发”。为了更好地描述对象之间存在的这种一对多(包括一对一)的联动,观察者模式应运而生,它定义了对象之间一种一对多的依赖关系,让一个对象的改变能够影响其他对象。 概述观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间可以没有任何相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展。 观察者模式定义如下: 观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。观察者模式结构中通常包括观察目标和观察者两个继承层次结构,其结构如图所示: 在观察者模式结构图中包含如下几个角色: Subject(目标):目标又称为主题,它是指被观察的对象。在目标中定义了一个观察者集合,一个观察目标可以接受任意数量的观察者来观察,它提供一系列方法来增加和删除观察者对象,同时它定义了通知方法notify()。目标类可以是接口,也可以是抽象类或具体类。ConcreteSubject(具体目标):具体目标是目标类的子类,通常它包含有经常发生改变的数据,当它的状态发生改变时,向它的各个观察者发出通知;同时它还实现了在目标类中定义的抽象业务逻辑方法(如果有的话)。如果无须扩展目标类,则具体目标类可以省略。Observer(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update(),因此又称为抽象观察者。ConcreteObserver(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了在抽象观察者Observer中定义的update()方法。通常在实现时,可以调用具体目标类的attach()方法将自己添加到目标类的集合中或通过detach()方法将自己从目标类的集合中删除。观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。观察者模式包含观察目标和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知。作为对这个通知的响应,每个观察者都将监视观察目标的状态以使其状态与目标状态同步,这种交互也称为发布-订阅(Publish-Subscribe)。观察目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。 下面通过示意代码来对该模式进行进一步分析。首先我们定义一个抽象目标Subject,典型代码如下所示: abstract class Subject{ /** * 定义一个观察者集合用于存储所有观察者对象 * @var Observer[] */ protected $observers = []; //注册方法,用于向观察者集合中增加一个观察者 public function attach(Observer $observer) { $this->observers[] = $observer; } //注销方法,用于在观察者集合中删除一个观察者 public function detach(Observer $observer) { unset($this->observers[array_search($observer, $this->observers)]); } //声明抽象通知方法 abstract public function notify();}具体目标类ConcreteSubject是实现了抽象目标类Subject的一个具体子类,其典型代码如下所示: class concreteSubject extends Subject{ //实现通知方法 public function notify() { foreach ($this->observers as $observer) { $observer->update(); } }}抽象观察者角色一般定义为一个接口,通常只声明一个update()方法,为不同观察者的更新(响应)行为定义相同的接口,这个方法在其子类中实现,不同的观察者具有不同的响应方法。抽象观察者Observer典型代码如下所示: interface Observer{ //声明响应方法 public function update();}在具体观察者ConcreteObserver中实现了update()方法,其典型代码如下所示: ...

July 4, 2020 · 2 min · jiezi

架构设计模式迭代器模式

在软件开发中,存在一些类,它们可以存储多个成员对象(元素),这些类通常称为聚合类(Aggregate Classes),对应的对象称为聚合对象。为了更加方便地操作这些聚合对象,同时可以很灵活地为聚合对象增加不同的遍历方法,我们也需要类似电视机遥控器一样的角色,可以访问一个聚合对象中的元素但又不需要暴露它的内部结构。本章我们将要学习的迭代器模式将为聚合对象提供一个遥控器,通过引入迭代器,客户端无须了解聚合对象的内部结构即可实现对聚合对象中成员的遍历,还可以根据需要很方便地增加新的遍历方式。 概述在软件开发中,我们经常需要使用聚合对象来存储一系列数据。聚合对象拥有两个职责:一是存储数据;二是遍历数据。从依赖性来看,前者是聚合对象的基本职责;而后者既是可变化的,又是可分离的。因此,可以将遍历数据的行为从聚合对象中分离出来,封装在一个被称之为“迭代器”的对象中,由迭代器来提供遍历聚合对象内部数据的行为,这将简化聚合对象的设计,更符合“单一职责原则”的要求。 迭代器模式定义如下: 迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。在迭代器模式结构中包含聚合和迭代器两个层次结构,考虑到系统的灵活性和可扩展性,在迭代器模式中应用了工厂方法模式,其模式结构如图所示: 在迭代器模式结构图中包含如下几个角色: Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法,例如:用于获取第一个元素的first()方法,用于访问下一个元素的next()方法,用于判断是否还有下一个元素的hasNext()方法,用于获取当前元素的currentItem()方法等,在具体迭代器中将实现这些方法。ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置,在具体实现时,游标通常是一个表示位置的非负整数。Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator()方法用于创建一个迭代器对象,充当抽象迭代器工厂角色。ConcreteAggregate(具体聚合类):它实现了在抽象聚合类中声明的createIterator()方法,该方法返回一个与该具体聚合类对应的具体迭代器ConcreteIterator实例。在迭代器模式中,提供了一个外部的迭代器来对聚合对象进行访问和遍历,迭代器定义了一个访问该聚合元素的接口,并且可以跟踪当前遍历的元素,了解哪些元素已经遍历过而哪些没有。迭代器的引入,将使得对一个复杂聚合对象的操作变得简单。 在迭代器模式中应用了工厂方法模式,抽象迭代器对应于抽象产品角色,具体迭代器对应于具体产品角色,抽象聚合类对应于抽象工厂角色,具体聚合类对应于具体工厂角色。 在抽象迭代器中声明了用于遍历聚合对象中所存储元素的方法,典型代码如下所示: interface Iterator { //返回游标当前指向元素 public function current(); //将游标指向下一个元素 public function next(); //返回当前元素的键 public function key(); //检查当前位置是否有效 public function valid(); //重置游标指向第一个元素 public function rewind();}在具体迭代器中将实现抽象迭代器声明的遍历数据的方法,如下代码所示: class ConcreteIterator implements Iterator{ //维持一个对具体聚合对象的引用,以便于访问存储在聚合对象中的数据 private $concreteAggregate; //定义一个游标,用于记录当前访问位置 private $cursor = 0; public function current() { ... } public function next() { ... } public function key() { ... } public function valid(): bool { ... } public function rewind() { ... }}需要注意的是抽象迭代器接口的设计非常重要,一方面需要充分满足各种遍历操作的要求,尽量为各种遍历方法都提供声明,另一方面又不能包含太多方法,接口中方法太多将给子类的实现带来麻烦。因此,可以考虑使用抽象类来设计抽象迭代器,在抽象类中为每一个方法提供一个空的默认实现。如果需要在具体迭代器中为聚合对象增加全新的遍历操作,则必须修改抽象迭代器和具体迭代器的源代码,这将违反“开闭原则”,因此在设计时要考虑全面,避免之后修改接口。 ...

June 29, 2020 · 2 min · jiezi

架构设计模式命令模式

装修新房的最后几道工序之一是安装插座和开关,通过开关可以控制一些电器的打开和关闭,例如电灯或者排气扇。在购买开关时,我们并不知道它将来到底用于控制什么电器,也就是说,开关与电灯、排气扇并无直接关系,一个开关在安装之后可能用来控制电灯,也可能用来控制排气扇或者其他电器设备。开关与电器之间通过电线建立连接,如果开关打开,则电线通电,电器工作;反之,开关关闭,电线断电,电器停止工作。相同的开关可以通过不同的电线来控制不同的电器。 在软件开发中也存在很多与开关和电器类似的请求发送者和接收者对象,例如一个按钮,它可能是一个“关闭窗口”请求的发送者,而按钮点击事件处理类则是该请求的接收者。为了降低系统的耦合度,将请求的发送者和接收者解耦,我们可以使用一种被称之为命令模式的设计模式来设计系统,在命令模式中,发送者与接收者之间引入了新的命令对象,将发送者的请求封装在命令对象中,再通过命令对象来调用接收者的方法。 概述在软件开发中,我们经常需要向某些对象发送请求(调用其中的某个或某些方法),但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,此时,我们特别希望能够以一种松耦合的方式来设计软件,使得请求发送者与请求接收者能够消除彼此之间的耦合,让对象之间的调用关系更加灵活,可以灵活地指定请求接收者以及被请求的操作。命令模式为此类问题提供了一个较为完美的解决方案。 命令模式可以将请求发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。 命令模式定义如下: 命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。命令模式的定义比较复杂,提到了很多术语,例如“用不同的请求对客户进行参数化”、“对请求排队”,“记录请求日志”、“支持可撤销操作”等,在后面将对这些术语进行一一讲解。 命令模式的核心在于引入了命令类,通过命令类来降低发送者和接收者的耦合度,请求发送者只需指定一个命令对象,再通过命令对象来调用请求接收者的处理方法,其结构如图所示: 在命令模式结构图中包含如下几个角色: Command(抽象命令类):抽象命令类一般是一个抽象类或接口,在其中声明了用于执行请求的execute()等方法,通过这些方法可以调用请求接收者的相关操作。ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接收者对象,将接收者对象的动作绑定其中。在实现execute()方法时,将调用接收者对象的相关操作(Action)。Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接收者,因此它只与抽象命令类之间存在关联关系。在程序运行时可以将一个具体命令对象注入其中,再调用具体命令对象的execute()方法,从而实现间接调用请求接收者的相关操作。Receiver(接收者):接收者执行与请求相关的操作,它具体实现对请求的业务处理。命令模式的本质是对请求进行封装,一个请求对应于一个命令,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求要求执行一个操作;接收的一方收到请求,并执行相应的操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求如何被接收、操作是否被执行、何时被执行,以及是怎么被执行的。 命令模式的关键在于引入了抽象命令类,请求发送者针对抽象命令类编程,只有实现了抽象命令类的具体命令才与请求接收者相关联。在最简单的抽象命令类中只包含了一个抽象的execute()方法,每个具体命令类将一个Receiver类型的对象作为一个实例变量进行存储,从而具体指定一个请求的接收者,不同的具体命令类提供了execute()方法的不同实现,并调用不同接收者的请求处理方法。 典型的抽象命令类代码如下所示: abstract class Command{ abstract public function execute();}对于请求发送者即调用者而言,将针对抽象命令类进行编程,可以通过构造注入或者设值注入的方式在运行时传入具体命令类对象,并在业务方法中调用命令对象的execute()方法,其典型代码如下所示: class Invoker{ private $command; //构造注入 public function __construct(Command $command) { $this->command = $command; } //设值注入 public function setCommand(Command $command) { $this->command = $command; } //业务方法,用于调用命令类的execute()方法 public function call() { $this->command->execute(); }}具体命令类继承了抽象命令类,它与请求接收者相关联,实现了在抽象命令类中声明的execute()方法,并在实现时调用接收者的请求响应方法action(),其典型代码如下所示: class ConcreteCommand extends Command{ //维持一个对请求接收者对象的引用 private $receiver; public function execute() { //调用请求接收者的业务处理方法action() $this->receiver->action(); }}请求接收者Receiver类具体实现对请求的业务处理,它提供了action()方法,用于执行与请求相关的操作,其典型代码如下所示: class Receiver{ public function action() { //具体操作 }}案例Sunny软件公司开发人员为公司内部OA系统开发了一个桌面版应用程序,该应用程序为用户提供了一系列自定义功能键,用户可以通过这些功能键来实现一些快捷操作。Sunny软件公司开发人员通过分析,发现不同的用户可能会有不同的使用习惯,在设置功能键的时候每个人都有自己的喜好,例如有的人喜欢将第一个功能键设置为“打开帮助文档”,有的人则喜欢将该功能键设置为“最小化至托盘”,为了让用户能够灵活地进行功能键的设置,开发人员提供了一个“功能键设置”窗口,该窗口界面如图所示: ...

June 28, 2020 · 3 min · jiezi

架构设计模式职责链模式

在类似“斗地主”这样的纸牌游戏中,某人出牌给他的下家,下家看看手中的牌,如果要不起上家的牌则将出牌请求再转发给他的下家,其下家再进行判断。一个循环下来,如果其他人都要不起该牌,则最初的出牌者可以打出新的牌。在这个过程中,牌作为一个请求沿着一条链在传递,每一位纸牌的玩家都可以处理该请求。在设计模式中,我们也有一种专门用于处理这种请求链式传递的模式,它就是职责链模式。 概述很多情况下,在一个软件系统中可以处理某个请求的对象不止一个,例如SCM系统中的采购单审批,主任、副董事长、董事长和董事会都可以处理采购单,他们可以构成一条处理采购单的链式结构,采购单沿着这条链进行传递,这条链就称为职责链。职责链可以是一条直线、一个环或者一个树形结构,最常见的职责链是直线型,即沿着一条单向的链来传递请求。链上的每一个对象都是请求处理者,职责链模式可以将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行相应的处理,客户端无须关心请求的处理细节以及请求的传递,只需将请求发送到链上即可,实现请求发送者和请求处理者解耦。 职责链模式定义如下: 职责链模式(Chain of Responsibility Pattern):避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。职责链模式结构的核心在于引入了一个抽象处理者。职责链模式结构如图所示: 在职责链模式结构图中包含如下几个角色: Handler(抽象处理者):它定义了一个处理请求的接口,一般设计为抽象类,由于不同的具体处理者处理请求的方式不同,因此在其中定义了抽象请求处理方法。因为每一个处理者的下家还是一个处理者,因此在抽象处理者中定义了一个抽象处理者类型的对象(如结构图中的successor),作为其对下家的引用。通过该引用,处理者可以连成一条链。ConcreteHandler(具体处理者):它是抽象处理者的子类,可以处理用户请求,在具体处理者类中实现了抽象处理者中定义的抽象请求处理方法,在处理请求之前需要进行判断,看是否有相应的处理权限,如果可以处理请求就处理它,否则将请求转发给后继者;在具体处理者中可以访问链中下一个对象,以便请求的转发。在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。 职责链模式的核心在于抽象处理者类的设计,抽象处理者的典型代码如下所示: abstract class Handler{ //维持对下家的引用 protected $successor; public function setSuccessor(Handler $successor) { $this->successor = $successor; } abstract public function handleRequest(string $request);}上述代码中,抽象处理者类定义了对下家的引用对象,以便将请求转发给下家,该对象的访问符可设为protected,在其子类中可以使用。在抽象处理者类中声明了抽象的请求处理方法,具体实现交由子类完成。 具体处理者是抽象处理者的子类,它具有两大作用:第一是处理请求,不同的具体处理者以不同的形式实现抽象请求处理方法handleRequest();第二是转发请求,如果该请求超出了当前处理者类的权限,可以将该请求转发给下家。具体处理者类的典型代码如下: class ConcreteHandler extends Handler{ public function handleRequest(string $request) { if (满足请求条件) { //处理请求 } else { //转发请求 $this->successor->handleRequest($request); } }}需要注意的是,职责链模式并不创建职责链,职责链的创建工作必须由系统的其他部分来完成,一般是在使用该职责链的客户端中创建职责链。职责链模式降低了请求的发送端和接收端之间的耦合,使多个对象都有机会处理这个请求。 案例Sunny软件公司承接了某企业SCM(Supply Chain Management,供应链管理)系统的开发任务,其中包含一个采购审批子系统。该企业的采购审批是分级进行的,即根据采购金额的不同由不同层次的主管人员来审批,主任可以审批5万元以下(不包括5万元)的采购单,副董事长可以审批5万元至10万元(不包括10万元)的采购单,董事长可以审批10万元至50万元(不包括50万元)的采购单,50万元及以上的采购单就需要开董事会讨论决定。如图所示: 如果采用一个处理类PurchaseRequestHandler统一处理所有审批请求的话,会造成以下几个问题: PurchaseRequestHandler类较为庞大,各个级别的审批方法都集中在一个类中,违反了“单一职责原则”,测试和维护难度大。如果需要增加一个新的审批级别或调整任何一级的审批金额和审批细节(例如将董事长的审批额度改为60万元)时都必须修改源代码并进行严格测试,此外,如果需要移除某一级别(例如金额为10万元及以上的采购单直接由董事长审批,不再设副董事长一职)时也必须对源代码进行修改,违反了“开闭原则”。审批流程的设置缺乏灵活性,现在的审批流程是“主任-->副董事长-->董事长-->董事会”,如果需要改为“主任-->董事长-->董事会”,在此方案中只能通过修改源代码来实现,客户端无法定制审批流程。为了让采购单的审批流程更加灵活,并实现采购单的链式传递和处理,Sunny公司开发人员使用职责链模式来实现采购单的分级审批,其基本结构如图所示: 抽象类Approver充当抽象处理者(抽象传递者),Director、VicePresident、President和Congress充当具体处理者(具体传递者),PurchaseRequest充当请求类。完整代码如下所示: <?php//采购单:请求类class PurchaseRequest{ private $amount; //采购金额 private $number; //采购单编号 private $purpose; //采购目的 public function __construct(float $amount, int $number, string $purpose) { $this->amount = $amount; $this->number = $number; $this->purpose = $purpose; } public function setAmount(float $amount) { $this->amount = $amount; } public function getAmount(): float { return $this->amount; } public function setNumber(int $number) { $this->number = $number; } public function getNumber(): int { return $this->number; } public function setPurpose(string $purpose) { $this->purpose = $purpose; } public function getPurpose(): string { return $this->purpose; }}//审批者类:抽象处理者abstract class Approver{ protected $successor; //定义后继对象 protected $name; //审批者姓名 public function __construct(string $name) { $this->name = $name; } //设置后继者 public function setSuccessor(Approver $successor) { $this->successor = $successor; } //抽象请求处理方法 abstract public function processRequest(PurchaseRequest $request);}//主任类:具体处理者class Director extends Approver{ public function __construct(string $name) { parent::__construct($name); } //具体请求处理方法 public function processRequest(PurchaseRequest $request) { if ($request->getAmount() < 50000) { //处理请求 echo '主任审批'; } else { //转发请求 $this->successor->processRequest($request); } }}//副董事长类:具体处理者class VicePresident extends Approver{ public function __construct(string $name) { parent::__construct($name); } //具体请求处理方法 public function processRequest(PurchaseRequest $request) { if ($request->getAmount() < 100000) { //处理请求 echo '副董事长审批'; } else { //转发请求 $this->successor->processRequest($request); } }}//董事长类:具体处理者class President extends Approver{ public function __construct(string $name) { parent::__construct($name); } //具体请求处理方法 public function processRequest(PurchaseRequest $request) { if ($request->getAmount() < 500000) { //处理请求 echo '董事长审批'; } else { //转发请求 $this->successor->processRequest($request); } }}//董事会类:具体处理者class Congress extends Approver{ public function __construct(string $name) { parent::__construct($name); } //具体请求处理方法 public function processRequest(PurchaseRequest $request) { echo '召开董事会审批'; }}class Client{ public function test() { $director = new Director('张主任'); $vicePresident = new VicePresident('杨副总'); $president = new President('王董事长'); $congress = new Congress('董事会'); //创建职责链 $director->setSuccessor($vicePresident); $vicePresident->setSuccessor($president); $president->setSuccessor($congress); //创建采购单 $pr1 = new PurchaseRequest(45000, 10001, '购买办公桌'); $director->processRequest($pr1); $pr2 = new PurchaseRequest(60000, 10002, '购买打印机'); $director->processRequest($pr2); $pr3 = new PurchaseRequest(160000, 10003, '购买台式机'); $director->processRequest($pr3); $pr4 = new PurchaseRequest(800000, 10004, '购买服务器'); $director->processRequest($pr4); }} 如果需要在系统增加一个新的具体处理者,如增加一个经理(Manager)角色可以审批5万元至8万元(不包括8万元)的采购单,需要编写一个新的具体处理者类Manager,作为抽象处理者类Approver的子类,实现在Approver类中定义的抽象处理方法,如果采购金额大于等于8万元,则将请求转发给下家。 ...

June 27, 2020 · 2 min · jiezi

架构设计模式享元模式

当前咱们国家正在大力倡导构建和谐社会,其中一个很重要的组成部分就是建设资源节约型社会,“浪费可耻,节俭光荣”。在软件系统中,有时候也会存在资源浪费的情况,例如在计算机内存中存储了多个完全相同或者非常相似的对象,如果这些对象的数量太多将导致系统运行代价过高,内存属于计算机的“稀缺资源”,不应该用来“随便浪费”,那么是否存在一种技术可以用于节约内存使用空间,实现对这些相同或者相似对象的共享访问呢?答案是肯定,这种技术就是我们将要学习的享元模式。 概述当一个软件系统在运行时产生的对象数量太多,将导致运行代价过高,带来系统性能下降等问题。例如在一个文本字符串中存在很多重复的字符,如果每一个字符都用一个单独的对象来表示,将会占用较多的内存空间,那么我们如何去避免系统中出现大量相同或相似的对象,同时又不影响客户端程序通过面向对象的方式对这些对象进行操作?享元模式正为解决这一类问题而诞生。享元模式通过共享技术实现相同或相似对象的重用,在逻辑上每一个出现的字符都有一个对象与之对应,然而在物理上它们却共享同一个享元对象,这个对象可以出现在一个字符串的不同地方,相同的字符对象都指向同一个实例,在享元模式中,存储这些共享实例对象的地方称为享元池(Flyweight Pool)。我们可以针对每一个不同的字符创建一个享元对象,将其放在享元池中,需要时再从享元池取出。如图所示: 享元模式以共享的方式高效地支持大量细粒度对象的重用,享元对象能做到共享的关键是区分了内部状态(Intrinsic State)和外部状态(Extrinsic State)。下面将对享元的内部状态和外部状态进行简单的介绍: 内部状态是存储在享元对象内部并且不会随环境改变而改变的状态,内部状态可以共享。如字符的内容,不会随外部环境的变化而变化,无论在任何环境下字符“a”始终是“a”,都不会变成“b”。外部状态是随环境改变而改变的、不可以共享的状态。享元对象的外部状态通常由客户端保存,并在享元对象被创建之后,需要使用的时候再传入到享元对象内部。一个外部状态与另一个外部状态之间是相互独立的。如字符的颜色,可以在不同的地方有不同的颜色,例如有的“a”是红色的,有的“a”是绿色的,字符的大小也是如此,有的“a”是五号字,有的“a”是四号字。而且字符的颜色和大小是两个独立的外部状态,它们可以独立变化,相互之间没有影响,客户端可以在使用时将外部状态注入享元对象中。正因为区分了内部状态和外部状态,我们可以将具有相同内部状态的对象存储在享元池中,享元池中的对象是可以实现共享的,需要的时候就将对象从享元池中取出,实现对象的复用。通过向取出的对象注入不同的外部状态,可以得到一系列相似的对象,而这些对象在内存中实际上只存储一份。 享元模式定义如下: 享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。享元模式结构较为复杂,一般结合工厂模式一起使用,在它的结构图中包含了一个享元工厂类,其结构图如图所示: 在享元模式结构图中包含如下几个角色: Flyweight(抽象享元类):通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类;当需要一个非共享具体享元类的对象时可以直接通过实例化创建。FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),返回新创建的实例并将其存储在享元池中。在享元模式中引入了享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,当用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。典型的享元工厂类的代码如下: class FlyweightFactory{ //存储享元对象,实现享元池 private $pool = []; public function getFlyweight(string $name): Flyweight { //如果对象不存在,先创建并添加到享元池中,再返回 if (!isset($this->pool[$name])) { $this->pool[$name] = new CharacterFlyweight($name); } return $this->pool[$name]; }}享元类的设计是享元模式的要点之一,在享元类中要将内部状态和外部状态分开处理,通常将内部状态作为享元类的成员变量,而外部状态通过注入的方式添加到享元类中。典型的享元类代码如下所示: abstract class Flyweight{ //内部状态intrinsicState作为成员变量 //同一个享元对象其内部状态是一致的 private $intrinsicState; public function __construct(string $intrinsicState) { $this->intrinsicState = $intrinsicState; } //外部状态extrinsicState在使用时由外部设置, //不保存在享元对象中, //即使是同一个对象,在每一次调用时也可以传入不同的外部状态 abstract public function operation(string $extrinsicState);}案例Sunny软件公司欲开发一个围棋软件,其界面效果如图所示: Sunny软件公司开发人员通过对围棋软件进行分析,发现在围棋棋盘中包含大量的黑子和白子,它们的形状、大小都一模一样,只是出现的位置不同而已。如果将每一个棋子都作为一个独立的对象存储在内存中,将导致该围棋软件在运行时所需内存空间较大,如何降低运行代价、提高系统性能是Sunny公司开发人员需要解决的一个问题。 为了解决这个问题,Sunny公司开发人员决定使用享元模式来设计该围棋软件的棋子对象,基本结构如图所示: ...

June 27, 2020 · 2 min · jiezi

架构设计模式外观模式

外观模式是一种使用频率非常高的结构型设计模式,它通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且客户端调用非常方便。 概述在软件开发中,有时候为了完成一项较为复杂的功能,一个客户类需要和多个业务类交互,而这些需要交互的业务类经常会作为一个整体出现,由于涉及到的类比较多,导致使用时代码较为复杂。此时,特别需要一个类似服务员一样的角色,由它来负责和多个业务类进行交互,而客户类只需与该类交互。外观模式通过引入一个新的外观类(Facade)来实现该功能,外观类充当了软件系统中的“服务员”,它为多个业务类的调用提供了一个统一的入口,简化了类与类之间的交互。在外观模式中,那些需要交互的业务类被称为子系统(Subsystem)。如果没有外观类,那么每个客户类需要和多个子系统之间进行复杂的交互,系统的耦合度将很大;而引入外观类之后,客户类只需要直接与外观类交互,客户类与子系统之间原有的复杂引用关系由外观类来实现,从而降低了系统的耦合度。 外观模式中,一个子系统的外部与其内部的通信通过一个统一的外观类进行,外观类将客户类与子系统的内部复杂性分隔开,使得客户类只需要与外观角色打交道,而不需要与子系统内部的很多对象打交道。 外观模式定义如下: 外观模式:为子系统中的一组接口提供一个统一的入口。外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。外观模式是迪米特法则的一种具体实现,通过引入一个新的外观角色可以降低原有系统的复杂度,同时降低客户类与子系统的耦合度。 外观模式没有一个一般化的类图描述,下面所示的类图可以作为描述外观模式的结构图: 外观模式包含如下两个角色: Facade(外观角色):在客户端可以调用它的方法,在外观角色中可以知道相关的(一个或者多个)子系统的功能和责任;在正常情况下,它将所有从客户端发来的请求委派到相应的子系统去,传递给相应的子系统对象处理。SubSystem(子系统角色):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个单独的类,而是一个类的集合,它实现子系统的功能;每一个子系统都可以被客户端直接调用,或者被外观角色调用,它处理由外观类传过来的请求;子系统并不知道外观的存在,对于子系统而言,外观角色仅仅是另外一个客户端而已。引入外观模式之后,增加新的子系统或者移除子系统都非常方便,客户类无须进行修改(或者极少的修改),只需要在外观类中增加或移除对子系统的引用即可。从这一点来说,外观模式在一定程度上并不符合开闭原则,增加新的子系统需要对原有系统进行一定的修改,虽然这个修改工作量不大。 外观模式中所指的子系统是一个广义的概念,它可以是一个类、一个功能模块、系统的一个组成部分或者一个完整的系统。子系统类通常是一些业务类,实现了一些具体的、独立的业务功能,其典型代码如下: class SubSystemA{ public function MethodA() { //业务实现代码 }}class SubSystemB{ public function MethodB() { //业务实现代码 }}class SubSystemC{ public function MethodC() { //业务实现代码 }}在引入外观类之后,与子系统业务类之间的交互统一由外观类来完成,在外观类中通常存在如下代码: class Facade{ private $obj1; private $obj2; private $obj3; public function __construct() { $this->obj1 = new SubSystemA(); $this->obj2 = new SubSystemB(); $this->obj3 = new SubSystemC(); } public function Method() { $this->obj1->MethodA(); $this->obj2->MethodB(); $this->obj3->MethodC(); }}由于在外观类中维持了对子系统对象的引用,客户端可以通过外观类来间接调用子系统对象的业务方法,而无须与子系统对象直接交互。 案例某软件公司欲开发一个可应用于多个软件的文件加密模块,该模块可以对文件中的数据进行加密并将加密之后的数据存储在一个新文件中,具体的流程包括三个部分,分别是读取源文件、加密、保存加密之后的文件,其中,读取文件和保存文件使用流来实现,加密操作通过求模运算实现。这三个操作相对独立,为了实现代码的独立重用,让设计更符合单一职责原则,这三个操作的业务代码封装在三个不同的类中。现使用外观模式设计该文件加密模块。 ...

June 26, 2020 · 1 min · jiezi

架构设计模式装饰模式

尽管目前房价依旧很高,但还是阻止不了大家对新房的渴望和买房的热情。如果大家买的是毛坯房,无疑还有一项艰巨的任务要面对,那就是装修。对新房进行装修并没有改变房屋用于居住的本质,但它可以让房子变得更漂亮、更温馨、更实用、更能满足居家的需求。在软件设计中,我们也有一种类似新房装修的技术可以对已有对象(新房)的功能进行扩展(装修),以获得更加符合用户需求的对象,使得对象具有更加强大的功能。这种技术对应于一种被称之为装饰模式的设计模式。 概述装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为,是一种用于替代继承的技术,它通过一种无须定义子类的方式来给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系。在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类的方法,还可以增加新的方法,以扩充原有类的功能。 装饰模式定义如下: 装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。在装饰模式中,为了让系统具有更好的灵活性和可扩展性,我们通常会定义一个抽象装饰类,而将具体的装饰类作为它的子类,装饰模式结构如图所示: 在装饰模式结构图中包含如下几个角色: Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。由于具体构件类和装饰类都实现了相同的抽象构件接口,因此装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。 装饰模式的核心在于抽象装饰类的设计,其典型代码如下所示: class Decorator implements Component{ //维持一个对抽象构件对象的引用 private $component; //注入一个抽象构件类型的对象 public function __construct(Component $component) { $this->component = $component; } public function operation() { //调用原有业务方法 $this->component->operation(); }}在抽象装饰类Decorator中定义了一个Component类型的对象component,维持一个对抽象构件对象的引用,并可以通过构造方法或Setter方法将一个Component类型的对象注入进来,同时由于Decorator类实现了抽象构件Component接口,因此需要实现在其中声明的业务方法operation(),需要注意的是在Decorator中并未真正实现operation()方法,而只是调用原有component对象的operation()方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。 在Decorator的子类即具体装饰类中将继承operation()方法并根据需要进行扩展,典型的具体装饰类代码如下: class ConcreteDecorator extends Decorator{ public function __construct(Component $component) { parent::__construct($component); } public function operation() { //调用原有业务方法 parent::operation(); //调用新增业务方法 $this->addedBehavior(); } //新增业务方法 public function addedBehavior() { ... }}在具体装饰类中可以调用到抽象装饰类的operation()方法,同时可以定义新的业务方法,如addedBehavior()。由于在抽象装饰类Decorator中注入的是Component类型的对象,因此我们可以将一个具体构件对象注入其中,再通过具体装饰类来进行装饰;此外,我们还可以将一个已经装饰过的Decorator子类的对象再注入其中进行多次装饰,从而对原有功能的多次扩展。 案例Sunny软件公司基于面向对象技术开发了一套图形界面构件库VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特效显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能,如图所示:如何提高图形界面构件库性的可扩展性并降低其维护成本是Sunny公司开发人员必须面对的一个问题。 如果使用基于继承的设计方案,会存在以下几个问题: 系统扩展麻烦,在某些编程语言中无法实现。代码重复。系统庞大,类的数目非常多。这些问题的根本原因在于复用机制的不合理,在复用父类的方法后再增加新的方法来扩展功能。根据“合成复用原则”,在实现功能复用时,我们要多用关联,少用继承。因此,Sunny公司开发人员决定使用装饰模式来重构图形界面构件库的设计,其中部分类的基本结构如图所示: Component充当抽象构件类,其子类Window、TextBox、ListBox充当具体构件类,Component类的另一个子类ComponentDecorator充当抽象装饰类,ComponentDecorator的子类ScrollBarDecorator和BlackBorderDecorator充当具体装饰类。完整代码如下所示: ...

June 26, 2020 · 1 min · jiezi

架构设计模式组合模式

树形结构在软件中随处可见,例如操作系统中的目录结构、应用软件中的菜单、办公系统中的公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。 组合模式为处理树形结构提供了一种较为完美的解决方案,它描述了如何将容器和叶子进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器和叶子。 概述对于树形结构,当容器对象(如文件夹)的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象)并调用执行,牵一而动百,其中使用了递归调用的机制来对整个结构进行处理。由于容器对象和叶子对象在功能上的区别,在使用这些对象的代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下我们希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性。 组合模式定义如下: 组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。在组合模式中引入了抽象构件类Component,它是所有容器类和叶子类的公共父类,客户端针对Component进行编程。组合模式结构如图所示: 在组合模式结构图中包含如下几个角色: Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,如增加子构件、删除子构件、获取子构件等。Leaf(叶子构件):它在组合结构中表示叶子节点对象,叶子节点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。 如果不使用组合模式,客户端代码将过多地依赖于容器对象复杂的内部实现结构,容器对象内部实现结构的变化将引起客户代码的频繁变化,带来了代码维护复杂、可扩展性差等弊端。组合模式的引入将在一定程度上解决这些问题。 下面通过简单的示例代码来分析组合模式的各个角色的用途和实现。对于组合模式中的抽象构件角色,其典型代码如下所示: abstract class Component { public abstract function add(Component $c); //增加成员 public abstract function remove(Component $c); //删除成员 public abstract function getChild(int $i): Component; //获取成员 public abstract function operation(); //业务方法}一般将抽象构件类设计为接口或抽象类,将所有子类共有方法的声明和实现放在抽象构件类中。对于客户端而言,将针对抽象构件编程,而无须关心其具体子类是容器构件还是叶子构件。 如果继承抽象构件的是叶子构件,则其典型代码如下所示: class Leaf extends Component{ public function add(Component $c) { //异常处理或错误提示 } public function remove(Component $c) { //异常处理或错误提示 } public function getChild(int $i): Component { //异常处理或错误提示 } public function operation() { //叶子构件具体业务方法的实现 }}作为抽象构件类的子类,在叶子构件中需要实现在抽象构件类中声明的所有方法,包括业务方法以及管理和访问子构件的方法,但是叶子构件不能再包含子构件,因此在叶子构件中实现子构件管理和访问方法时需要提供异常处理或错误提示。当然,这无疑会给叶子构件的实现带来麻烦。 ...

June 26, 2020 · 2 min · jiezi

架构设计模式桥接模式

在正式介绍桥接模式之前,先跟大家谈谈两种常见文具的区别,它们是毛笔和蜡笔。假如我们需要大中小3种型号的画笔,能够绘制12种不同的颜色,如果使用蜡笔,需要准备3×12 = 36支,但如果使用毛笔的话,只需要提供3种型号的毛笔,外加12个颜料盒即可,涉及到的对象个数仅为 3 + 12 = 15,远小于36,却能实现与36支蜡笔同样的功能。如果增加一种新型号的画笔,并且也需要具有12种颜色,对应的蜡笔需增加12支,而毛笔只需增加一支。为什么会这样呢?通过分析我们可以得知:在蜡笔中,颜色和型号两个不同的变化维度(即两个不同的变化原因)融合在一起,无论是对颜色进行扩展还是对型号进行扩展都势必会影响另一个维度;但在毛笔中,颜色和型号实现了分离,增加新的颜色或者型号对另一方都没有任何影响。如果使用软件工程中的术语,我们可以认为在蜡笔中颜色和型号之间存在较强的耦合性,而毛笔很好地将二者解耦,使用起来非常灵活,扩展也更为方便。在软件开发中,我们也提供了一种设计模式来处理与画笔类似的具有多变化维度的情况,即将要介绍的桥接模式。 概述桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原则”。与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构,并且在抽象层建立一个抽象关联,该关联关系类似一条连接两个独立继承结构的桥,故名桥接模式。 桥接模式用一种巧妙的方式处理多层继承存在的问题,用抽象关联取代了传统的多层继承,将类之间的静态继承关系转换为动态的对象组合关系,使得系统更加灵活,并易于扩展,同时有效控制了系统中类的个数。桥接定义如下: 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。桥接模式的结构与其名称一样,存在一条连接两个继承等级结构的桥,桥接模式结构如图所示: 在桥接模式结构图中包含如下几个角色: Abstraction(抽象类):用于定义抽象类的接口,它一般是抽象类而不是接口,其中定义了一个Implementor(实现类接口)类型的对象并可以维护该对象,它与Implementor之间具有关联关系,它既可以包含抽象业务方法,也可以包含具体业务方法。RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在RefinedAbstraction中可以调用在Implementor中定义的业务方法。Implementor(实现类接口):定义实现类的接口,这个接口不一定要与Abstraction的接口完全一致,事实上这两个接口可以完全不同,一般而言,Implementor接口仅提供基本操作,而Abstraction定义的接口可能会做更多更复杂的操作。Implementor接口对这些基本操作进行了声明,而具体实现交给其子类。通过关联关系,在Abstraction中不仅拥有自己的方法,还可以调用到Implementor中定义的方法,使用关联关系来替代继承关系。ConcreteImplementor(具体实现类):具体实现Implementor接口,在不同的ConcreteImplementor中提供基本操作的不同实现,在程序运行时,ConcreteImplementor对象将替换其父类对象,提供给抽象类具体的业务操作方法。桥接模式是一个非常有用的模式,在桥接模式中体现了很多面向对象设计原则的思想,包括“单一职责原则”、“开闭原则”、“合成复用原则”、“里氏代换原则”、“依赖倒转原则”等。熟悉桥接模式有助于我们深入理解这些设计原则,也有助于我们形成正确的设计思想和培养良好的设计风格。 在使用桥接模式时,我们首先应该识别出一个类所具有的两个独立变化的维度,将它们设计为两个独立的继承等级结构,为两个维度都提供抽象层,并建立抽象耦合。通常情况下,我们将具有两个独立变化维度的类的一些普通业务方法和与之关系最密切的维度设计为“抽象类”层次结构(抽象部分),而将另一个维度设计为“实现类”层次结构(实现部分)。例如:对于毛笔而言,由于型号是其固有的维度,因此可以设计一个抽象的毛笔类,在该类中声明并部分实现毛笔的业务方法,而将各种型号的毛笔作为其子类;颜色是毛笔的另一个维度,由于它与毛笔之间存在一种“设置”的关系,因此我们可以提供一个抽象的颜色接口,而将具体的颜色作为实现该接口的子类。在此,型号可认为是毛笔的抽象部分,而颜色是毛笔的实现部分,结构示意图如图所示:

June 26, 2020 · 1 min · jiezi

架构设计模式适配器模式

在软件开发中,有时存在结构之间不兼容的情况,我们也可以像引入一个电源适配器一样引入一个称之为适配器的角色来协调这些存在不兼容的结构,这种设计方案即为适配器模式。 概述与电源适配器相似,在适配器模式中引入了一个被称为适配器(Adapter)的包装类,而它所包装的对象称为适配者(Adaptee),即被适配的类。适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。也就是说:当客户类调用适配器的方法时,在适配器类的内部将调用适配者类的方法,而这个过程对客户类是透明的,客户类并不直接访问适配者类。因此,适配器让那些由于接口不兼容而不能交互的类可以一起工作。 适配器模式可以将一个类的接口和另一个类的接口匹配起来,而无须修改原来的适配者接口和抽象目标类接口。适配器模式定义如下: 适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。注:在适配器模式定义中所提及的接口是指广义的接口,它可以表示一个方法或者方法的集合。 根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。在实际开发中,对象适配器的使用频率更高,对象适配器模式结构如图所示: 在对象适配器模式结构图中包含如下几个角色: Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承或实现Target并关联一个Adaptee对象使二者产生联系。Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。在对象适配器中,客户端需要调用request()方法,而适配者类Adaptee没有该方法,但是它所提供的specificRequest()方法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装类Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户端与适配者衔接起来,在适配器的request()方法中调用适配者的specificRequest()方法。因为适配器类与适配者类是关联关系(也可称之为委派关系),所以这种适配器模式称为对象适配器模式。典型的对象适配器代码如下所示: <?phpclass Adapter extends Target{ //维持一个对适配者对象的引用 private $adaptee; public function __construct($adaptee) { $this->adaptee = $adaptee; } public function request() { //转发调用 $this->adaptee->specificRequest(); }}案例Sunny软件公司在很久以前曾开发了一个算法库,里面包含了一些常用的算法,例如排序算法和查找算法,在进行各类软件开发时经常需要重用该算法库中的算法。在为某学校开发教务管理系统时,开发人员发现需要对学生成绩进行排序和查找,该系统的设计人员已经开发了一个成绩操作接口ScoreOperation,在该接口中声明了排序方法sort()和查找方法search()。为了提高排序和查找的效率,开发人员决定重用算法库中的快速排序算法类QuickSort和二分查找算法类BinarySearch。由于某些原因,现在Sunny公司开发人员已经找不到该算法库的源代码,无法直接通过复制和粘贴操作来重用其中的代码;部分开发人员已经针对ScoreOperation接口编程,如果再要求对该接口进行修改或要求大家直接使用QuickSort类和BinarySearch类将导致大量代码需要修改。Sunny软件公司开发人员面对这个没有源码的算法库,遇到一个幸福而又烦恼的问题:如何在既不修改现有接口又不需要任何算法库代码的基础上能够实现算法库的重用?Sunny软件公司开发人员决定使用适配器模式来重用算法库中的算法,其基本结构如图所示: ScoreOperation接口充当抽象目标,QuickSort和BinarySearch类充当适配者,OperationAdapter充当适配器。完整代码如下所示: <?php//抽象成绩操作类:目标接口interface ScoreOperation{ //成绩排序 public function sort(array $array): array; //成绩查找 public function search(array $array, int $key): int;}//快速排序类:适配者class QuickSort{ public function _quickSort(array $array): array { $this->sort($array, 0, count($array) - 1); return $array; } public function sort(array $array, int $p, int $r) { $q = 0; if ($p < $r) { $q = $this->partition($array, $p, $r); $this->sort($array, $p, $q - 1); $this->sort($array, $q + 1, $r); } } public function partition(array $a, int $p, int $r): int { $x = $a[$r]; $j = $p - 1; for ($i = $p; $i <= $r - 1; $i++) { if ($a[$i] <= $x) { $j++; $this->swap($a, $j, $i); } } $this->swap($a, $j + 1, $r); return $j + 1; } public function swap(array $a, int $i, int $j) { $t = $a[$i]; $a[$i] = $a[$j]; $a[$j] = $t; }}//二分查找类:适配者class BinarySearch{ public function _binarySearch(array $array, int $key): int { $low = 0; $high = count($array) - 1; while ($low <= $high) { $mid = ($low + $high) / 2; $midVal = $array[$mid]; if ($midVal < $key) { $low = $mid + 1; } elseif ($midVal > $key) { $high = $mid - 1; } else { return 1; } } return -1; }}//操作适配器:适配器class OperationAdapter implements ScoreOperation{ //定义适配者QuickSort对象 private $sortObj; //定义适配者BinarySearch对象 private $searchObj; public function __construct() { $this->sortObj = new QuickSort(); $this->searchObj = new BinarySearch(); } public function sort(array $array): array { return $this->sortObj->_quickSort($array); } public function search(array $array, int $key): int { return $this->searchObj->_binarySearch($array, $key); }}为了让系统具备良好的灵活性和可扩展性,我们引入了工具类ConfigUtil和配置文件,将适配器类的类名存储在配置文件中。如果需要使用其他排序算法类和查找算法类,可以增加一个新的适配器类,使用新的适配器来适配新的算法,原有代码无须修改。通过引入配置文件和反射机制,可以在不修改客户端代码的情况下使用新的适配器,无须修改源代码,符合“开闭原则”。 ...

June 25, 2020 · 2 min · jiezi

架构设计模式建造者模式

没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。 概述建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。它关注如何一步一步创建一个的复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。 建造者模式定义如下: 建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式结构如图所示: 在建造者模式结构图中包含如下几个角色: Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也提供一个方法返回创建好的复杂产品对象。Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。在建造者模式的定义中提到了复杂对象,那么什么是复杂对象?简单来说,复杂对象是指那些包含多个成员属性的对象,这些成员属性也称为部件或零件,如汽车包括方向盘、发动机、轮胎等部件,电子邮件包括发件人、收件人、主题、内容、附件等部件,一个典型的复杂对象类代码示例如下: <?phpclass Product{ //定义部件,部件可以是任意类型,包括值类型和引用类型 private $partA; private $partB; private $partC;}在抽象建造者类中定义了产品的创建方法和返回方法,其典型代码如下: <?phpabstract class Builder{ //产品对象 private $product; public abstract function buildPartA(); public abstract function buildPartB(); public abstract function buildPartC(); //创建产品对象 public abstract function createProduct(); //返回产品对象 public function getResult(): Product { return $this->product; }}在抽象类Builder中声明了一系列抽象的buildPartX()方法用于创建复杂产品的各个部件,具体建造过程在ConcreteBuilder中实现,此外还提供了工厂方法getResult(),用于返回一个建造好的完整产品。 在ConcreteBuilder中实现了buildPartX()方法,不同的具体建造者在实现buildPartX()方法时将有所区别,而这些对于客户端来说都无须关心,客户端只需知道具体建造者类型即可。 在建造者模式的结构中还引入了一个指挥者类Director,该类主要有两个作用:一方面它隔离了客户与创建过程;另一方面它控制产品的创建过程,包括某个buildPartX()方法是否被调用以及多个buildPartX()方法调用的先后次序等。指挥者针对抽象建造者编程,客户端只需要知道具体建造者的类型,即可通过指挥者类调用建造者的相关方法,返回一个完整的产品对象。在实际生活中也存在类似指挥者一样的角色,如一个客户去购买电脑,电脑销售人员相当于指挥者,只要客户确定电脑的类型,电脑销售人员可以通知电脑组装人员给客户组装一台电脑。指挥者类的代码示例如下: <?phpclass Director{ private $builder; public function __construct(Builder $builder) { $this->builder = $builder; } public function setBuilder(Builder $builder) { $this->builder = $builder; } //产品构建与组装方法 public function build(): Product { $this->builder->createProduct(); $this->builder->buildPartA(); $this->builder->buildPartB(); $this->builder->buildPartC(); return $this->builder->getResult(); }}在指挥者类中可以注入一个抽象建造者类型的对象,其核心在于提供了一个建造方法build(),在该方法中调用了builder对象的构造部件的方法,最后返回一个产品对象。 ...

June 25, 2020 · 2 min · jiezi

架构设计模式原型模式

在设计模式中存在一个模式,可以通过一个原型对象克隆出多个一模一样的对象,该模式称之为原型模式。 概述原型模式的定义如下: 原型模式(Prototype  Pattern):使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。原型模式的工作原理很简单:将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。由于在软件系统中我们经常会遇到需要创建多个相同或者相似对象的情况,因此原型模式在真实开发中的使用频率还是非常高的。原型模式是一种“另类”的创建型模式,创建克隆对象的工厂就是原型类自身,工厂方法由克隆方法来实现。 需要注意的是通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,通常对克隆所产生的对象进行修改对原型对象不会造成任何影响,每一个克隆对象都是相互独立的。通过不同的方式修改可以得到一系列相似但不完全相同的对象。 原型模式的结构如图所示: 在原型模式结构图中包含如下几个角色: Prototype(抽象原型类):它是声明克隆方法的接口,是所有具体原型类的公共父类,可以是抽象类也可以是接口,甚至还可以是具体实现类。ConcretePrototype(具体原型类):它实现在抽象原型类中声明的克隆方法,在克隆方法中返回自己的一个克隆对象。Client(客户类):让一个原型对象克隆自身从而创建一个新的对象,在客户类中只需要直接实例化或通过工厂方法等方式创建一个原型对象,再通过调用该对象的克隆方法即可得到多个相同的对象。由于客户类针对抽象原型类Prototype编程,因此用户可以根据需要选择具体原型类,系统具有较好的可扩展性,增加或更换具体原型类都很方便。注:在PHP语言中,可以使用clone关键字克隆一个对象,此处不再举例,只需要注意在具体原型类中实现特定的__clone方法即可。 总结原型模式作为一种快速创建大量相同或相似对象的方式,在软件开发中应用较为广泛,很多软件提供的复制(Ctrl + C)和粘贴(Ctrl + V)操作就是原型模式的典型应用。 主要优点当创建新的对象实例较为复杂时,使用原型模式可以简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率。扩展性较好,由于在原型模式中提供了抽象原型类,在客户端可以针对抽象原型类进行编程,而将具体原型类写在配置文件中,增加或减少产品类对原有系统都没有任何影响。原型模式提供了简化的创建结构,工厂方法模式常常需要有一个与产品类等级结构相同的工厂等级结构,而原型模式就不需要这样,原型模式中产品的复制是通过封装在原型类中的克隆方法实现的,无须专门的工厂类来创建产品。可以使用深克隆的方式保存对象的状态,使用原型模式将对象复制一份并将其状态保存起来,以便在需要的时候使用(如恢复到某一历史状态),可辅助实现撤销操作。主要缺点需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的内部,当对已有的类进行改造时,需要修改源代码,违背了“开闭原则”。在实现深克隆时需要编写较为复杂的代码,而且当对象之间存在多重的嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来可能会比较麻烦。适用场景创建新对象成本较大(如初始化需要占用较长的时间,占用太多的CPU资源或网络资源),新的对象可以通过原型模式对已有对象进行复制来获得,如果是相似对象,则可以对其成员变量稍作修改。如果系统要保存对象的状态,而对象的状态变化很小,或者对象本身占用内存较少时,可以使用原型模式配合备忘录模式来实现。需要避免使用分层次的工厂类来创建分层次的对象,并且类的实例对象只有一个或很少的几个组合状态,通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便。

June 25, 2020 · 1 min · jiezi

架构设计的五视图

June 23, 2020 · 0 min · jiezi

架构设计-高并发流量削峰共享资源加锁机制

本文源码:GitHub·点这里 || GitEE·点这里 一、高并发简介在互联网的业务架构中,高并发是最难处理的业务之一,常见的使用场景:秒杀,抢购,订票系统;高并发的流程中需要处理的复杂问题非常多,主要涉及下面几个方面: 流量管理,逐级承接削峰;网关控制,路由请求,接口熔断;并发控制机制,资源加锁;分布式架构,隔离服务和数据库;高并发业务核心还是流量控制,控制流量下沉速度,或者控制承接流量的容器大小,多余的直接溢出,这是相对复杂的流程。其次就是多线程并发下访问共享资源,该流程需要加锁机制,避免数据写出现错乱情况。 二、秒杀场景1、预抢购业务活动未正式开始,先进行活动预约,先把一部分流量收集和控制起来,在真正秒杀的时间点,很多数据可能都已经预处理好了,可以很大程度上削减系统的压力。有了一定预约流量还可以提前对库存系统做好准备,一举两得。 场景:活动预约,定金预约,高铁抢票预购。 2、分批抢购分批抢购和抢购的场景实现的机制是一致的,只是在流量上缓解了很多压力,秒杀10W件库存和秒杀100件库存系统的抗压不是一个级别。如果秒杀10W件库存,系统至少承担多于10W几倍的流量冲击,秒杀100件库存,体系可能承担几百或者上千的流量就结束了。下面流量削峰会详解这里的策略机制。 场景:分时段多场次抢购,高铁票分批放出。 3、实时秒杀最有难度的场景就是准点实时的秒杀活动,假如10点整准时抢1W件商品,在这个时间点前后会涌入高并发的流量,刷新页面,或者请求抢购的接口,这样的场景处理起来是最复杂的。 首先系统要承接住流量的涌入;页面的不断刷新要实时加载;高并发请求的流量控制加锁等;服务隔离和数据库设计的系统保护;场景:618准点抢购,双11准点秒杀,电商促销秒杀。 三、流量削峰 1、Nginx代理Nginx是一个高性能的HTTP和反向代理web服务器,经常用在集群服务中做统一代理层和负载均衡策略,也可以作为一层流量控制层,提供两种限流方式,一是控制速率,二是控制并发连接数。 基于漏桶算法,提供限制请求处理速率能力;限制IP的访问频率,流量突然增大时,超出的请求将被拒绝;还可以限制并发连接数。 高并发的秒杀场景下,经过Nginx层的各种限制策略,可以控制流量在一个相对稳定的状态。 2、CDN节点CDN静态文件的代理节点,秒杀场景的服务有这样一个操作特点,活动倒计时开始之前,大量的用户会不断的刷新页面,这时候静态页面可以交给CDN层面代理,分担数据服务接口的压力。 CDN层面也可以做一层限流,在页面内置一层策略,假设有10W用户点击抢购,可以只放行1W的流量,其他的直接提示活动结束即可,这也是常用的手段之一。 话外之意:平时参与的抢购活动,可能你的请求根本没有到达数据接口层面,就极速响应商品已抢完,自行意会吧。 3、网关控制网关层面处理服务接口路由,一些校验之外,最主要的是可以集成一些策略进入网关,比如经过上述层层的流量控制之后,请求已经接近核心的数据接口,这时在网关层面内置一些策略控制:如果活动是想激活老用户,网关层面快速判断用户属性,老用户会放行请求;如果活动的目的是拉新,则放行更多的新用户。 经过这些层面的控制,剩下的流量已经不多了,后续才真正开始执行抢购的数据操作。 话外之意:如果有10W人参加抢购活动,真正下沉到底层的抢购流量可能就1W,甚至更少,在分散到集群服务中处理。 4、并发熔断在分布式服务的接口中,还有最精细的一层控制,对于一个接口在单位之间内控制请求处理的数量,这个基于接口的响应时间综合考虑,响应越快,单位时间内的并发量就越高,这里逻辑不难理解。 言外之意:流量经过层层控制,数据接口层面分担的压力已经不大,这时候就是面对秒杀业务中的加锁问题了。 四、分布式加锁1、悲观锁机制描述 所有请求的线程必须在获取锁之后,才能执行数据库操作,并且基于序列化的模式,没有获取锁的线程处于等待状态,并且设定重试机制,在单位时间后再次尝试获取锁,或者直接返回。 过程图解 Redis基础命令 SETNX:加锁的思路是,如果key不存在,将key设置为value如果key已存在,则 SETNX 不做任何动作。并且可以给key设置过期时间,过期后其他线程可以继续尝试锁获取机制。 借助Redis的该命令模拟锁的获取动作。 代码实现 这里基于Redis实现的锁获取和释放机制。 import org.springframework.stereotype.Component;import redis.clients.jedis.Jedis;import javax.annotation.Resource;@Componentpublic class RedisLock { @Resource private Jedis jedis ; /** * 获取锁 */ public boolean getLock (String key,String value,long expire){ try { String result = jedis.set( key, value, "nx", "ex", expire); return result != null; } catch (Exception e){ e.printStackTrace(); }finally { if (jedis != null) jedis.close(); } return false ; } /** * 释放锁 */ public boolean unLock (String key){ try { Long result = jedis.del(key); return result > 0 ; } catch (Exception e){ e.printStackTrace(); }finally { if (jedis != null) jedis.close(); } return false ; }}这里基于Jedis的API实现,这里提供一份配置文件。 ...

June 22, 2020 · 2 min · jiezi

架构设计模式单例模式

对于一个软件系统的某些类而言,我们无须创建多个实例。举个大家都熟知的例子——Windows任务管理器,通常情况下,无论我们启动任务管理多少次,Windows系统始终只能弹出一个任务管理器窗口,也就是说在一个Windows系统中,任务管理器存在唯一性。 回到实际开发中,我们也经常遇到类似的情况,为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,这就是单例模式的动机所在。 概述单例模式定义如下: 单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。 单例模式是结构最简单的设计模式一,在它的核心结构中只包含一个被称为单例类的特殊类。单例模式结构如图所示: 单例模式结构图中只包含一个单例角色: Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。案例Sunny软件公司承接了一个服务器负载均衡(Load Balance)软件的开发工作,该软件运行在一台负载均衡服务器上,可以将并发访问和数据流量分发到服务器集群中的多台设备上进行并发处理,提高系统的整体处理能力,缩短响应时间。由于集群中的服务器需要动态删减,且客户端请求需要统一分发,因此需要确保负载均衡器的唯一性,只能有一个负载均衡器来负责服务器的管理和请求的分发,否则将会带来服务器状态的不一致以及请求分配冲突等问题。如何确保负载均衡器的唯一性是该软件成功的关键。Sunny公司开发人员通过分析和权衡,决定使用单例模式来设计该负载均衡器,结构图如下: 将负载均衡器LoadBalancer设计为单例类,其中包含一个存储服务器信息的集合serverList,每次在serverList中随机选择一台服务器来响应客户端的请求,实现代码如下所示: <?phpfinal class LoadBalancer{ //私有静态成员变量,存储唯一实例 private static $instance = null; //服务器集合 private $serverList = []; //私有构造函数 private function __construct() { } //公有静态成员方法,返回唯一实例 public static function getLoadBalancer() { if (static::$instance == null) { static::$instance = new static(); } return static::$instance; } //增加服务器 public function addServer($server) { $this->serverList[] = $server; } //删除服务器 public function removeServer($server) { if ($key = array_search($server, $this->serverList)) { unset($this->serverList[$key]); } } //随机获取服务器 public function getServer(): string { $index = mt_rand(0, count($this->serverList)); return (string)$this->serverList[$index]; } //禁止克隆 private function __clone() { } //禁止反序列化 private function __wakeup() { }}总结单例模式作为一种目标明确、结构简单、理解容易的设计模式,在软件开发中使用频率相当高,在很多应用软件和框架中都得以广泛应用。 ...

June 21, 2020 · 1 min · jiezi

架构设计模式抽象工厂模式

工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题,但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个“产品族”,由同一个工厂来统一生产,这就是我们本文将要学习的抽象工厂模式的基本思想。 产品等级结构与产品族在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法具有唯一性,一般情况下,一个具体工厂中只有一个或者一组重载的工厂方法。但是有时候我们希望一个工厂可以提供多个产品对象,而不是单一的产品对象,如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器,而不是只生产某一种电器。为了更好地理解抽象工厂模式,我们先引入两个概念: 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。产品等级结构与产品族示意图如图所示: 在图中,不同颜色的多个正方形、圆形和椭圆形分别构成了三个不同的产品等级结构,而相同颜色的正方形、圆形和椭圆形构成了一个产品族,每一个形状对象都位于某个产品族,并属于某个产品等级结构。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。 当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。抽象工厂模式示意图如下: 每一个具体工厂可以生产属于一个产品族的所有产品,例如生产颜色相同的正方形、圆形和椭圆形,所生产的产品又位于不同的产品等级结构中。如果使用工厂方法模式,图4所示结构需要提供15个具体工厂,而使用抽象工厂模式只需要提供5个具体工厂,极大减少了系统中类的个数。 概述抽象工厂模式为创建一组对象提供了一种解决方案。与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。抽象工厂模式定义如下: 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族,抽象工厂模式结构如图所示:

June 21, 2020 · 1 min · jiezi

架构设计模式工厂方法模式

简单工厂模式虽然简单,但存在一个很严重的问题。当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背“开闭原则”,如何实现增加新产品而不影响已有代码?工厂方法模式应运而生,本文将介绍第二种工厂模式——工厂方法模式。 概述在简单工厂模式中只提供一个工厂类,该工厂类处于对产品类进行实例化的中心位置,它需要知道每一个产品对象的创建细节,并决定何时实例化哪一个产品类。简单工厂模式最大的缺点是当有新产品要加入到系统中时,必须修改工厂类,需要在其中加入必要的业务逻辑,这违背了“开闭原则”。此外,在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重,业务逻辑较为复杂,具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性,而工厂方法模式则可以很好地解决这一问题。 在工厂方法模式中,我们不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构。工厂方法模式定义如下: 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。 工厂方法模式提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象。工厂方法模式结构如图所示: 在工厂方法模式结构图中包含如下几个角色: Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类。ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应。Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口。ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例。与简单工厂模式相比,工厂方法模式最重要的区别是引入了抽象工厂角色,抽象工厂可以是接口,也可以是抽象类或者具体类,其典型代码如下所示: interface Factory { public function factoryMethod();}在抽象工厂中声明了工厂方法但并未实现工厂方法,具体产品对象的创建由其子类负责,客户端针对抽象工厂编程,可在运行时再指定具体工厂类,具体工厂类实现了工厂方法,不同的具体工厂可以创建不同的具体产品,其典型代码如下所示: class ConcreteFactory implements Factory{ public function factoryMethod(): ConcreteProduct { return new ConcreteProduct(); }}在实际使用时,具体工厂类在实现工厂方法时除了创建具体产品对象之外,还可以负责产品对象的初始化工作以及一些资源和环境配置工作,例如连接数据库、创建文件等。 在客户端代码中,只需关心工厂类即可,不同的具体工厂可以创建不同的产品,典型的客户端类代码片段如下所示: //可通过配置文件实现$factory = new ConcreteFactory();$product = $factory->factoryMethod();可以通过配置文件来存储具体工厂类ConcreteFactory的类名,更换新的具体工厂时无须修改源代码,系统扩展更为方便。 案例Sunny软件公司欲开发一个系统运行日志记录器(Logger),该记录器可以通过多种途径保存系统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,Sunny公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。如何封装记录器的初始化过程并保证多种记录器切换的灵活性是Sunny公司开发人员面临的一个难题。Sunny公司开发人员决定使用工厂方法模式来设计日志记录器,其基本结构如图所示: Logger接口充当抽象产品,其子类FileLogger和DatabaseLogger充当具体产品,LoggerFactory接口充当抽象工厂,其子类FileLoggerFactory和DatabaseLoggerFactory充当具体工厂。完整代码如下所示: <?php//日志记录器接口:抽象产品interface Logger{ public function writeLog();}//数据库日志记录器:具体产品class DatabaseLogger implements Logger{ public function writeLog() { echo '数据库日志记录'; }}//文件日志记录器:具体产品class FileLogger implements Logger{ public function writeLog() { echo '文件日志记录'; }}//日志记录器工厂接口:抽象工厂interface LoggerFactory{ public function createLogger(): Logger;}//数据库日志记录器工厂类:具体工厂class DatabaseLoggerFactory implements LoggerFactory{ public function createLogger(): Logger { //连接数据库,代码省略 //创建数据库日志记录器对象 $logger = new DatabaseLogger(); //初始化数据库日志记录器,代码省略 return $logger; }}//文件日志记录器工厂类:具体工厂class FileLoggerFactory implements LoggerFactory{ public function createLogger(): Logger { //创建文件日志记录器对象 $logger = new FileLogger(); //创建文件,代码省略 return $logger; }}class Client{ public function test() { //可引入配置文件实现 $factory = new FileLoggerFactory(); $logger = $factory->createLogger(); $logger->writeLog(); }}改进为了让系统具有更好的灵活性和可扩展性,Sunny公司开发人员决定对日志记录器客户端代码进行重构,使得可以在不修改任何客户端代码的基础上更换或增加新的日志记录方式。 ...

June 21, 2020 · 1 min · jiezi

今日头条在消息服务平台和容灾体系建设方面的实践与思考

本篇文章整理自今日头条的沈辉在 RocketMQ 开发者沙龙中的演讲,主要和大家分享一下,RocketMQ 在微服务架构下的实践和容灾体系建设。沈辉是今日头条的架构师,主要负责 RocketMQ 在头条的落地以及架构设计,参与消息系统的时间大概一年左右。 以下是本次分享的议题: 头条的业务背景为什么选择 RocketMQRocketMQ 在头条的落地实践头条的容灾系统建设业务背景今日头条的服务大量使用微服务,容器数目巨大,业务线繁多, Topic 的数量也非常多。另外,使用的语言比较繁杂,包括 Python,Go, C++, Java, JS 等,对于基础组件的接入,维护 SDK 的成本很高。 引入 RocketMQ 之前采用的消息队列是 NSQ 和 kafka , NSQ 是纯内存的消息队列,缺少消息的持久性,不落盘直接写到 Golang 的 channel 里,在并发量高的时候 CPU 利用率非常高,其优点是可以无限水平扩展,另外,由于不需要保证消息的有序性,集群单点故障对可用性基本没有影响,所以具有非常高的可用性。我们也用到了 Kafka ,它的主要问题是在业务线和 Topic 繁多,其写入性能会出现明显的下降,拆分集群又会增加额外的运维负担。并且在高负载下,其故障恢复时间比较长。所以,针对当时的状况和业务场景的需求,我们进行了一些调研,期望选择一款新的 MQ 来比较好的解决目前的困境,最终选择了 RocketMQ 。 为什么选择 RocketMQ这是一个经过阿里巴巴多年双11验证过的、可以支持亿级并发的开源消息队列,是值得信任的。其次关注一下他的特性。 RocketMQ 具有高可靠性、数据持久性,和 Kafka 一样是先写 PageCache ,再落盘,并且数据有多副本;并且它的存储模型是所有的 Topic 都写到同一个 Commitlog 里,是一个append only 操作,在海量 Topic 下也能将磁盘的性能发挥到极致,并且保持稳定的写入时延。然后就是他的性能,经过我们的 benchmark ,采用一主两从的结构,单机 qps 可以达到 14w , latency 保持在 2ms 以内。对比之前的 NSQ 和 Kafka , Kafka 的吞吐非常高,但是在多 Topic 下, Kafka 的 PCT99 毛刺会非常多,而且平均值非常长,不适合在线业务场景。另外 NSQ 的消息首先经过 Golang 的 channel ,这是非常消耗 CPU 的,在单机 5~6w 的时候 CPU 利用率达到 50~60% ,高负载下的写延迟不稳定。另外 RocketMQ 对在线业务特性支持是非常丰富的,支持 retry , 支持并发消费,死信队列,延时消息,基于时间戳的消息回溯,另外消息体支持消息头,这个是非常有用的,可以直接支持实现消息链路追踪,不然就需要把追踪信息写到 message 的 body 里;还支持事务的消息。综合以上特性最终选择了 RocketMQ 。 ...

November 5, 2019 · 3 min · jiezi

微服务架构案例04中间件集成公共服务封装

本文源码:GitHub·点这里 || GitEE·点这里 更新进度(共6节): 01:项目技术选型简介,架构图解说明02:业务架构设计,系统分层管理03:数据库选型,业务数据设计规划04:中间件集成,公共服务管理一、中间件简介中间件是基础软件的一类, 属于复用性极高的软件。处于操作系统软件与应用程序的之间。是一种独立的系统软件,也可以是公共的服务程序,分布式架构系统借助中间件,可以在不同的技术之间共享资源,或者不同的服务直接传递信息。中间件位操作系统之上,管理计算机资源和网络通讯。是连接两个独立应用程序或独立系统的软件,例如:消息队列中间件,在两个服务之间进行异步的消息传递;数据缓存中间件,缓存整合系统的热点数据,提高程序的响应速度;Nginx中间件,提供负载均衡,服务代理,等功能;二、公共服务简介公共服务,顾名思义就是系统内通用的服务,例如用户身份验证,消息发送,监控预警,网关服务等。 该案例的中间件和公共服务,都是基于Feign接口统一的方式提供服务。 三、中间件集成1、消息中间件RocketMq简介RocketMq 是一款分布式、队列模型的消息中间件,有两个核心角色:消息生产者和消息消费者。作为高并发系统的核心组件之一,能够帮助业务系统解构提高系统稳定性。 应用流程消息生产者@Componentpublic class MsgSendService { @Resource private ProducerConfig producerConfig ; public void sendMsg (MsgWrap msgWrap) { producerConfig.sendMsg(msgWrap.getGroup(),msgWrap.getTopic(), msgWrap.getTag(),msgWrap.getContent()); }}消息消费者@Component@Consumer(group = MsgRoute.husky_group_1, topic = MsgRoute.husky_topic_1 , tag = MsgRoute.husky_tag_1)public class UserSearchListener implements MsgReadService { @Resource private BookEsAnalyFeign bookEsAnalyFeign ; @Override public void readMsg(String msg) throws Exception { LOGGER.info("【用户搜索消息监听 Msg】:{}",msg) ; // 转发请求数据分析服务 bookEsAnalyFeign.sendBookEsMsg(msg); }}提供Feign接口@RestControllerpublic class UserSearchController implements UserSearchFeign { @Resource private SendMsgService sendMsgService ; @Override public void sendBookSearch(String msgContent) { MsgWrap msgWrap = new MsgWrap() ; msgWrap.setContent(msgContent); msgWrap.setGroup(MsgRoute.husky_group_1); msgWrap.setTopic(MsgRoute.husky_topic_1); msgWrap.setTag(MsgRoute.husky_tag_1); sendMsgService.sendMsg(msgWrap); }}2、缓存中间件Redis简介Redis 是一个基于内存的高性能key-value数据库。对高并发系统提供各种场景的支撑:热点数据缓存,计数器,流量削峰等。 ...

November 5, 2019 · 3 min · jiezi

安居客-Android-APP-走向平台化

首发于微信公众号:BaronTalk安居客 Android App 距离上次的模块化/组件化重构已经两年多了,重构之后很好的支撑了两年多以来的业务发展。但这个世界总是在向前走的,没有任何一种架构能够一劳永逸的解决所有问题,外部环境的不断变化相应的也要求项目架构做出改变,以此来应对环境变化所带来的挑战。 本文分享的就是我们安居客 App 团队这次向平台化转型的背景、转型过程中所面临的问题、挑战、我们的解决方案以及我个人在这个过程中的收获和感悟。 一. 背景自 18 年以来的市场环境大家都知道,各大公司都在缩减开支、提升组织效率,希望用更少的投入带来更多的产出,以此来应对经济下行带的不确定性。在这个大背景下,集团在 18 年底做出了一系列人效提升、业务整合的动作。 拿房产业务举例:58 App 里的房产业务之前是由北京的房产团队开发的,而整个安居客 App 是由我所在的上海安居客团队开发的。在这次调整之后,北京的房产团队作为一条垂直业务线来负责 58 App 和安居客 App 中的租房业务的开发,安居客团队则继续负责整个安居客 App(包含新房、二手房、内容、IM 等业务)的开发,同时还要开发 58 App 中二手房、新房、房产大内容等业务。 这样一次调整给我们带来了三大挑战: 在人力不变,工作量翻倍的情况下,我们要如何保证业务的迭代速度不受影响?由以往的「单兵作战」变成了跨团队跨地域协作开发,我们要如何作为一个平台方来和业务方协作开发?对于 58 App 而言我们是业务方,对于北京房产团队而言我们是平台方,我们要如何同时处理好双重角色?面对这些挑战我们需要转变开发思维、改进项目架构。 一次项目重构和架构升级,不只是要解决当下的问题,更要为未来一到两年的业务发展提供支持。为了解决这一系列的问题,我们联合 58 无线团队、58 房产团队、前端、后端多个团队的同学一起发起了「木星计划」,也开启了我们的平台化转型之路。 二. 问题、挑战及解决方案当公司的业务调整政策下来以后,团队面临的最急迫的一个选择是继续在 58 App 上维护老的房产代码,迭代新功能;还是将安居客现有业务搬迁到 58 App 实现一套代码在两个 App 里运行呢? 前者我们需要分一半的人力去开发 58 App,这必然导致团队的需求消化量减半,业务迭代速度受影响。好处是暂时不用做任何技术上的改造。后者需要我们协调 58 无线、58 房产、前后端等多个团队一起对 App 做一次「大手术」,同时还需要说服产品团队容忍改造期间业务迭代速度的放缓。好处是能够一次性将安居客上的房产业务搬迁到 58 App 上,后续我们只需针对房产业务做一次开发就能跑在两个 App 上,用一份人力做了两份的活,开发效率翻倍。为长远计,我们最终选择了后者。可是要做到一套代码双端运行并不容易,58 App 和安居客 App 隶属于北京、上海两个不同的团队开发,大家底层库不一样,技术方案不一样,开发模式也不一样,要达到我们的目的必然要费一番功夫。接下来我从整体到局部逐步介绍我们在平台化演进过程中的设计思路、遇到的问题和解决方案 ...

October 22, 2019 · 3 min · jiezi

云原生时代什么是蚂蚁金服推荐的金融架构

蚂蚁金服在过去十五年重塑支付改变生活,为全球超过十二亿人提供服务,这些背后离不开技术的支撑。在 2019 杭州云栖大会上,蚂蚁金服将十五年来的技术沉淀,以及面向未来的金融技术创新和参会者分享。我们将其中的优秀演讲整理成文并将陆续发布在“金融级分布式架构”公众号上,本文为其中一篇。本文作者:杨延昭(杨冰),蚂蚁金服智能科技产品技术部总监 互联网技术发展日新月异,我们正在进入云原生时代,这个过程中金融行业要如何拥抱云原生?在近两年蚂蚁金服将云原生在金融领域落地,沉淀下一些实践经验,接下来我想分享在蚂蚁的演进过程当中,我们心中的云原生是什么样的,在金融领域落地的时候遇到什么问题,以及我们是怎么解决的。 经过多年云计算的蓬勃发展,上云已经不是太大问题,接下来的问题是怎么把云用好,用得更高效。RightScale 2019年最新数据显示,现在公有云规模占22%,只使用私有云的客户占3%,更多客户通过混合的模式去使用云,通过混合云取得数据隐私、安全与效率、弹性的平衡。 再看全球整个 IT 行业,公有云的比例只占整个基础 IT 市场的10%,市场空间仍然很大,IT 市场中剩下很多都是传统企业客户。为什么传统行业无法很好地利用公有云,一个重要的原因是因为他们的 IT 系统经过很长时间建设,很多都有自己的机房。另外有些则业务比较稳定,对上公有云没有很强的需求。它们通常会发展混合云策略,把一些核心业务留在私有云,而把一些边缘业务或创新业务放在公有云上。 这些特点在金融行业也非常明显,除此之外金融行业还有两个特征: 业务形态走向开放和互联网化:随着互联网和数字化经济的发展,金融机构需要进行数字化转型,以及业务敏捷化、服务场景化,以应对新的商业模式带来的冲击;监管合规的诉求:金融行业的业务特点决定了必须是强隔离,强监管的,所以公有云上的资源共享模式在监管方面会有比较大的挑战。因此,混合云战略对金融机构更为适用。这一结论也得到研究支持,根据调研机构 Nutanix 的报告,全球金融业在混合云应用方面的发展速度超过其它行业,目前部署普及率达到21%,而全球平均水平为18.5%。 那么,什么样的混合云是适合金融机构的呢?以蚂蚁的演进历程为例。 蚂蚁在第四代架构的时候演变成为云平台架构,而且为了应对互联网业务形态下突发性业务对资源的弹性需求,蚂蚁也在同一阶段将架构直接进化成弹性混合云架构。现在蚂蚁已经演进到第五代云原生架构。蚂蚁又是如何在云原生的架构下,把混合云变成金融级的混合云,我想会对各位有些启发。在这个发展过程中,有一条主线,是不同阶段蚂蚁对研发的标准和要求,包括:自主、成本、安全、稳定、海量、敏捷,这也是在在线金融的时代,我们对云原生架构的要求。 从分布式到云原生 建立金融级交易支付系统 建立金融级的在线交易系统,第一步是要实现金融级分布式的架构,蚂蚁在这方面的代表技术是 SOFAStack 和 OceanBase,目前都已对外商业化,并有丰富的案例。SOFAStack 代表的是,在整个应用层或者无状态服务这个层面上,如何去做可伸缩、可扩展的一套架构。OceanBase 代表的是以数据库为代表的存储或者是有状态服务层面,如何在架构上面去进行分布式。它们拥有四个特性: 高可用,99.99%+的可用性保证,确保系统始终连续运行不中断;一致性,在任何异常情况下数据最终一致,确保资金安全;可扩展,支持应用级、数据库级、机房级、地域级的快速扩展;高性能,存储采用读写分离架构,计算引擎全链路性能优化,准内存数据库性能。而这四个关键的特性都是金融业务最为看重的,而且需要在应用和存储上端到端实现。 以一致性为例,在单个数据库内是可以确保数据一致性的,但在大规模应用的情况下,单个数据库总是会出现瓶颈,数据往往会像服务或者应用一样,按照类似交易、支付、账目等粒度垂直拆开,当这些数据分别存储在不同的数据库集群后,就需要在应用层来解决一致性问题了,同时为了支持海量数据,数据库集群内部也会做分别和多副本,OceanBase 就是这样一套分布式数据库,在其内部也要实现分布式事务。只有这样上下配合才能解掉所有分布式架构下的一致性问题,缺一不可。 再比如可扩展性方面,有些系统号称做了分布式架构,实际可能只是用了微服务框架,做了应用层的服务化改造,但数据库层既没有用水平扩展的技术,也没用分布式数据库,整个系统的可扩展性就卡在数据层的短板上。 所以,真正的分布式系统,需要实现端到端的分布式,才能实现无限可扩展和高性能,而真正的金融级分布式系统则要实现端到端的高可用和一致性。 蚂蚁金服三地五中心异地多活架构我们认为,高可用架构最关键的目标是数据不丢,业务不停。在这个目标的基础上,我们设计并实施了三地五中心的异地多活架构。它的核心优势包括城市级容灾,低成本交易,无限可扩展,以及 RPO=0,PTO<30s. 大家知道我们在去年云栖大会上做了一次剪网线的demo,它演示了整个架构层面上怎么样做到跨城市多活和灾难情况下的恢复快速恢复能力。同时在高可用达标的情况下,我们也做了很多风险相关的事情,总结起来就是在高可用的基础上还要做到资金的安全、变更的免疫和故障的快速恢复。 解决了高可用的问题,其实金融级最被高频提到的话题就是安全,在云原生时代,我们要解决的是全链路、端到端的安全风险。具体分为三个层面: 云原生网络安全,包括策略化高效流量控制,全链路加密,流量劫持与分析;云原生基础设施安全,包括安全容器,不共享内核,以及安全沙箱;云原生业务安全,包括 SOFAEnclave 机密计算中间件,以及内存安全的、多任务 Enclave LibOS Occlum。 这个部分我的同事在《金融服务的云原生安全架构》演讲中会详细介绍。小结一下,所谓金融级的能力,最主要是要实现端到端的金融级的高可用,同时实现端到端的安全。接下来我想分享的是,在云原生这个阶段往前走遇到了哪些问题。 从单元化到弹性架构 应对互联网爆炸式的流量脉冲 从单元化到云原生下的弹性架构 首先解释下什么是单元化,大家可能比较容易理解数据库层的分库分表或者说  Sharding,能够通过分片的方式解决集中存储计算性能问题,单元化的核心思想是把数据的分片提前到了入口请求的分片,在机房的网络接入层将用户请求根据某个纬度(比如用户 ID)进行 Sharding,这就好比把每个机房就当做了一个巨大无比的有状态的数据库分片,当你是一个 ID 尾号为007或者008用户的时候,当请求通过手机端或者网页域名发送到机房,接入层就已经识别出应该将你路由到华东地区还是在华南地区。当你进入到某个地区的机房时,大部分请求处理工作可以在机房内部完成。偶尔会有一些业务可能会发生跨机房的服务调用,比如说数据在 A 机房的用户给数据在 B 机房的用户转账。这个时候就需要在这个机房上去做有状态的设计。 我们走向云原生时代的时候,在大的架构上面用 Kubernetes 为基础来设计,在单元化架构下,我们选择在每个单元里部署一个 Kubernetes 集群,将支持多 K8s 集群管理和管控指令下发的 Federated APIServer 做逻辑上的全局部署,其中管控元数据是存储在一个 ETCD 集群的,以保持全局数据一致,但大家知道 ETCD 也只能解决同城双机房的容灾,无法再应对多城市多数据中心的一致性,因此我们正在把 ETCD 搬到我们的 OB 的 KV 引擎上,这样在引擎层还是保持 ETCD 的存储格式和语义,存储层就具备了三地五中心高可用能力。 ...

October 17, 2019 · 2 min · jiezi

设计模式之模板方法模式

0x01.定义与类型定义:定义了一个算法的骨架,并允许子类为一个或多个步骤提供实现准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。比如定义一个操作中的算法的骨架,将步骤延迟到子类中。模板方法使得子类可以再不改变算法结构的情况下,重新定义算法的某些步骤类型:行为型UML类图 样例代码/** * 模板方法类 */public abstract class ATemplate { /** * 模板方法 */ public void templateMethod() { before(); doAction(); after(); } /** * 钩子函数 * 一个空的方法 */ protected void before(){} /** * 抽象方法 * 业务逻辑 */ public abstract void doAction(); /** * 具体方法 */ private void after() { System.out.println("after!"); }}/** * 具体的实现类 */public class BusinessEntity extends ATemplate { @Override protected void before() { super.before(); System.out.println("before"); } @Override public void doAction() { System.out.println("doAction"); }}测试与应用类public class Test { public static void main(String[] args) { ATemplate template = new BusinessEntity(); template.templateMethod(); }}输出结果beforedoActionafter!角色介绍 ...

October 17, 2019 · 2 min · jiezi

云原生时代蚂蚁金服公开了新的金融混合云架构

蚂蚁金服在过去十五年重塑支付改变生活,为全球超过十二亿人提供服务,这些背后离不开技术的支撑。在 2019 杭州云栖大会上,蚂蚁金服将十五年来的技术沉淀,以及面向未来的金融技术创新和参会者分享。互联网技术发展日新月异,我们正在进入云原生时代,这个过程中金融行业要如何拥抱云原生?在近两年蚂蚁金服将云原生在金融领域落地,沉淀下一些实践经验,接下来我想分享在蚂蚁的演进过程当中,我们心中的云原生是什么样的,在金融领域落地的时候遇到什么问题,以及我们是怎么解决的。 经过多年云计算的蓬勃发展,上云已经不是太大问题,接下来的问题是怎么把云用好,用得更高效。RightScale 2019年最新数据显示,现在公有云规模占22%,只使用私有云的客户占3%,更多客户通过混合的模式去使用云,通过混合云取得数据隐私、安全与效率、弹性的平衡。 再看全球整个IT行业,公有云的比例只占整个基础IT市场的10%,市场空间仍然很大,IT市场中剩下很多都是传统企业客户。为什么传统行业无法很好地利用公有云,一个重要的原因是因为他们的 IT 系统经过很长时间建设,很多都有自己的机房。另外有些则业务比较稳定,对上公有云没有很强的需求。它们通常会发展混合云策略,把一些核心业务留在私有云,而把一些边缘业务或创新业务放在公有云上。 这些特点在金融行业也非常明显,除此之外金融行业还有两个特征: 业务形态走向开放和互联网化:随着互联网和数字化经济的发展,金融机构需要进行数字化转型,以及业务敏捷化、服务场景化,以应对新的商业模式带来的冲击;监管合规的诉求:金融行业的业务特点决定了必须是强隔离,强监管的,所以公有云上的资源共享模式在监管方面会有比较大的挑战。因此,混合云战略对金融机构更为适用。这一结论也得到研究支持,根据调研机构Nutanix的报告,全球金融业在混合云应用方面的发展速度超过其它行业,目前部署普及率达到21%,而全球平均水平为18.5%。 那么,什么样的混合云是适合金融机构的呢?以蚂蚁的演进历程为例。 蚂蚁在第四代架构的时候演变成为云平台架构,而且为了应对互联网业务形态下突发性业务对资源的弹性需求,蚂蚁也在同一阶段将架构直接进化成弹性混合云架构。现在蚂蚁已经演进到第五代云原生架构。蚂蚁又是如何在云原生的架构下,把混合云变成金融级的混合云,我想会对各位有些启发。在这个发展过程中,有一条主线,是不同阶段蚂蚁对研发的标准和要求,包括:自主、成本、安全、稳定、海量、敏捷,这也是在在线金融的时代,我们对云原生架构的要求。 从分布式到云原生 建立金融级交易支付系统建立金融级的在线交易系统,第一步是要实现金融级分布式的架构,蚂蚁在这方面的代表技术是SOFAStack和OceanBase,目前都已对外商业化,并有丰富的案例。SOFAStack代表的是,在整个应用层或者无状态服务这个层面上,如何去做可伸缩、可扩展的一套架构。OceanBase代表的是以数据库为代表的存储或者是有状态服务层面,如何在架构上面去进行分布式。它们拥有四个特性: 高可用,99.99%+的可用性保证,确保系统始终连续运行不中断; 一致性,在任何异常情况下数据最终一致,确保资金安全; 可扩展,支持应用级、数据库级、机房级、地域级的快速扩展; 高性能,存储采用读写分离架构,计算引擎全链路性能优化,准内存数据库性能。 而这四个关键的特性都是金融业务最为看重的,而且需要在应用和存储上端到端实现。 以一致性为例,在单个数据库内是可以确保数据一致性的,但在大规模应用的情况下,单个数据库总是会出现瓶颈,数据往往会像服务或者应用一样,按照类似交易、支付、账目等粒度垂直拆开,当这些数据分别存储在不同的数据库集群后,就需要在应用层来解决一致性问题了,同时为了支持海量数据,数据库集群内部也会做分别和多副本,OceanBase 就是这样一套分布式数据库,在其内部也要实现分布式事务。只有这样上下配合才能解掉所有分布式架构下的一致性问题,缺一不可。 再比如可扩展性方面,有些系统号称做了分布式架构,实际可能只是用了微服务框架,做了应用层的服务化改造,但数据库层既没有用水平扩展的技术,也没用分布式数据库,整个系统的可扩展性就卡在数据层的短板上。 所以,真正的分布式系统,需要实现端到端的分布式,才能实现无限可扩展和高性能,而真正的金融级分布式系统则要实现端到端的高可用和一致性。 我们认为,高可用架构最关键的目标是数据不丢,业务不停。在这个目标的基础上,我们设计并实施了三地五中心的异地多活架构。它的核心优势包括城市级容灾,低成本交易,无限可扩展,以及RPO=0,PTO<30s. 大家知道我们在去年云栖大会上做了一次剪网线的demo,它演示了整个架构层面上怎么样做到跨城市多活和灾难情况下的恢复快速恢复能力。同时在高可用达标的情况下,我们也做了很多风险相关的事情,总结起来就是在高可用的基础上还要做到资金的安全、变更的免疫和故障的快速恢复。 解决了高可用的问题,其实金融级最被高频提到的话题就是安全,在云原生时代,我们要解决的是全链路、端到端的安全风险。具体分为三个层面: 云原生网络安全,包括策略化高效流量控制,全链路加密,流量劫持与分析;云原生基础设施安全,包括安全容器,不共享内核,以及安全沙箱;云原生业务安全,包括SOFAEnclave机密计算中间件,以及内存安全的、多任务Enclave LibOS Occlum。这个部分我的同事在《金融服务的云原生安全架构》演讲中会详细介绍(点此查看演讲整理)。小结一下,所谓金融级的能力,最主要是要实现端到端的金融级的高可用,同时实现端到端的安全。接下来我想分享的是,在云原生这个阶段往前走遇到了哪些问题。 从单元化到弹性架构 应对互联网爆炸式的流量脉冲 首先解释下什么是单元化,大家可能比较容易理解数据库层的分库分表或者说 Sharding,能够通过分片的方式解决集中存储计算性能问题,单元化的核心思想是把数据的分片提前到了入口请求的分片,在机房的网络接入层将用户请求根据某个纬度(比如用户ID)进行 Sharding,这就好比把每个机房就当做了一个巨大无比的有状态的数据库分片,当你是一个 ID 尾号为007或者008用户的时候,当请求通过手机端或者网页域名发送到机房,接入层就已经识别出应该将你路由到华东地区还是在华南地区。当你进入到某个地区的机房时,大部分请求处理工作可以在机房内部完成。偶尔会有一些业务可能会发生跨机房的服务调用,比如说数据在 A 机房的用户给数据在 B 机房的用户转账。这个时候就需要在这个机房上去做有状态的设计。 我们走向云原生时代的时候,在大的架构上面用Kubernetes为基础来设计,在单元化架构下,我们选择在每个单元里部署一个Kubernetes集群,将支持多 K8s 集群管理和管控指令下发的 Federated APIServer 做逻辑上的全局部署,其中管控元数据是存储在一个 ETCD 集群的,以保持全局数据一致,但大家知道ETCD也只能解决同城双机房的容灾,无法再应对多城市多数据中心的一致性,因此我们正在把ETCD搬到我们的OB的 KV引擎上,这样在引擎层还是保持 ETCD 的存储格式和语义,存储层就具备了三地五中心高可用能力。 虽然这种架构是适合蚂蚁的技术架构的,但在我们的技术开放给外部客户时又会遇到很多新的问题,比方说在客户的机房会有很多异构的基础设施,我们就需要以 Cloud Provider的标准来实现多云适配。 而且包括我们在内的很多金融机构,因为很多老系统并没有按照「云原生」的方式去设计,很多会对基础设施有状态依赖,比如依赖IP ,所以很难完全采用不可变基础设施的模式来支撑。有些时候,由于对业务连续性的极高要求,也很难接受原生 K8s workload 的运维模式,比如原生 deployment 做灰度或者金丝雀发布时,对应用和流量的处理都是非常简单粗暴的,这样会导致运维变更时的业务的异常和不连续。这些我们都通过扩展原生的 Deployment 成更适合金融业务要求的 CAFEDeployment,使得大规模集群发布、灰度、回滚时更加优雅,符合我们的「技术风险三板斧原则」。 ...

October 16, 2019 · 1 min · jiezi

当金融科技遇上云原生蚂蚁金服是怎么做安全架构的

蚂蚁金服在过去十五年重塑支付改变生活,为全球超过十二亿人提供服务,这些背后离不开技术的支撑。在 2019 杭州云栖大会上,蚂蚁金服将十五年来的技术沉淀,以及面向未来的金融技术创新和参会者分享。我们将其中的优秀演讲整理成文并将陆续发布在“ 金融级分布式架构”公众号上,本文为其中一篇。本文作者:何征宇,gVisor 创始人,蚂蚁金服研究员 在云原生发展趋势之下,金融行业想要应用云原生技术,安全问题是一个非常大的拦路虎,而云原生社区对安全问题的重视程度远远不够。蚂蚁金服在落地云原生的时候,解决安全问题是重中之重,经过探索与实践,我们沉淀出了一套从底层硬件到软件、从系统到应用层的全链路金融级云原生安全架构。 金融行业最重要的就是信任,我们认为,安全所带来的信任,是一种无形的产品,支撑着所有金融业务。 顺应互联网时代发展,金融行业与机构也发生了很多的变化,包括 App、小程序等更多的访问渠道,更快的业务变化,更多的第三方供应商。但是,不管怎么变化,金融行业有一点始终不变,那就是 Zero Fault,对错误的零容忍,也就是对稳定性和安全性的极高要求。 这里,我还想澄清大家对金融行业的一个错误看法,就是,大家都说金融机构有很多遗留系统,很多技术是十几年前的,就认为金融机构的技术是落后的。但其实,金融行业一直是科技含量非常高的。前段时间有一部电影上映,叫《蜂鸟计划》,根据真实事件改编,讲一帮做高频交易的人,为了降低从堪萨斯到纽约交易所的时间,建造了一条上千英里直通两地的光纤,想尽办法去争取那最后一毫秒。所以,金融行业并不只有平庸保守的科技,它同样也在追逐最前沿最先进的技术,我们的使命就是要用科技来进一步武装金融行业,为金融科技注入更多的活力。 云原生架构其实代表一种新的生产力,金融行业肯定是需要云原生的,它为我们带来了节约成本和敏捷开发的能力,但是在它前面还需要加一个定语,就是安全的云原生架构,它里面不仅仅包含之前的相对简单的安全方案,而是一个从端到端的全链路可信的安全解决方案。包括明晰代码所有权,做到可信启动,对镜像的制作和发布收口,配合账号体系,明晰应用的所有权和访问权限;以及安全可独立部署的精细化隔离方案,将安全策略和实施集成在基础架构中,对软件开发和测试透明。 这里我们着重分享蚂蚁金服正在实践的几项云原生安全技术,包括云原生网络安全 Service Mesh,安全容器,以及机密计算。 云原生网络安全:SOFAMesh 当前,云原生里除了容器之外第二大技术其实就是 Service Mesh,从蚂蚁的实践来看,其实它对金融安全有非常高的帮助。它至少可以做到三点: 策略化高效流量控制,可以帮助运维迅速适应业务快速变化;全链路加密,保护端到端数据安全;流量劫持与分析,当发现异常流量与容器时,进行流量阻断。并且,这些工作对业务是透明的,不需要给业务开发增加负担,同时我们还可以对流量进行实时的语义分析等等,做比传统的防火墙更多的事情。 蚂蚁金服在对 Service Mesh 的探索中,推出了自己用 Golang 打造的 SOFAMesh,并且已经对外开源,希望和社区一起努力,让 Service Mesh 的理念和技术更加普及。 SOFAMesh 是基于 Istio 改进和扩展而来的 Service Mesh 大规模落地实践方案。在继承 Istio 强大功能和丰富特性的基础上,为满足大规模部署下的性能要求以及应对落地实践中的实际情况,所做的改进包括采用 Golang 编写的 SOFAMosn 取代  Envoy,极大降低了 Mesh 本身的开发难度,并做了一些创新性工作,例如合并Mixer到数据平面以解决性能瓶颈,增强 Pilot 以实现更灵活的服务发现机制,增加对 SOFARPC、Dubbo 的支持,等等。 更多详情可查看 SOFAMesh 的 GitHub 主页:https://github.com/sofastack/... 蚂蚁金服率先在生产环境中大规模落地 SOFAMesh,超过 10W+ 容器做到了 Mesh 化,平稳支撑了 618 大促,给我们带来了多协议支持、UDPA、平滑升级、安全等多方面的好处,并且对性能仅有轻微的影响,单跳 CPU 增加 5% 损耗,RT增加不到 0.2ms,甚至部分业务经过 Mesh 化改造将业务链路下沉,RT 反而下降 7%。 ...

October 15, 2019 · 2 min · jiezi

如何基于-Nacos-和-Sentinel-实现灰度路由和流量防护一体化

基于Alibaba Nacos和Sentinel,实现灰度路由和流量防护一体化的解决方案,发布在最新的 Nepxion Discovery 5.4.0 版,具体参考: 源码主页,请访问 源码主页指南主页,请访问 指南主页文档主页,请访问 文档主页 Nepxion Discovery框架在实现灰度发布和路由功能前提下,结合Nacos和Sentinel,对流量再实施一层防护措施,更能达到企业级的流量安全控制的目的。它的功能包括: 封装远程配置中心和本地规则文件的读取逻辑,即优先读取远程配置,如果不存在或者规则错误,则读取本地规则文件。动态实现远程配置中心对于规则的热刷新封装NacosDataSource和ApolloDataSource,支持Nacos和Apollo两个远程配置中心,零代码实现Sentinel功能。更多的远程配置中心,请参照Sentinel官方的DataSource并自行集成支持原生的流控规则、降级规则、授权规则、系统规则、热点参数流控规则支持扩展LimitApp的机制,通过动态的Http Header方式实现组合式防护机制,包括基于服务名、基于灰度组、基于灰度版本、基于灰度区域、基于机器地址和端口等防护机制,支持自定义任意的业务参数组合实现该功能,例如,根据传入的微服务灰度版本号+用户名,组合在一起进行熔断支持微服务侧Actuator、Swagger和Rest三种方式的规则写入支持控制台侧基于微服务名的Actuator、Swagger和Rest三种方式的批量规则写入支持开关关闭上述功能spring.application.strategy.sentinel.enabled=true,默认是关闭的[Nacos] 阿里巴巴中间件部门开发的新一代集服务注册发现中心和配置中心为一体的中间件。它是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施,支持几乎所有主流类型的“服务”的发现、配置和管理,更敏捷和容易地构建、交付和管理微服务平台 [Sentinel] 阿里巴巴中间件部门开发的新一代以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性的分布式系统的流量防卫兵。它承接了阿里巴巴近10年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等 环境搭建及依赖引入服务端在Discovery框架原有依赖的基础上,再引入如下依赖 <dependency> <groupId>com.nepxion</groupId> <artifactId>discovery-plugin-strategy-starter-service-sentinel</artifactId> <version>${discovery.version}</version></dependency><dependency> <groupId>com.nepxion</groupId> <artifactId>discovery-plugin-strategy-sentinel-starter-nacos</artifactId> <!-- <artifactId>discovery-plugin-strategy-sentinel-starter-apollo</artifactId> --> <version>${discovery.version}</version></dependency>原生Sentinel注解参照下面代码,为接口方法增加@SentinelResource注解,value为sentinel-resource,blockHandler和fallback是防护其作用后需要执行的方法 @RestController@ConditionalOnProperty(name = DiscoveryConstant.SPRING_APPLICATION_NAME, havingValue = "discovery-guide-service-b")public class BFeignImpl extends AbstractFeignImpl implements BFeign { private static final Logger LOG = LoggerFactory.getLogger(BFeignImpl.class); @Override @SentinelResource(value = "sentinel-resource", blockHandler = "handleBlock", fallback = "handleFallback") public String invoke(@PathVariable(value = "value") String value) { value = doInvoke(value); LOG.info("调用路径:{}", value); return value; } public String handleBlock(String value, BlockException e) { return value + "-> B server sentinel block, cause=" + e.getClass().getName() + ", rule=" + e.getRule() + ", limitApp=" + e.getRuleLimitApp(); } public String handleFallback(String value) { return value + "-> B server sentinel fallback"; }}原生Sentinel规则Sentinel在配置中心订阅的Key格式,如下: ...

October 15, 2019 · 2 min · jiezi

阿里张磊云计算生态价值点正迅速聚焦到应用上

导读:云原生不再只是基础设施的开发和运维人员的关注点,在应用交付领域小组成立之后,CNCF 基金会正在同应用开发和应用运维人员更紧密的联系在一起。云原生的理念如今正如火如荼。它不仅仅是一种技术,更是社区基于对云的思考,逐渐提炼出的一系列技术、最佳实践与方法论的集合。不过,到目前为止云原生的讨论较多局限在基础设施的开发和运维人员群体中。 相比之下,更关注业务本身的应用开发同学,与云原生技术带来的资源利用率提升、分布式系统的弹性扩展与可靠性等能力之间,始终存在着一定的隔阂。对这部分同学来说,云原生技术更多时候还停留在“知其然”的阶段。 然而,伴随着云原应用的理念持续普及,我们正看到整个云计算生态的核心关注点正在发生着微妙的变化。 2019 年 9 月 12 日,云原生基金会 CNCF 宣布成立应用交付领域小组(Application Delivery SIG)。阿里巴巴高级技术专家、Kubernetes 社区资深成员张磊,软件智能公司 Dynatrace 的首席技术与战略创新官 Alois Reitbauer,与 VMware 资深专家 Bryan Liles 共同当选为该小组首届联席主席。 该领域小组是 CNCF 基金会官方成立的第一个以“应用”为中心的领域小组,也被社区誉为是 “CNCF 里最具价值的领域小组”。 那么,为什么 CNCF 会将“应用交付”设立为新的核心关注点呢?云原生的本质,是一种让应用最大程度享受云计算红利的架构思想。这种思想,实际上是在云计算技术不断普及的过程中,应用基础架构不断朝着”让专业的人做专业事“的方向持续演进、然后逐步沉淀下来的一套最佳实践和架构范式。 实际上,在云计算真正普及之前,基础设施能力(比如服务发现、流量控制、监控与可观测性、访问控制、网络控制、存储层抽象等)并不是开发者唾手可得的资源。所以应用基础设施必须以某种方式屏蔽底层基础设施对它的缺失和薄弱的环节进行增补,才能够让开发者更好的专注于业务逻辑这个最具价值的事情。 所以在这个时期,传统应用基础架构与应用之间是非常紧密的耦合关系,要么应用基础设施直接接管应用开发本身的各个阶段(比如 ESB),要么就是应用基础设施直接成为应用开发过程中的一部分(比如 各种编程框架和中间件)。这种架构下,应用本身的能力与演进,实际上是跟应用基础设施的命运被紧紧的绑定在了一起。 当然,这个情况如今已经今非昔比。云计算的迅速崛起,使得当今的基础设施能力正逐渐通过 Kubernetes 这样的标准的平台层下沉到了更加专业的云服务体系当中,而不再拘泥和锁定于传统中心化应用基础设施和中间件自身的能力。云原生技术体系,打通了云与应用之间最后的隔阂,也使得后续涌现出的 Service Mesh 思想得以进一步解耦“应用”与“应用基础设施”,使得应用可以直接通过 localhost,即可连接到原先必须由中心化应用基础设施或者中间件才能提供的各项能力当中。 伴随着云原生应用架构的逐步落地,应用开发者的心智正逐步从基础设施层当中解放出来。这也使得社区的价值聚焦点,开始从“资源效能”逐步向“研发效能”和“交付效能”靠拢。这个变化,将会接下来成为云原生生态继续发展的一个重要趋势。 如何解读云原生基金会 CNCF 成立应用交付领域小组?对于这一新成立的领域小组,其后续会做哪些事情是广大云计算领域开发者非常关注的,张磊表示: 一、领域小组将逐步确立和推进“云原生应用管理与标准交付体系”云原生应用管理与交付是一个随着云原生技术日渐成熟之后迅速成为新一代云计算技术聚焦点的重要技术领域。在当前的技术生态当中,Kubernetes 正在构建一个受到全世界普遍认同的、标准化的应用基础设施层;Serverless 则提供了一种高效的调度与资源管理模型;而 Service Mesh 则进一步明确了应用之间非侵入式的服务治理机制。这些能力,我们都统一称之为“平台层能力”,也是之前 CNCF 基金会主要关注的领域。 而本次 CNCF 应用交付领域小组所关注的,则是在“平台层”之上的“应用管理层”的技术架构和演进方向。这一层,也是未来云计算生态的价值聚焦点。 应用交付领域小组将致力于与整个云原生社区协作,共同在“应用”、“最终用户”和“平台层”之间,构建出一套高效、标准和可信赖的交付与连通体系。这个思想贯穿应用交付的声明周期,我们可以通过一个标准的分层结构(云原生应用分层模型)来将其形象表达出来: 在这个模型下,“应用定义”,“应用部署与交付”,和“应用实例管理”之间会进行清晰的分层和协作。这种分层理念,是目前整个云计算生态都缺失的。而云原生应用分层模型,将会成为后续云原生应用交付生态向“标准化”、“插件化”、和“职责分离”的方向不断演进的重要理论基础。 二、云原生应用交付最佳实践与架构范式应用交付领域小组将协同云原生开源社区一起,在上述“云原生应用分层模型”体系下逐步抽象与提炼出各层对应的最佳实践、基础范式、参考架构与项目范例,同时对主流开源社区中的应用管理项目进行梳理和汇总。最终,这些内容都会以《CNCF 云原生应用架构白皮书》的方式同整个生态见面。 三、推动云原生应用交付生态向分层与标准的架构上不断演进在上述理论和实践基础上,应用交付领域小组将会联同社区和生态,共同推进主线应用管理开源项目逐步向分层、统一、标准的方向持续演进。此外,领域小组也会持续在这套体系下进一步甄别和孵化开源项目,并通过编制《云原生应用交付生态指南(Cloud Native App Delivery Lanscape)》来帮助云原生用户和开发者进行选型和架构参考。这些都有望让云原生社区的终端用户真正成为应用交付领域小组最大的受益者。 ...

October 9, 2019 · 1 min · jiezi

如何避免新代码变包袱阿里通用方法来了

阿里妹导读:什么是设计?什么是架构?从零开始建立一个新的系统,新写的每行代码都可能成为明天的历史包袱?如何能有效的在遗留代码上工作?今天,阿里资深技术专家辉子为我们带来NBF框架下软件工程架构设计通用方法论,值得细细品读。Note:本文讨论的是基于服务化前提下的通用软件工程架构方法论,并未涉及到微观设计或架构的具体细节。 前言即使代码多年的人都会对这两个问题有点蒙圈:什么是设计?什么是架构? 从单词上看:设计是Software Design,架构是Software Architecture;分别对应的作者是:Designer和Architect: Architect都是Designer,但Designer未必是Architect。正如所有的架构设计都是设计,但设计未必是架构设计;Design关注微观代码(inside component),Architecture关注宏观软件结构(between components);Architect应该都是从Designer成长起来的。毕业了用code编写软件;成长了用ppt设计软件;只会用ppt设计,但代码写得不好的Architect都是假的Architect;Architecture里听到比较多的词语:Serverless、FAAS、Microservice、multi-layer、Event driven、OSGI、NBF......Design里听到比较多的词语:SOLID、 DDD、正交设计、Design Pattern;搞不清SOLID,也不可能把软件的层次分好,也无法理解什么是OSGI的价值;好的Designer是通往好的Architect的必经之路。服务化架构的基本原则 New System从零开始建立一个新的系统,有几个特征: 历史包袱小上下文简单设计的约束小新写的每行代码都可能成为明天的历史包袱由于调用方还没有,新系统可以比较完美的执行我们预想的架构设计,但是切记,最后那行才是最重要的那行:不要让今天的代码成为明天的历史包袱,新的每行代码都在书写历史。 上图的1,2,3,4代表新建系统的顺序: 由“相”抽象出“心”:先思考,那么多的业务场景下“相”,共同的特征“心”是什么。并反向用更多的相去验证心。将“心”具象成领域模型:关注领域模型(Domain Model),解耦数据模型(Persistence Model):将TUNNEL SPI化。将领域模型中的依赖SPI化:解耦对外部系统的依赖,反转依赖控制权。Mock所有spi实现,确保“心”领域模型包裹的单元测试完全通过实现TUNNEL BUNDLE:设计数据模型(Persistence Model),关注“存”,“取”不关注领域模型。实现依赖SPI适配BUNDLE:连接真实依赖服务。包装domain service:模型相关,业务无关。根据业务需求组合/编排domain service成为scenario bundle或者业务SOP。Working on legacy对于一个软件工程师来讲,写代码最痛苦的事情莫过于coding on legacy,但同时又给了我们各种说辞: 这些代码太烂了,改起来太费劲【需要更多人】这事做不到,因为以前系统架构问题导致的【责任不在我】经过我的修改,现在已经好很多了,工单数量大批下降【我功劳显著】知不知道:接手你代码的人其实也在重复说上述3件事情如何能有效的在遗留代码上工作,业内有本非常不错的书,叫"Working Effectively with Legacy Code",值得精读: 所以我这里的标题可能不准确,我要讨论的更多是"遗留代码的重构",什么时候我们开始讨论需要把现有系统重构: 代码确实腐化到无法正常维护,或者新加一个需求代价很大;目前代码的技术架构满足不了下一步业务的发展;很多特性已经下线作废,却跟有用的代码藕断丝连;业务逻辑随着发展分散到不同的应用里,界限不清;专家级的未雨绸缪,着眼未来的规划和新技术的应用;换老大了,需要立新的flag。架构的基本原则依然是上面那幅图。但上下文的不同,我们的发力点和优先级有明显的区别。阿里整个体系里的依赖关系错综复杂,要对阿里环境下的系统做重构是件绝对谨小慎微的事情。为了完成在这么复杂体系下的架构及代码重构,我们必须有条不紊的分离关注点以及一如既往的坚持软件卓越。 聚焦与收敛上游调用 解耦下游依赖 以服务为单位切换 老系统下线 经过一步一步的分解,legacy系统已经完全被重构,并且具备随时切换的准备。这里我给几个建议: 先把老实现作为API的默认实现,新的实现作为老的实现的降级实现,并使用策略分流一部分流量(具体比例跟团队信心相关);对于有业务需求变更的部分应尽快实现在新的实现里,并将新实现作为API的默认实现,老实现作为新实现的降级实现,策略应该是即时降级,也就是新实现出现问题立刻降级到老实现;运行一段时间没有问题后,讲所有默认实现切换为新实现,并将老实现作为新实现的降级实现;其实这时就算所有切换完毕:老实现可以永远作为新实现的降级实现,也就是只要我升级一次服务,上一次成功版本就可以作为这次的降级实现,这样,线上问题回滚就是秒级的。总结本文基于借助NBF提供的远程多态,服务编排等能力下基础资料,商品,组网等系统新建,重构的经验及方法论总结。仅供遇到架构重构,解耦等问题困扰的技术团队参考。 Note:本文所有图形出自玉简 本文作者:辉子阅读原文 本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

September 30, 2019 · 1 min · jiezi

Serverless-Kubernetes全面升级20架构支持多命名空间RBACCRDPVPVC等功能

Serverless Kubernetes概述:阿里云Serverless Kubernetes容器服务最新开放香港、新加坡、悉尼区域,同时全面开放2.0架构,帮助用户更加便捷、轻松地步入“以应用为中心”的全新架构。通过Serverless Kubernetes,用户50秒内可从零启动500应用容器,而无需关心底层服务器资源。 Serverless Kubernetes 2.0新架构Serverless Kubernetes 2.0对后台架构进行了彻底升级,从之前的基于Namespace的多租户隔离,升级为租户独占k8s master,极大的增强了安全性和隔离型。每个租户拥有独立的apiserver,避免了共享Apiserver导致的租户干扰问题,同时一个集群中apiserver的安全风险也不会扩散到其他集群。因为租户拥有完整的k8s master,所以天然支持更完整的原生kubernetes能力,包括多命名空间、CRD、RBAC等,详细对比如下:通过CRD/RBAC的支持,我们可以在Serverless集群中部署Istio/knative/Argo/Spark/Kubeflow等多种controller,极大扩展了Serverless Kubernetes面向的应用场景,支撑更多云原生应用的Serverless化部署,充分享受Serverless带来的简单、敏捷和弹性能力。 收费模式:用户需要为集群中的Pod资源资源付费(收费规则请参考ECI收费规则)。Serverless集群中的k8s master(apiserver等)被阿里云容器服务托管,用户并不需要为master资源付费。 下面让我们创建Serverless集群,体验2.0相关功能。 **体验Serverless Kubernetes 2.0:创建Serverless集群** Namespace管理对于新创建的serverless集群,默认有default/kube-system/kube-public三个命名空间。用户可以创建新的namespace,并在新的namespace中创建pod。虚拟节点Sererless集群中默认存在一个virtual-kubelet虚拟节点,此节点负责所有pod的生命周期管理。得益于虚拟节点的“无限容量”,serverless集群中用户无需做容量规划,也不存在节点的扩容和缩容,用户只需要关注pod的管理。PV/PVC管理目前需要用户在Serverless集群中手动部署alicloud-disk-controller。部署成功后才可以管理pv/pvc/storageClass等资源。 主子账号授权同托管版集群一样,Serverless集群也支持在“授权管理”页面对子账号按照Namespace进行细粒度授权。结束近期ECI售价平均降低46%,创建pod的成本进一步降低。欢迎登录阿里云容器服务控制台创建serverless集群,体验serverless的敏捷和弹性。本文作者:贤维原文链接:https://yq.aliyun.com/article... 本文为云栖社区原创内容,未经允许不得转载。

September 19, 2019 · 1 min · jiezi

如果你也想做实时数仓…

数据仓库也是公司数据发展到一定规模后必然会提供的一种基础服务,数据仓库的建设也是“数据智能”中必不可少的一环。本文将从数据仓库的简介、经历了怎样的发展、如何建设、架构演变、应用案例以及实时数仓与离线数仓的对比六个方面全面分享关于数仓的详细内容。 1.数据仓库简介数据仓库是一个面向主题的(Subject Oriented)、集成的(Integrate)、相对稳定的(Non-Volatile)、反映历史变化(Time Variant)的数据集合,用于支持管理决策。 数据仓库是伴随着企业信息化发展起来的,在企业信息化的过程中,随着信息化工具的升级和新工具的应用,数据量变的越来越大,数据格式越来越多,决策要求越来越苛刻,数据仓库技术也在不停的发展。数据仓库的趋势: 实时数据仓库以满足实时化&自动化决策需求;大数据&数据湖以支持大量&复杂数据类型(文本、图像、视频、音频); 2.数据仓库的发展数据仓库有两个环节:数据仓库的构建与数据仓库的应用。 早期数据仓库构建主要指的是把企业的业务数据库如 ERP、CRM、SCM 等数据按照决策分析的要求建模并汇总到数据仓库引擎中,其应用以报表为主,目的是支持管理层和业务人员决策(中长期策略型决策)。 随着业务和环境的发展,这两方面都在发生着剧烈变化。 随着IT技术走向互联网、移动化,数据源变得越来越丰富,在原来业务数据库的基础上出现了非结构化数据,比如网站 log,IoT 设备数据,APP 埋点数据等,这些数据量比以往结构化的数据大了几个量级,对 ETL 过程、存储都提出了更高的要求;互联网的在线特性也将业务需求推向了实时化,随时根据当前客户行为而调整策略变得越来越常见,比如大促过程中库存管理,运营管理等(即既有中远期策略型,也有短期操作型);同时公司业务互联网化之后导致同时服务的客户剧增,有些情况人工难以完全处理,这就需要机器自动决策。比如欺诈检测和用户审核。 总结来看,对数据仓库的需求可以抽象成两方面:实时产生结果、处理和保存大量异构数据。 注:这里不讨论数据湖技术。3.数据仓库建设方法论3.1 面向主题从公司业务出发,是分析的宏观领域,比如供应商主题、商品主题、客户主题和仓库主题 3.2 为多维数据分析服务数据报表;数据立方体,上卷、下钻、切片、旋转等分析功能。 3.3 反范式数据模型以事实表和维度表组成的星型数据模型 4.数据仓库架构的演变数据仓库概念是 Inmon 于 1990 年提出并给出了完整的建设方法。随着互联网时代来临,数据量暴增,开始使用大数据工具来替代经典数仓中的传统工具。此时仅仅是工具的取代,架构上并没有根本的区别,可以把这个架构叫做离线大数据架构。 后来随着业务实时性要求的不断提高,人们开始在离线大数据架构基础上加了一个加速层,使用流处理技术直接完成那些实时性要求较高的指标计算,这便是 Lambda 架构。 再后来,实时的业务越来越多,事件化的数据源也越来越多,实时处理从次要部分变成了主要部分,架构也做了相应调整,出现了以实时事件处理为核心的 Kappa 架构。 4.1 离线大数据架构数据源通过离线的方式导入到离线数仓中。下游应用根据业务需求选择直接读取 DM 或加一层数据服务,比如 MySQL 或 Redis。数据仓库从模型层面分为三层: ODS,操作数据层,保存原始数据;DWD,数据仓库明细层,根据主题定义好事实与维度表,保存最细粒度的事实数据;DM,数据集市/轻度汇总层,在 DWD 层的基础之上根据不同的业务需求做轻度汇总;典型的数仓存储是 HDFS/Hive,ETL 可以是 MapReduce 脚本或 HiveSQL。 4.2 Lambda 架构随着大数据应用的发展,人们逐渐对系统的实时性提出了要求,为了计算一些实时指标,就在原来离线数仓的基础上增加了一个实时计算的链路,并对数据源做流式改造(即把数据发送到消息队列),实时计算去订阅消息队列,直接完成指标增量的计算,推送到下游的数据服务中去,由数据服务层完成离线&实时结果的合并。 注:流处理计算的指标批处理依然计算,最终以批处理为准,即每次批处理计算后会覆盖流处理的结果。(这仅仅是流处理引擎不完善做的折中)Lambda 架构问题: 同样的需求需要开发两套一样的代码:这是 Lambda 架构最大的问题,两套代码不仅仅意味着开发困难(同样的需求,一个在批处理引擎上实现,一个在流处理引擎上实现,还要分别构造数据测试保证两者结果一致),后期维护更加困难,比如需求变更后需要分别更改两套代码,独立测试结果,且两个作业需要同步上线。资源占用增多:同样的逻辑计算两次,整体资源占用会增多(多出实时计算这部分 4.3 Kappa 架构Lambda 架构虽然满足了实时的需求,但带来了更多的开发与运维工作,其架构背景是流处理引擎还不完善,流处理的结果只作为临时的、近似的值提供参考。后来随着 Flink 等流处理引擎的出现,流处理技术很成熟了,这时为了解决两套代码的问题,LickedIn 的 Jay Kreps 提出了 Kappa 架构。 ...

September 10, 2019 · 1 min · jiezi

蚂蚁金服-3-个项目进入-CNCF-云原生全景图-开源

2019 年 6 月 25 日,全球知名开源组织云原生计算基金会 CNCF 宣布,蚂蚁金服正式成为 CNCF 黄金会员,蚂蚁金服表示将持续加大对开源项目的支持,包括 Kubernetes,ServiceMesh,Serverless,安全容器等方向,并发挥自己的力量。SOFAStack 作为蚂蚁金服重要的开源项目,最近也与 CNCF 有故事发生。近期,CNCF 发布了最新版本的 Cloud Native Landscape,蚂蚁金服金融级分布式架构 SOFAStack 中有 3 个项目被纳入,分别是 Service Mesh 数据平面代理 SOFAMosn、分布式链路跟踪系统 SOFATracer 和 RPC 服务框架 SOFARPC。 CNCF & CNCF Cloud Native LandscapeCNCF(Cloud Native Computing Foundation),是由 Google 牵头创立的云原生计算开源软件基金会。它致力于云原生(Cloud Native)技术的普及和可持续发展。2016 年 11 月,CNCF 开始维护 Cloud Native Landscape,汇总流行热门的云原生技术与工具,并加以分类,为企业构建云原生体系提供参考,在云生态研发、运维领域具有广泛影响力。 SOFAStack & CNCF Cloud Native Landscape蚂蚁金服金融级分布式架构 SOFAStack 中的 3 个项目加入这次最新版本的 Cloud Native Landscape ,分别是 Service Mesh 数据平面代理 SOFAMosn、分布式链路跟踪系统 SOFATracer 和 RPC 服务框架 SOFARPC。 ...

August 7, 2019 · 1 min · jiezi

网易云音乐的消息队列改造之路

十年文案老司机,不如网易评论区。 网易云音乐自2013年上线后,业务保持了高速增长。云音乐除了提供好听的音乐外,还留下了我们在乐和人上的美好回忆。本文整理自网易云音乐消息队列负责人林德智在近期 Apache Flink&RocketMQ Meetup 上海站的分享,通过该文,您将了解到: 网易云音乐消息队列改造背景网易云音乐业务对消息队列要求网易云音乐消息队列架构设计网易云音乐消息队列部分高级特性介绍网易云音乐消息队列落地使用情况网易云音乐消息队列未公开规划背景网易云音乐从13年4月上线以来,业务和用户突飞猛进。后台技术也从传统的 Tomcat 集群到分布式微服务快速演进和迭代,在业务的不断催生下,诞生了云音乐的 RPC,API 网关和链路跟踪等多种服务,消息队列也从 RabbitMQ 集群迁移到 Kafka集群。对于消息队列,更多处于使用阶段,也在使用中出现很多问题。因此我们期望提供一种完全可控,出现问题我们自己能排查,能跟踪,可以根据业务需求做定制改造的消息队列。 调研结果 RabbitMQ 由于持久化场景下的吞吐量只有2.6万,不能满足我们业务吞吐量的需求,云音乐在 2017 年将消息队列从 RabbitMQ 迁移到 Kafka 也是这个原因,因此不再考虑范围之内。由于云音乐整体业务的 QPS 较高,因此,ActiveMQ 也不在考虑范围。 这里主要对比 RocketMQ 与 Kafka: Kafka 更偏向大数据,日志处理,缺少死信,消费失败自动重试,事物消息,定时消息,消息过滤,广播消息等特性,另外 Kafka 没有同步刷盘。云音乐的业务更偏向于多 Topic,死信可溯源,消费失败可收敛自动重试,高可用,自动 Failover 等特性。对于商城和社交业务来说,事物,顺序 Topic 使用会比较多。Kafka 和RocketMQ 对比 : http://jm.taobao.org/2016/03/24/rmq-vs-kafka 经过 RabbitMQ,Kafka 和 RocketMQ( ActiveMQ 性能较差,暂不考虑)的调研和分析后,我们发现 RocketMQ 比较适合云音乐的通用业务,但是开源 RocketMQ 也有一些缺陷,只有我们解决了这些缺陷才能在业务中大规模使用。 开源 RocketMQ 的基本架构如下:(基本介绍参考) 开源 RocketMQ 主要问题有: Broker 仅提供了 Master 到 Slave 的复制,没有 Failover 切换的能力;事物消息不开源(我们开始研发时不开源);消息发送消费无追踪(我们开始研发时不开源);告警与监控体系没有;开源控制台不完善。云音乐业务对消息队列的要求 ...

July 26, 2019 · 2 min · jiezi

支撑马蜂窝会员体系全面升级背后的架构设计

流量红利正逐渐走向终结,这已经不再是什么秘密。后互联网时代,如何维系住用户群,提升用户在平台上的体验是整个行业都需要考虑的事情。正是出于这一原因,现在全行业都在关注会员体系的搭建,这也是马蜂窝 2019 年重点投入的方向之一。  面对这个全行业都在发力的会员市场,要对「马蜂窝特色」的会员体系进行有力的支撑,无疑对会员体系的架构设计提出更高的要求。 马蜂窝会员体系建设从 2018 年 9 月份开始启动,经过前期对会员身份和会员权益的摸索,伴随业务的快速发展,到 2019 年上半年,为了让更多用户体验到马蜂窝高质量的会员服务,公司推出了更灵活、维度更多、权益更丰富的会员模式。在这样的背景下,初期较为粗旷的底层技术也需要及时做出调整,对核心架构和服务进行升级。 一、会员身份策略改造早期的会员身份模块由会员产品、用户属性和时间属性共同构成: 可以看到早期的会员产品比较单一,因此将产品信息设计成一级结构。这种设计的好处是逻辑简单,可以快速实现,但不易扩展,一旦新增会员类别以及不同卡种之间出现复杂关系时,不论是对项目或者对代码本身而言,维护成本都将成倍增长。 从 2019 年年初开始,马蜂窝会员体系进行了全面升级,主要体现在以下几个方面: 更完善的获客渠道,增加了在小程序端的服务展示;更丰富的会员类别,新增了非常多卡种,在最初的年度金卡和体验金卡基础上,增加了季度金卡、 7 日卡、「蜂享卡」,未来还计划推出月度金卡、学生卡等;更低的获取门槛,早期的会员身份只能通过在 App 中购买获得,为了让更多用户享受到品质更高的服务,增加了通过完成用户激励任务、供应商合作、产品搭售、线下实体卡等会员获取方式。这也意味着,同一时间段内用户的会员身份将变得愈发复杂,早期单一的会员身份策略和模型设计已经不能满足需求。重新设计会员身份的时候,我们明确了未来无论业务线如何划分会员身份,底层结构都要能够较好地支持,因此决定把会员模块身份抽离出来。会员体系升级后,产品信息调整为以 SKU 作为最小粒度重新划分,同时增加了用户信息中的来源以及获取渠道信息: 二、会员中心架构设计和优化在明确了新的会员身份策略后,我们对整个会员体系进行了梳理,将现阶段的会员中心架构设计如下: 合上面的架构图来看,目前马蜂窝会员中心系统主要划分为数据存储、核心服务、接口层、应用层四大部分: 数据储存:主要基于 MySQL 和 Redis,以及马蜂窝统一日志系统 MES核心服务:这是当前马蜂窝会员体系中最重要的一层。核心服务又可以分为三大块:(1)「四驾马车」:会员身份、权益、增值服务接入、会员积分,驱动着整个会员体系的运转; (2)交易营销:辅助四驾马车快速往前跑; (3)支撑模块:与会员体系对接的公司级别支撑模块,包括风控、监控、日志、消息总线、商家结算对账等 接口层:会员体系对外暴露的接口,包括了会员身份、权益领取、蜂蜜消费等接口应用层:主要是面向 C 端的应用,包括会员频道页、蜂蜜中心、用户权益中心、任务中心等下面重点围绕「核心服务」层展开介绍。 2.1「四驾马车」2.1.1 会员身份目前,市面上很多常见的会员产品都是采用普通的续费模式,比如一些视频平台的年度会员、季度会员。这种模式的特点是只进行时间的区分,在会员身份后生效后享受的权益完全相同,通过续费使权益时效得到相应延长。 但是马蜂窝由于业务的特殊性,会员体系需要设计得更为立体。如果只采用单纯的续费模式,会影响高忠诚度用户的使用体验。 首先,在同一类别的会员身份下,时长不同的产品对应的权益也不同。以金卡会员为例,季度金卡、年度金卡这种同类别下的会员身份,可以通过续费升级,但它们彼拥有的权益不完全相同,比如年度金卡 96 折抵额上限为 500 元,季度金卡只有 100 元。另外,同一用户在同一时间内,只要满足条件,就可同时拥有不同类别的卡种,比如金卡和蜂享卡。为了满足上述需求,我们决定引入用户身份的叠加以及续费模型。通过增加会员 SKU 叠加、续费关系表,使用户在一个时间段内不仅可以同时拥有多种身份,还可以续费已有卡种。 上图是会员身份的时间轴示意。横轴代表时间,纵轴代表不同的卡种。我们通过最终 SKU 时间轴便可以确认用户当前的会员身份。 我们将用户已有的每个 SKU 时间轴拉平,当用户在某个时间点发出购买新卡种的请求时,查看当前生效的时间轴中是否已有用户正在购买的 SPU,如果没有则叠加,如已有则需要再判断 SKU 之间的配置策略,决定是叠加还是续费;然后继续计算出正在购买的 SKU 生效时间轴;接下来根据配置好的规则,对比当前购买生效时间轴和已有 SKU 时间轴的身份关系,决定用户是否可以完成此次购买,如: 前置身份:指必须已经购买某个 SKU,才可以购买当前 SKU冲突身份:指如果已经购买某个 SKU,就不可以购买当前 SKU为了满足不同的业务需求,这里的叠加、续费关系都是可以通过运营来配置的。整个流程大致示意如下: ...

July 26, 2019 · 1 min · jiezi

机器学习在高德搜索建议中的应用优化实践

导读:高德的愿景是:连接真实世界,让出行更美好。为了实现愿景,我们要处理好LBS大数据和用户之间的智能链接。信息检索是其中的关键技术,而搜索建议又是检索服务不可或缺的组成部分。 本文将主要介绍机器学习在高德搜索建议的具体应用,尤其是在模型优化方面进行的一些尝试,这些探索和实践都已历经验证,取得了不错的效果,并且为后来几年个性化、深度学习、向量索引的应用奠定了基础。 对搜索排序模块做重构搜索建议(suggest服务)是指:用户在输入框输入query的过程中,为用户自动补全query或POI(Point of Interest,兴趣点,地理信息系统中可以是商铺、小区、公交站等地理位置标注信息),罗列出补全后的所有候选项,并进行智能排序。 我们希望通过suggest服务:智能提示,降低用户的输入成本。它的特点是:响应快、不承担复杂query的检索,可以把它理解为一个简化版的LBS领域信息检索服务。 和通用IR系统一样,suggest也分为doc(LBS中的doc即为POI)的召回和排序两个阶段。其中,排序阶段主要使用query和doc的文本相关性,以及doc本身的特征(weight、click),进行加权算分排序。 但随着业务的不断发展、特征规模越来越大,人工调参逐渐困难,基于规则的排序方式已经很难得到满意的效果。这种情况下,为了解决业务问题,将不得不打上各种补丁,导致代码难以维护。 因此,我们决定对排序模块进行重构,Learning to Rank无疑是一个好的选择。 面临的挑战:样本构造、模型调优Learning to Rank(LTR)是用机器学习的方法来解决检索系统中的排序问题。业界比较常用的模型是gbrank,loss方案用的最多的是pair wise,这里也保持一致。一般应用LTR解决实际问题,最重要的问题之一就是如何获得样本。 首先,高德地图每天的访问量巨大,这背后隐藏的候选POI更是一个天文数字,想要使用人工标注的方法去获得样本明显不现实。 其次,如果想要使用一些样本自动构造的方法,比如基于用户对POI的点击情况构建样本pair ,也会遇到如下的问题: 容易出现点击过拟合,以前点击什么,以后都给什么结果。有时,用户点击行为也无法衡量真实满意度。suggest前端只展示排序top10结果,更多的结果没有机会展现给用户,自然没有点击。部分用户习惯自己输入完整query进行搜索,而不使用搜索建议的补全结果,统计不到这部分用户的需求。对于这几个问题总结起来就是:无点击数据时,建模很迷茫。但就算有某个POI的点击,却也无法代表用户实际是满意的。 最后,在模型学习中,也面临了特征稀疏性的挑战。统计学习的目标是全局误差的一个最小化。稀疏特征由于影响的样本较少,在全局上影响不大,常常被模型忽略。但是实际中一些中长尾case的解决却往往要依靠这些特征。因此,如何在模型学习过程中进行调优是很重要。 系统建模过程详解上一节,我们描述了建模的两个难题,一个是样本如何构造,另一个是模型学习如何调优。 先看下怎么解决样本构造难题,我们解决方案是: 考量用户在出行场景的行为session,不光看在suggest的某次点击行为,更重要的是,考察用户在出行场景下的行为序列。比如suggest给出搜索建议后,继续搜索的是什么词,出行的地点是去哪里,等等。不是统计某个query下的点击, 而是把session看作一个整体,用户在session最后的点击行为,会泛化到session中的所有query上。详细方案第一步,融合服务端多张日志表,包括搜索建议、搜索、导航等。接着,进行session的切分和清洗。最后,通过把输入session中,末尾query的点击计算到session中所有query上,以此满足实现用户输入session最短的优化目标。 如下图所示: 最终,抽取线上点击日志超过百万条的随机query,每条query召回前N条候选POI。利用上述样本构造方案,最终生成千万级别的有效样本作为gbrank的训练样本。 特征方面,主要考虑了4种建模需求,每种需求都有对应的特征设计方案: 有多个召回链路,包括:不同城市、拼音召回。因此,需要一种特征设计,解决不同召回链路间的可比性。随着用户的不断输入,目标POI不是静态的,而是动态变化的。需要一种特征能够表示不同query下的动态需求。低频长尾query,无点击等后验特征,需要补充先验特征。LBS服务,有很强的区域个性化需求。不同区域用户的需求有很大不同。为实现区域个性化,做到千域千面,首先利用geohash算法对地理空间进行分片,每个分片都得到一串唯一的标识符。从而可以在这个标识符(分片)上分别统计特征。 详细的特征设计,如下表所示: 完成特征设计后,为了更好发挥特征的作用,进行必要的特征工程,包括尺度缩放、特征平滑、去position bias、归一化等。这里不做过多解释。 初版模型,下掉所有规则,在测试集上MRR 有5个点左右的提升,但模型学习也存在一些问题,gbrank特征学习的非常不均匀。树节点分裂时只选择了少数特征,其他特征没有发挥作用。 以上就是前面提到的,建模的第二个难题:模型学习的调优问题。具体来说就是如何解决gbrank特征选择不均匀的问题。接下来,我们详细解释下。 先看下,模型的特征重要度。如下图所示: 经过分析,造成特征学习不均衡的原因主要有: 交叉特征query-click的缺失程度较高,60%的样本该特征值为0。该特征的树节点分裂收益较小,特征无法被选择。然而,事实上,在点击充分的情况下,query-click的点击比city-click更接近用户的真实意图。对于文本相似特征,虽然不会缺失,但是它的正逆序比较低,因此节点分裂收益也比city-click低,同样无法被选择。综上,由于各种原因,导致树模型学习过程中,特征选择时,不停选择同一个特征(city-click)作为树节点,使得其他特征未起到应有的作用。解决这个问题,方案有两种: 方法一:对稀疏特征的样本、低频query的样本进行过采样,从而增大分裂收益。优点是实现简单,但缺点也很明显:改变了样本的真实分布,并且过采样对所有特征生效,无法灵活的实现调整目标。我们选择了方法二来解决。方法二: 调loss function。按两个样本的特征差值,修改负梯度(残差),从而修改该特征的下一轮分裂收益。例如,对于query-click特征非缺失的样本,学习错误时会产生loss,调loss就是给这个loss增加惩罚项loss_diff。随着loss的增加,下一棵树的分裂收益随之增加,这时query-click特征被选作分裂节点的概率就增加了。具体的计算公式如下式: 以上公式是交叉熵损失函数的负梯度,loss_diff 相当于对sigmod函数的一个平移。 差值越大,loss_diff越大,惩罚力度越大,相应的下一轮迭代该特征的分裂收益也就越大。 调loss后,重新训练模型,测试集MRR在初版模型的基础又提升了2个点。同时历史排序case的解决比例从40%提升到70%,效果明显。 写在最后Learning to Rank技术在高德搜索建议应用后,使系统摆脱了策略耦合、依靠补丁的规则排序方式,取得了明显的效果收益。gbrank模型上线后,效果基本覆盖了各频次query的排序需求。 目前,我们已经完成了人群个性化、个体个性化的建模上线,并且正在积极推进深度学习、向量索引、用户行为序列预测在高德搜索建议上的应用。 本文作者:高德技术小哥阅读原文 本文为云栖社区原创内容,未经允许不得转载。

July 10, 2019 · 1 min · jiezi

千亿级的数据难题优酷工程师怎么解决

阿里妹导读:优酷一天的日志量会达到千亿级别,面对如此大的数据样本,2017年5月,优酷完成了从Hadoop迁移到阿里云MaxCompute,实现计算消耗和储存的消耗呈下降趋势,得到了非常大的收益。今天,阿里数据技术专家门德亮给大家做个分享,从为什么要用MaxCompute,到优酷的业务场景下典型的方案及应用分析,聊聊迁移后对业务及平台的具体价值。本文内容根据演讲视频以及PPT整理而成,希望对你有所助益。 大家好,我是门德亮,很荣幸,我正好见证了优酷从没有MaxCompute到有的,这样一个历程,我们正好是在快到5年的时候,做了从Hadoop到MaxCompute的这样一个升级。 2016年5月到2019年5月优酷的发展历程。整个用户数,还有表的数据,实际上是呈指数式增长的。但是在2017年5月,当优酷完成了整个Hadoop迁移MaxCompute后,优酷的计算消耗,还有储存的消耗实际上是呈下降趋势的,整个迁移得到了非常大的收益。 下面说一下优酷的业务特点。 第一个特点是大数据平台整个的用户复杂度,不止是数据的同学和技术的同学在使用,还会包括一些BI同学,测试同学,甚至产品运营都可能去使用这个大数据的平台。 第二个特点就是业务复杂,优酷是一个视频网站,它有非常复杂的业务场景,从日志分类上,除了像页面浏览,还会有一些播放相关的数据、性能相关的数据。从整个的业务模式上,有直播、有会员、有广告、有大屏等这样一些非常不一样的场景。 第三个特点,就是数据量非常巨大,一天的日志量会达到千亿级别,这是一个非常庞大的数据量,而且会做非常复杂的计算。 第四个比较有意思,不管是小公司、大公司,对成本的意识是非常高的。优酷也是有非常严格的预算,包括在阿里集团内是有非常严格的预算系统的,但是我们也经常会去做一些重要的战役,像双十一战役,像我们暑期的世界杯战役,还有春节也会搞各种战役。这其实对计算资源的弹性要求是非常高的。 基于上面的优酷的业务特点,我整理了MaxCompute可以完美的支持我们业务的几个特点。 简单易用。完善的生态。性能非常强悍。资源使用非常弹性。第一个特点,简单易用。MaxCompute有一个非常完整的链路,不管是从数据开发,还是数据运维,包括数据集成,数据质量的管控,还有整个数据地图,数据安全。当年优酷从Hadoop迁到MaxCompute之后,我们最大的体会是不用经常自己半夜起来去维护集群了,不用去跑任务了,之前别人提一个需求过来,我可能要排几周,现在我可以告诉他,我给你马上跑一下,就可以出来了。包括之前像分析师BI还要登录客户端,写脚本,自己写调度,经常会说我的数据今天为什么没出来?包括高层看的数据,可能要到12点钟才能出来。而现在基本上所有重要的数据都会在7点钟产出,包括一些基本的业务需求,其实分析师或者产品,他们自己都可以实现了,不需要所有需求都提到数据这边。 第二个特点,完整的生态。优酷在2017年之前是完全基于Hadoop的生态,迁到MaxCompute之后,是基于阿里云提供的Serverless大数据服务的生态。大家可以在开源上看到的组件,在整个的MaxCompute上都是有的,而且比开源的要更好用、更简单。从架构图上可以看到,我们中间是MaxCompute,左侧依赖的Mysql、Hbase、ES、Redis这些都是由同步中心去做一个双向的同步。右侧会有资源管理、资源监控、数据监控,包括数据资产,还有一些数据规范。我们下层的数据输入,包括一些集团的采集工具,再往上边,有提供给开发人员用的DataWorks,包括一些命令行的工具,有提供给BI人员用的QuickBI及数据服务。 第三个特点,强悍的性能,MaxCompute支撑了优酷EB级的数据存储,千亿级的数据样本分析,包括千亿级的数据报表,10W级实例的并发、任务。这些在之前维护Hadoop的时候,是想都不敢想的。 第四个特点,资源使用的弹性。我们在2016年迁移之前,其实优酷的Hadoop集群规模已经达到了一千多台,这个当时还是一个比较大的规模。当时我们遇到了很多问题,包括像NameNode 这种内存的问题,机房没有办法再扩容的问题,当时是非常痛苦的,包括一些运维管理上面的问题。我们不断地去问运维要资源,运维说你们已经花了资源,多少钱。我们面临的问题是计算资源如何按需使用,夜里的作业很多,到了午后,整个集群都空下来了,没有人用,造成了浪费。其实MaxCompute完美地解决了这个问题。 第一个,它是按用量计费的,不是说给你多少台机器,就收你多少钱,是你用了多少资源收多少钱的,在成本上来说,比自己去维护集群,可能是一个砍半(降50%)的收益。 第二个,实际上MaxCompue计算资源是可以分时的,比如说生产队列,凌晨的时候会调高一些,保证报表能够尽快出来。到白天时候,让开发的计算资源高一些,可以让分析师、开发去临时跑一些数据,会更顺畅一些。 第三个,MaxCompute快速的扩容能力,比如说突然有一个比较强的业务需求,发现数据跑不动了,计算资源不够,所有的队列都堵死了,这个时候其实可以直接跟运维说一声,帮忙一键扩容,两秒钟敲一个命令就搞定了。这样,所有的资源可以迅速地消化下去。 这张图实际上是优酷,包括可能现在阿里集团内部一些非常典型的技术架构图。中间可以看到,MaxCompute在中间核心的位置,左侧主要是一个输入,右侧是一个输出的趋向,绿色的线是一个实时的链路,包括现在我们从整个的数据源上,比如DB也好或者服务器的本地日志Log也好,我们通过TT&Datahub存储到MaxCompute上面做分析。当然现在非常火的Flink实时计算,其实是作为一个实时处理的链路。 包括DB的同步,除了实时的链路,DB也会去通过按天/按小时,把数据同步到MaxCompute,数据计算结果也可以同步到Hbase、Mysql这种DB上面。再通过统一的服务层对应用提供服务。下面这个是机器学习Pai做的一些算法训练,再把训练的结果通过OSS传到一个算法的应用上面去。 这张图可能也是业界比较流行的一个数仓分层的图,因为我们这边是数据中台,所有的数据都是统一从ods层cdm层,然后ads层,去一层一层地往上去做精细,再到最上面,通过接口服务、文件服务、SQL服务,去提供多样化的服务。再往上面,提供对内的一些数据产品,对高管、对小二,可能还有一些对外的,比如说像优酷的播放数,包括热度这些对应用的数据。 这张图其实就是我们从Hadoop迁到MaxCompute平台上以来,两个非常经典的案例。我们通过数据中台对不同场景的用户打通,来去赋能到两个不同的场景,提升业务价值。 第二个,可能是内部的,我们通过优酷,还有集团内部的一些BU去做换量,我们通过统一的标签去做样本放大,把优酷的量导给其它的BU,把其它BU的量导给优酷,这样去达到一个共赢的效果。 这张图是大部分互联网公司不太会涉及到的,就是关于反作弊的问题。这个是我们在MaxCompute做的一个反作弊的架构,通过原始的数据去提取它的特征,然后再通过算法模型,包括机器学习、深度学习、图模型去支持流量反作弊、渠道反作弊等等。再通过业务场景上反作弊的监控工具,把监控到的作弊信息去打一个黑白样本,再把这个黑白样本跟特征一起来不断地迭代优化算法模型。同时针对算法模型,做一个模型的评价,不断来完善反作弊体系。 最后一点,其实还是跟成本相关,在日常使用中,一定是有小白用户或者一些新来的用户去错误地使用或者不在乎地使用一些资源,比如经常会有一些实习生或者是非技术的同学,如分析师,一个SQL消费比较高,这个其实是非常浪费资源,而且可能他一个任务,让其他所有人的任务都在这儿等着排队,实际上我们会去对整个的资源做一个治理。 从节点的粒度上,通过大数据来治理大数据,我们可以算出哪些表产出来之后,多少天没有被读取的,包括它的访问跨度可能没有那么大的,我们会去做下线或者去做治理,有一些业务场景可能并不是非常的重要或者它的时间要求没有那么高,比如一些算法训练,可以去做一些错峰的调度,保证水位不要太高。从MaxCompute任务的角度,可以算出哪些任务有数据倾斜、哪些数据可能会有相似计算,哪些任务需要去做MapJoin,哪些任务需要去做一些裁剪,然后来节省它的IO。还有哪些任务会去做暴力扫描,扫一个月、扫一年的数据,哪些数据可能会有这样一个数据膨胀,比如说它做了CUBE之类的这种复杂计算,一些算法模型的迭代;我们通过数据计算出来的这些迹象,去反推用户,来去提高它的这样一个数据的质量分,来去达到我们降低整个计算资源的目的。 在计算平台的角度,我们也持续地在使用MaxCompute推出的一些非常高级的用法,比如我们这边的HBO、Hash Cluster、Aliorc; 第一个,HBO就是我们基于一个历史的优化,这样避免了用户不知道怎么调参,我可能为了自己任务快一点,就调一个特别大的参数,这样的话,对集成的资源是非常浪费的。通过这个功能,用户就不用去调参数,集群自动调好,用户就写好自己业务逻辑就好了。 第二个,可能就是最近两年推出的Hash Cluster,当时在使用Hadoop的时候经常会出现,两个大表Join的时候计算不出来,这个Hash Cluster其实是一个优化的利器。大表跟小表Join,可以做一些分发,做一些优化。大表跟大表就涉及到一个排序的问题。这个Hash Cluster,实际上就是提前把数据排好,中间省掉很多计算环节,来达到效率提升的目的。 第三个,Aliorc,在一些固定的场景上面,可以稳定的提升20%的计算效率。 第四个,Session。对一些比较小的数据,直接就放到SSD或缓存里面,一个节点下游有100个叶子场景,是非常友好的,因为低延迟秒出结果。同时,优酷也在使用Lightning解决计算加速,这个是在一个计算架构方案上的优化,它是一个MPP的架构。 最后一页是存储的优化,因为像一些关键的原始数据或者是需要审计的数据是不能删的,永久不能删的。实际上就会造成我们数据存储的趋势是一直往上不减的,计算会在某一个时间点达到一个平衡。当前用这么多的计算资源,再往后,其实应该也不会再大涨了,比如说旧的业务逻辑下掉了,会换新的业务逻辑,这样会保持在一个相对平稳的波动上面。 但是储存,因为它有一些历史的数据是永远不能删的,可能会出现一直在增长,而且是指数级的。所以我们也会持续关注存储的情况,还是通过大数据来治大数据,去看哪些表的访问跨度比较小,来去做生命周期的优化,来去控制它的增速。还有刚才提到的Aliorc,实际上也是做压缩的。我们会去做一些大字段的拆分,来提高压缩的比例。 共建大数据生态,企业级大数据平台开发者版已正式发布,点击文末“阿里技术”阅读原文立即申请。 本文作者:阿里技术阅读原文 本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

July 10, 2019 · 1 min · jiezi

分布式服务架构下的混沌工程实践

本文来自阿里巴巴高可用架构团队高级开发工程师肖长军(花名穹谷)在 GIAC(全球互联网架构大会)上的分享,包含三部分内容:(阿里巴巴中间件公众号对话框发送“混沌工程”,获取分享PPT) 混沌工程的定义、价值、原则和流程;混沌工程如何在企业中落地,以及 ChaosBlade 和混沌实验平台 AHAS Chaos 架构设计;结合两个具体案例介绍了分布式服务下的混沌工程实践;大家好,我是来自阿里的肖长军,今天给大家分享混沌工程在分布式服务架构下的具体实践。 先做个自我介绍,我来自于阿里高可用架构团队,花名穹谷,做过分布式系统设计和 APM 研发相关工作,现在专注于高可用架构和混沌工程领域,是阿里云产品 AHAS 底层技术负责人和开源项目 ChaosBlade 负责人,并且承担集团内故障演练、突袭演练、攻防演练相关的研发工作。今天分享的内容包含以下三个方面。 先从混沌工程的定义、价值、原则和实施步骤介绍混沌工程,然后分享混沌工程如何在企业中落地,最后介绍分布式服务下混沌工程实践案例。我们先来看一下什么是混沌工程。 混沌工程理论一文中提到,其是在分布式系统上进行实验的学科,核心目的是提高生产环境中系统的容错性和可恢复性。尼采的这句话: "打不倒我的必使我强大",也很好的诠释了混沌工程反脆弱的思想。除了这里提到的目的,实施混沌工程还有哪些价值呢? 这里我从四个角色来说明,对于架构师来说,可以验证系统架构的容错能力,比如验证现在提倡的面向失败设计的系统;对于开发和运维,可以提高故障的应急效率,实现故障告警、定位、恢复的有效和高效性。对于测试来说,可以弥补传统测试方法留下的空白,之前的测试方法基本上是从用户的角度去做,而混沌工程是从系统的角度进行测试,降低故障复发率。对于产品和设计,通过混沌事件查看产品的表现,提升客户使用体验。所以说混沌工程面向的不仅仅是开发、测试,拥有最好的客户体验是每个人的目标。我们知道,系统发生故障的那一刻不是由你来选择的,而是那一刻选择你,你所能做,只能是为之做好准备。了解了混沌工程的价值,我们再来看一下实施混沌工程的一些原则。 前面 Vilas 老师也提到了,我这里重点来介绍一下这五项原则。第一条:”建立一个围绕稳定状态行为的假说“,其包含两个含义,一个是定义能直接反应业务服务的监控指标,需要注意的是这里的监控指标并不是系统资源指标,比如CPU、内存等,这里的监控指标是能直接衡量系统服务质量的业务监控。举个例子,一个调用延迟故障,请求的 RT 会变长,对上层交易量造成下跌的影响,那么这里交易量就可以作为一个监控指标。这条原则的另一个含义是故障触发时,对系统行为作出假设以及监控指标的预期变化。第二个指模拟生产环境中真实的或有理论依据的故障,第三个建议在生产环境中运行实验,但也不是说必须在生产环境中执行,只是实验环境越真实,混沌工程越有价值。持续的执行才能持续的降低故障复发率和提前发现故障,所以需要持续的自动化运行试验,最后一个,混沌工程很重要的一点是控制爆炸半径,也就是试验影响面,防止预期外的资损发生,后面会介绍控制爆炸半径的方式。依据这些指导原则可以更有效实施混沌工程,那么混沌工程的实施步骤是什么? 主要细分为这 8 步,指定试验计划,定义稳态指标,做出系统容错假设,执行实验,检查稳态指标,记录、恢复 实验,修复发现的问题,然后做持续验证。以上是对混沌工程理论相关的介绍,那么如何在企业中落地混沌工程呢? 我这里分为三个阶段,首先要坚定价值,因为你会受到来自多方面的挑战,其次引入混沌工程技术,最后在企业中推广混沌工程文化。在实施混沌工程之前,必须能说清楚混沌工程的价值,而且当受到挑战时,意志要坚定。 比如来自老板的挑战,”如何衡量混沌工程的价值?“,可以向老板表达出,”从故障的应急效率、故障复发率、线上故障发现数来衡量“等等。所以这些问题自己要想清楚。有了坚定的意志,就要开始落地,首先要先了解自己的系统。 这里系统成熟度分 5 个等级,也可以说是业务系统所处的阶段,列出了每个阶段适合什么故障场景。刚才也有听众问,”我的服务就是单点的,还有没有实施混沌工程的必要?“,有必要,可以实施简单的实验场景,比如 CPU 满载等,来验证监控告警,如果发现没有监控告警,就要去推动完善它,然后再推动服务多实例部署,通过混沌工程一级一级的去推动系统的演进,最终实现具有韧性的系统。根据系统成熟度了解自己系统所适合的场景,接下来就要选择一款合适的混沌实验工具。 这里列举了五个维度:场景丰富度、工具类型、易用性等。可以从 awesome-chaos-engineering github 项目查找或者从 CNCF Landscpage 中查看混沌实验工具。阿里今年开源的 ChaosBlade 也已经加入到 CNCF Landscape 中,后面会对此项目做重点介绍,先来看阿里混沌工程技术的演进。 2012 年阿里内部就上线了 EOS 项目,用于梳理分布式服务强弱依赖问题,同年进行了同城容灾的断网演练。 15 年 实现异地多活,16 年内部推出故障演练平台 MonkeyKing,开始在线上环境实施混沌实验,然后 18 年输出了 ACP 专有云产品 和 AHAS 公有云产品,其中 AHAS 旨在将阿里的高可用架构经验以产品的形式对外输出,服务于外部。19 年推出 ChaosBlade 项目,将底层的故障注入能力对外开源,同年也推出混沌实验平台专有云版本 AHAS Chaos,接下来重点介绍一下 ChaosBlade 项目。 ...

July 5, 2019 · 1 min · jiezi

如何带领团队攻城略地优秀的架构师这样做

阿里妹导读:架构师是一个既能掌控整体又能洞悉局部瓶颈并依据具体的业务场景给出解决方案的团队领导型人物。看似完美的“人格模型”背后,是艰辛的探索。今天,阿里巴巴技术专家九摩将多年经验,进行系统性地总结,帮助更多架构师在进阶这条路上走得更“顺畅”,姿态更“优雅”。架构师职责架构师不是一个人,他需要建立高效卓越的体系,带领团队去攻城略地,在规定的时间内完成项目。 架构师需要能够识别定义并确认需求,能够进行系统分解形成整体架构,能够正确地技术选型,能够制定技术规格说明并有效推动实施落地。 按 TOGAF 的定义,架构师的职责是了解并关注实际上关系重大但未变得过载的一些关键细节和界面,架构师的角色有:理解并解析需求,创建有用的模型,确认、细化并扩展模型,管理架构。 从业界来看对于架构师的理解可以大概区分为: 企业架构师:专注于企业总体 IT 架构的设计。IT 架构师-软件产品架构师:专注于软件产品的研发。IT 架构师-应用架构师:专注于结合企业需求,定制化 IT 解决方案;大部分需要交付的工作包括总体架构、应用架构、数据架构,甚至部署架构。IT 架构师-技术架构师:专注于基础设施,某种软硬件体系,甚至云平台,提交:产品建议、产品选型、部署架构、网络方案,甚至数据中心建设方案等。阿里内部没有在职位 title 上专门设置架构师了,架构师更多是以角色而存在,现在还留下可见的 title 有两个:首席架构师和解决方案架构师,其中解决方案架构师目前在大部分 BU 都有设置,特别是在阿里云和电商体系。 解决方案架构师 工作方式理解 了解和挖掘客户痛点,项目定义,现有环境管理;梳理明确高阶需求和非功能性需求;客户有什么资产,星环(阿里电商操作系统)/阿里云等有什么解决方案;沟通,方案建议,多次迭代,交付总体架构;架构决策。职责 1.从客户视图来看: 坚定客户高层信心:利用架构和解决方案能力,帮忙客户选择星环/阿里云平台的信心。解决客户中层问题:利用星环/阿里云平台服务+结合应用架构设计/解决方案能力,帮忙客户解决业务问题,获得业务价值。引领客户 IT 员工和阿里生态同学:技术引领、方法引领、产品引领。2.从项目视图看: 对接管理部门:汇报技术方案,进度;技术沟通。对接客户 PM,项目 PM:协助项目计划,人员管理等。负责所有技术交付物的指导。对接业务部门和需求人员:了解和挖掘痛点,帮忙梳理高级业务需求,指导需求工艺。对接开发:产品支持、技术指导、架构指导。对接测试:配合测试计划和工艺制定。配合性能测试或者非功能性测试。对接运维:产品支持,运维支持。对接配置&环境:产品支持。其他:阿里技术资源聚合。3.从阿里内部看: 销售方案支持;市场宣贯;客户需求Facade;解决方案沉淀。架构师职责明确了,那么有什么架构思维可以指导架构设计呢?请看下述的架构思维。 架构思维自顶向下构建架构 要点主要如下: 1.首先定义问题,而定义问题中最重要的是定义客户的问题。定义问题,特别是识别出关键问题,关键问题是对客户有体感,能够解决客户痛点,通过一定的数据化来衡量识别出来,关键问题要优先给出解决方案。 2.问题定义务必加入时间维度,把手段/方案和问题定义区分开来。 3.问题定义中,需要对问题进行升层思考后再进行升维思考,从而真正抓到问题的本质,理清和挖掘清楚需求;要善用第一性原理思维进行分析思考问题。 4.问题解决原则:先解决客户的问题(使命),然后才能解决自己的问题(愿景);务必记住不是强调我们怎么样,而是我们能为客户具体解决什么问题,然后才是我们变成什么,从而怎么样去更好得服务客户。 5.善用多种方法对客户问题进行分析,转换成我们产品或者平台需要提供的能力,比如仓储系统 WMS 可以提供哪些商业能力。 6.对我们的现有的流程和能力模型进行梳理,找到需要提升的地方,升层思考和升维思考真正明确提升部分。 7.定义指标,并能够对指标进行拆解,然后进行数学建模。 8.将抽象出来的能力诉求转换成技术挑战,此步对于技术人员来说相当于找到了靶子,可以进行方案的设计了,需要结合自底向上的架构推导方式。 9.创新可以是业务创新,也可以是产品创新,也可以是技术创新,也可以是运营创新,升层思考、升维思考,使用第一性原理思维、生物学(进化论--进化=变异+选择+隔离、熵增定律、分形和涌现)思维等哲科思维可以帮助我们在业务,产品,技术上发现不同的创新可能。可以说哲科思维是架构师的灵魂思维。 自底向上推导应用架构 先根据业务流程,分解出系统时序图,根据时序图开始对模块进行归纳,从而得到粒度更大的模块,模块的组合/聚合构建整个系统架构。 基本上应用逻辑架构的推导有4个子路径,他们分别是: 业务概念架构:业务概念架构来自于业务概念模型和业务流程;系统模型:来自于业务概念模型;系统流程:来自业务流程;非功能性的系统支撑:来自对性能、稳定性、成本的需要。效率、稳定性、性能是最影响逻辑架构落地成物理架构的三大主要因素,所以从逻辑架构到物理架构,一定需要先对效率、稳定性和性能做出明确的量化要求。 自底向上重度依赖于演绎和归纳。 如果是产品方案已经明确,程序员需要理解这个业务需求,并根据产品方案推导出架构,此时一般使用自底向上的方法,而领域建模就是这种自底向上的分析方法。 对于自底向上的分析方法,如果提炼一下关键词,会得到如下两个关键词: 1.演绎:演绎就是逻辑推导,越是底层的,越需要演绎: 从用例到业务模型就属于演绎;从业务模型到系统模型也属于演绎;根据目前的问题,推导出要实施某种稳定性措施,这是也是演绎。2.归纳:这里的归纳是根据事物的某个维度来进行归类,越是高层的,越需要归纳: 问题空间模块划分属于归纳;逻辑架构中有部分也属于归纳;根据一堆稳定性问题,归纳出,事前,事中,事后都需要做对应的操作,是就是根据时间维度来进行归纳。 领域驱动设计架构 大部分传统架构都是基于领域模型分析架构,典型的领域实现模型设计可以参考DDD(领域驱动设计),详细可以参考《实现领域驱动设计》这本书,另外《UML和模式应用》在领域建模实操方面比较好,前者偏理论了解,后者便于落地实践。 领域划分设计步骤: 1.对用户需求场景分析,识别出业务全维度 Use Case; 2.分析模型鲁棒图,识别出业务场景中所有的实体对象。鲁棒图 —— 是需求设计过程中使用的一种方法(鲁棒性分析),通过鲁棒分析法可以让设计人员更清晰,更全面地了解需求。它通常使用在需求分析后及需求设计前做软件架构分析之用,它主要注重于功能需求的设计分析工作。需求规格说明书为其输入信息,设计模型为其输出信息。它是从功能需求向设计方案过渡的第一步,重点是识别组成软件系统的高级职责模块、规划模块之间的关系。鲁棒图包含三种图形:边界、控制、实体,三个图形如下: ...

July 4, 2019 · 3 min · jiezi

案例精选-蘑菇街滴滴淘宝微信的组件化架构解析

导读:前段时间公司项目打算重构,准确来说应该是按之前的产品逻辑重写一个项目。在重构项目之前涉及到架构选型的问题,我和组里小伙伴一起研究了一下组件化架构,打算将项目重构为组件化架构。当然不是直接拿来照搬,还是要根据公司具体的业务需求设计架构。 在学习组件化架构的过程中,从很多高质量的博客中学到不少东西,例如蘑菇街李忠、casatwy、bang的博客。在学习过程中也遇到一些问题,在微博和QQ上和一些做iOS的朋友进行了交流,非常感谢这些朋友的帮助。 本篇文章主要针对于之前蘑菇街提出的组件化方案,以及casatwy提出的组件化方案进行分析,后面还会简单提到滴滴、淘宝、微信的组件化架构,最后会简单说一下我公司设计的组件化架构。 组件化架构的由来 随着移动互联网的不断发展,很多程序代码量和业务越来越多,现有架构已经不适合公司业务的发展速度了,很多都面临着重构的问题。 在公司项目开发中,如果项目比较小,普通的单工程+MVC架构就可以满足大多数需求了。但是像淘宝、蘑菇街、微信这样的大型项目,原有的单工程架构就不足以满足架构需求了。 就拿淘宝来说,淘宝在13年开启的“All in 无线”战略中,就将阿里系大多数业务都加入到手机淘宝中,使客户端出现了业务的爆发。在这种情况下,单工程架构则已经远远不能满足现有业务需求了。所以在这种情况下,淘宝在13年开启了插件化架构的重构,后来在14年迎来了手机淘宝有史以来最大规模的重构,将项目重构为组件化架构。 蘑菇街的组件化架构 原因 在一个项目越来越大,开发人员越来越多的情况下,项目会遇到很多问题。 业务模块间划分不清晰,模块之间耦合度很大,非常难维护。 所有模块代码都编写在一个项目中,测试某个模块或功能,需要编译运行整个项目。 耦合严重的工程 为了解决上面的问题,可以考虑加一个中间层来协调各个模块间的调用,所有的模块间的调用都会经过中间层中转。 中间层设计 但是发现增加这个中间层后,耦合还是存在的。中间层对被调用模块存在耦合,其他模块也需要耦合中间层才能发起调用。这样还是存在之前的相互耦合的问题,而且本质上比之前更麻烦了。 架构改进 所以应该做的是,只让其他模块对中间层产生耦合关系,中间层不对其他模块发生耦合。 对于这个问题,可以采用组件化的架构,将每个模块作为一个组件。并且建立一个主项目,这个主项目负责集成所有组件。这样带来的好处是很多的: 业务划分更佳清晰,新人接手更佳容易,可以按组件分配开发任务。 项目可维护性更强,提高开发效率。 更好排查问题,某个组件出现问题,直接对组件进行处理。 开发测试过程中,可以只编译自己那部分代码,不需要编译整个项目代码。 方便集成,项目需要哪个模块直接通过CocoaPods集成即可。 改进后的架构 进行组件化开发后,可以把每个组件当做一个独立的app,每个组件甚至可以采取不同的架构,例如分别使用MVVM、MVC、MVCS等架构,根据自己的编程习惯做选择。 MGJRouter方案 蘑菇街通过MGJRouter实现中间层,由MGJRouter进行组件间的消息转发,从名字上来说更像是“路由器”。实现方式大致是,在提供服务的组件中提前注册block,然后在调用方组件中通过URL调用block,下面是调用方式。 架构设计 MGJRouter组件化架构 MGJRouter是一个单例对象,在其内部维护着一个“URL -> block”格式的注册表,通过这个注册表来保存服务方注册的block,以及使调用方可以通过URL映射出block,并通过MGJRouter对服务方发起调用。 MGJRouter是所有组件的调度中心,负责所有组件的调用、切换、特殊处理等操作,可以用来处理一切组件间发生的关系。除了原生页面的解析外,还可以根据URL跳转H5页面。 在服务方组件中都对外提供一个PublicHeader,在PublicHeader中声明当前组件所提供的所有功能,这样其他组件想知道当前组件有什么功能,直接看PublicHeader即可。每一个block都对应着一个URL,调用方可以通过URL对block发起调用。 ifndef UserCenterPublicHeader_h#define UserCenterPublicHeader_h/ 跳转用户登录界面 /staticconstNSStringCTBUCUserLogin=@"CTB://UserCenter/UserLogin";/ 跳转用户注册界面 /staticconstNSStringCTBUCUserRegister=@"CTB://UserCenter/UserRegister";/* 获取用户状态 /staticconstNSString*CTBUCUserStatus=@"CTB://UserCenter/UserStatus";#endif在组件内部实现block的注册工作,以及block对外提供服务的代码实现。在注册的时候需要注意注册时机,应该保证调用时URL对应的block已经注册。 蘑菇街项目使用git作为版本控制工具,将每个组件都当做一个独立工程,并建立主项目来集成所有组件。集成方式是在主项目中通过CocoaPods来集成,将所有组件当做二方库集成到项目中。详细的集成技术点在下面“标准组件化架构设计”章节中会讲到。 MGJRouter调用 下面代码模拟对详情页的注册、调用,在调用过程中传递id参数。参数传递可以有两种方式,类似于Get请求在URL后面拼接参数,以及通过字典传递参数。下面是注册的示例代码: [MGJRouter registerURLPattern:@"mgj://detail"toHandler:^(NSDictionary*routerParameters) {// 下面可以在拿到参数后,为其他组件提供对应的服务NSStringuid = routerParameters[@"id"];}]; 通过openURL:方法传入的URL参数,对详情页已经注册的block方法发起调用。调用方式类似于GET请求,URL地址后面拼接参数。 [MGJRouter openURL:@"mgj://detail?id=404"]; 也可以通过字典方式传参,MGJRouter提供了带有字典参数的方法,这样就可以传递非字符串之外的其他类型参数,例如对象类型参数。 [MGJRouter openURL:@"mgj://detail"withParam:@{@"id": @"404"}]; ...

July 4, 2019 · 3 min · jiezi

数据人看Feed流架构实践

背景Feed流:可以理解为信息流,解决的是信息生产者与信息消费者之间的信息传递问题。我们常见的Feed流场景有:1 手淘,微淘提供给消费者的首页商品信息,用户关注店铺的新消息等2 微信朋友圈,及时获取朋友分享的信息3 微博,粉丝获取关注明星、大V的信息4 头条,用户获取系统推荐的新闻、评论、八卦 关于Feed流的架构设计,包括以上场景中的很多业内专家给出了相应的思考、设计和实践。本人是大数据方向出身的技术人,所在的团队参与了阿里手淘、微淘Feed流的存储层相关服务,我们的HBase/Lindorm数据存储产品在公有云上也支持着Soul、趣头条、惠头条等一些受欢迎的新媒体、社交类产品。我们在数据存储产品的功能、性能、可用性上的一些理解,希望对真实落地一个Feed流架构可以有一些帮助,以及一起探讨Feed流的未来以及数据产品如何帮助Feed流进一步迭代。 本文希望可以提供两点价值: 1 Feed流当前的主流架构以及落地方案2 一个初创公司如何选择Feed流的架构演进路径 业务分析Feed流参与者的价值信息生产者希望信息支持格式丰富(文字、图片、视频),发布流畅(生产信息的可用性),订阅者及时收到消息(时效性),订阅者不漏消息(传递的可靠性) 信息消费者希望及时收到关注的消息(时效性),希望不错过朋友、偶像的消息(传递的可靠性),希望获得有价值的消息(解决信息过载) 平台希望吸引更多的生产者和消费者(PV、UV),用户更长的停留时间,广告、商品更高的转化率 Feed信息传递方式一种是基于关系的消息传递,关系通过加好友、关注、订阅等方式建立,可能是双向的也可能是单向的。一种是基于推荐算法的,系统根据用户画像、消息画像利用标签分类或者协同过滤等算法向用户推送消息。微信和微博偏向于基于关系,头条、抖音偏向于基于推荐。 Feed流的技术难点互联网场景总是需要一定规模才能体现出技术的瓶颈,下面我们先看两组公开数据: 新浪微博为例,作为移动社交时代的重量级社交分享平台,2017年初日活跃用户1.6亿,月活跃用户近3.3亿,每天新增数亿条数据,总数据量达千亿级,核心单个业务的后端数据访问QPS高达百万级(来自 Feed系统架构与Feed缓存模型) 截止2016年12月底,头条日活跃用户7800W,月活跃用户1.75亿,单用户平均使用时长76分钟,用户行为峰值150w+msg/s,每天训练数据300T+(压缩后),机器规模万级别(来自 今日头条推荐系统架构设计实践) 上面还是两大巨头的历史指标,假设一条消息1KB那么千亿消息约93TB的数据量,日增量在几百GB规模且QPS高达百万,因此需要一个具备高读写吞吐,扩展性良好的分布式存储系统。用户浏览新消息期望百毫秒响应,希望新消息在秒级或者至少1分钟左右可见,对系统的实时性要求很高,这里需要多级的缓存架构。系统必须具备高可用,良好的容错性。最后这个系统最好不要太贵。 因此我们需要一个高吞吐、易扩展、低延迟、高可用、低成本的Feed流架构 主流架构图1是对Feed流的最简单抽象,完成一个从生产者向消费者传递消息的过程。 消息和关系首先,用户在APP侧获得的是一个Feed ID列表,这个列表不一定包含了所有的新消息,用户也不一定每一个都打开浏览,如果传递整个消息非常浪费资源,因此产生出来的消息首先生成主体和索引两个部分,其中索引包含了消息ID和元数据。其次一个应用总是存在关系,基于关系的传递是必不可少的,也因此一定有一个关系的存储和查询服务。 消息本身应该算是一种半结构化数据(包含文字,图片,短视频,音频,元数据等)。其读写吞吐量要求高,读写比例需要看具体场景。总的存储空间大,需要很好的扩展性来支撑业务增长。消息可能会有多次更新,比如内容修改,浏览数,点赞数,转发数(成熟的系统会独立一个counter模块来服务这些元数据)以及标记删除。消息一般不会永久保存,可能要在1年或者3年后删除。 综上,个人推荐使用HBase存储 HBase支持结构化和半结构化数据;具有非常好的写入性能,特别对于Feed流场景可以利用批量写接口单机(32核64GB)达到几十万的写入效率;HBase具备非常平滑的水平扩展能力,自动进行Sharding和Balance;HBase内置的BlockCache加上SSD盘可以提供ms级的高并发读;HBase的TTL特性可以自动的淘汰过期数据;利用数据复制搭建一个冷热分离系统,新消息存储在拥有SSD磁盘和大规格缓存的热库,旧数据存储在冷库。运用编码压缩有效的控制存储成本,见HBase优化之路-合理的使用编码压缩 对于关系服务,其写入操作是建立关系和删除关系,读取操作是获取关系列表,逻辑上仅需要一个KV系统。如果数据量较少可以使用RDS,如果数据量较大推荐使用HBase。如果对关系的QPS压力大可以考虑用Redis做缓存。 消息传递讲到Feed流一定会有关于推模式和拉模式的讨论,推模式是把消息复制N次发送到N个用户的收信箱,用户想看消息时从自己的收信箱直接获取。拉模式相反,生产者的消息写入自己的发信箱,用户想看消息时从关注的M个发信箱中收集消息。 推模式实现相对简单,时效性也比较好。拉模式要想获得好的性能需要多级的缓存架构。推模式重写,拉模式重读,Feed流场景下写的聚合效果要优于读,写可以大批量聚合。N越大,写入造成的数据冗余就越大。M越大,读消耗的资源越大。 随着业务的增长,推模式资源浪费会越发严重。原因在于两点:第一存在着大量的僵尸账号,以及大比例的非活跃用户几天或者半个月才登陆一次;第二信息过载,信息太多,重复信息太多,垃圾信息太多,用户感觉有用的信息少,消息的阅读比例低。这种情况下推模式相当一部分在做无用功,白白浪费系统资源。 是推?是拉?还是混合?没有最好的架构,只有适合的场景~ 基于关系的传递图6是纯推模式的架构,该架构有3个关键的部分 异步化。生产者提交消息首先写入一个队列,成功则表示发布成功,Dispatcher模块会异步的处理消息。这一点非常关键,首先生产者的消息发布体验非常好,不需要等待消息同步到粉丝的收信箱,发布延迟低成功率高;其次Dispatcher可以控制队列的处理速度,可以有效的控制大V账号造成的脉冲压力。多级队列。Dispatcher可以根据消费者的状态,信息的分类等划分不同的处理方式,分配不同的资源。比如对于大V账号的消息,当前活跃用户选择直接发送,保障消息的时效性,非活跃用户放入队列延迟发送。比如转发多的消息可以优先处理等。队列里的消息可以采用批量聚合写的方式提高吞吐。收信箱。假如有两亿用户,每个用户保留最新2000条推送消息。即便存储的是索引也是千亿的规模。收信箱一般的表结构为用户ID+消息序列 + 消息ID + 消息元数据,消息序列是一个递增的ID,需要存储一个偏移量表示上次读到的消息序列ID。用户读取最新消息 select * from inbox where 消息序列 > offset。 推荐使用HBase实现收信箱 HBase单机批量写能力在几十万并且可以水平扩展。HBase的高效前缀扫描非常适合读取最新的消息。HBase的TTL功能可以对数据定义生命周期,高效的淘汰过期数据。HBase的Filter过滤器和二级索引可以有效的实现Inbox的搜索能力。消费者收信箱hbase表设计如下,其中序列号要保证递增,一般用时间戳即可,特别高频情况下可以用一个RDS来制造序列号 Rowkey消息元数据列状态列其它列MD5(用户ID)+用户ID+序列号消息ID、作者、发布时间、关键字等已读、未读 图7是推拉结合的模式 增加发信箱,大V的发布进入其独立的发信箱。非大V的发布直接发送到用户的收信箱。其好处是解决大量的僵尸账号和非活跃账号的问题。用户只有在请求新消息的时候(比如登陆、下拉消息框)才会去消耗系统资源。发信箱的多级缓存架构。一个大V可能有百万粉丝,一条热点消息的传播窗口也会非常短,即短时间内会对发信箱中的同一条消息大量重复读取,对系统挑战很大。终态下我们可能会选择两级缓存,收信箱数据还是要持久化的,否则升级或者宕机时数据就丢失了,所以第一层是一个分布式数据存储,这个存储推荐使用HBase,原因和Inbox类似。第二层使用redis缓存加速,但是大V过大可能造成热点问题还需要第三层本地缓存。缓存层的优化主要包括两个方向:第一提高缓存命中率,常用的方式是对数据进行编码压缩,第二保障缓存的可用性,这里涉及到对缓存的冗余。 基于推荐的传递图8是基于推荐的模型,可以看出它是在推拉结合的模式上融合了推荐系统。 引入画像系统,保存用户画像、消息画像(简单情况下消息画像可以放在消息元数据中)。画像用于推荐系统算法的输入。引入了临时收信箱,在信息过载的场景中,非大V的消息也是总量很大,其中不免充斥着垃圾、冗余消息,所以直接进入用户收信箱不太合适。收信箱和发信箱都需要有良好的搜索能力,这是推荐系统高效运行的关键。Outbox有缓存层,索引可以做到缓存里面;Inbox一般情况下二级索引可以满足大部分需求,但如果用户希望有全文索引或者任意维度的检索能力,还需要引入搜索系统如Solr/ES 用户画像使用HBase存储 画像一般是稀疏表,画像总维度可能在200+甚至更多,但单个用户的维度可能在几十,并且维度可能随业务不断变化。那么HBase的Schema free和稀疏表的能力非常适合这个场景,易用且节省大量存储空间。对画像的访问一般是单行读,hbase本身单行Get的性能就非常好。阿里云HBase在这个方向上做了非常多的优化,包括CCSMAP、SharedBucketCache、MemstoreBloomFilter、Index Encoding等,可以达到平均RT=1-2ms,单库99.9% <100ms。阿里内部利用双集群Dual Service可以做到 99.9% < 30ms,这一能力我们也在努力推到公有云。hbase的读吞吐随机器数量水平扩展。临时收信箱使用云HBase HBase的读写高吞吐、低延迟能力,这里不再重复。HBase提供Filter和全局二级索引,满足不同量级的搜索需求。阿里云HBase融合HBase与Solr能力,提供低成本的全文索引、多维索引能力。初创公司的迭代路径在业务发展的初期,用户量和资源都没有那么多,团队的人力投入也是有限的,不可能一上来就搞一个特别复杂的架构,“够用”就行了,重要的是 可以快速的交付系统要稳定未来可以从容的迭代,避免推倒重来本人水平有限,根据自身的经验向大家推荐一种迭代路径以供参考,如有不同意见欢迎交流 ...

July 3, 2019 · 1 min · jiezi

大数据架构如何做到流批一体

阿里妹导读:大数据与现有的科技手段结合,对大多数产业而言都能产生巨大的经济及社会价值。这也是当下许多企业,在大数据上深耕的原因。大数据分析场景需要解决哪些技术挑战?目前,有哪些主流大数据架构模式及其发展?今天,我们都会一一解读,并介绍如何结合云上存储、计算组件,实现更优的通用大数据架构模式,以及该模式可以涵盖的典型数据处理场景。大数据处理的挑战现在已经有越来越多的行业和技术领域需求大数据分析系统,例如金融行业需要使用大数据系统结合 VaR(value at risk) 或者机器学习方案进行信贷风控,零售、餐饮行业需要大数据系统实现辅助销售决策,各种 IOT 场景需要大数据系统持续聚合和分析时序数据,各大科技公司需要建立大数据分析中台等等。 抽象来看,支撑这些场景需求的分析系统,面临大致相同的技术挑战: 业务分析的数据范围横跨实时数据和历史数据,既需要低延迟的实时数据分析,也需要对 PB 级的历史数据进行探索性的数据分析;可靠性和可扩展性问题,用户可能会存储海量的历史数据,同时数据规模有持续增长的趋势,需要引入分布式存储系统来满足可靠性和可扩展性需求,同时保证成本可控;技术栈深,需要组合流式组件、存储系统、计算组件和;可运维性要求高,复杂的大数据架构难以维护和管控;简述大数据架构发展Lambda 架构 Lambda 架构是目前影响最深刻的大数据处理架构,它的核心思想是将不可变的数据以追加的方式并行写到批和流处理系统内,随后将相同的计算逻辑分别在流和批系统中实现,并且在查询阶段合并流和批的计算视图并展示给用户。Lambda的提出者 Nathan Marz 还假定了批处理相对简单不易出现错误,而流处理相对不太可靠,因此流处理器可以使用近似算法,快速产生对视图的近似更新,而批处理系统会采用较慢的精确算法,产生相同视图的校正版本。 Lambda架构典型数据流程是(http://lambda-architecture.net/)): 所有的数据需要分别写入批处理层和流处理层;批处理层两个职责:(i)管理 master dataset (存储不可变、追加写的全量数据),(ii)预计算batch view;服务层对 batch view 建立索引,以支持低延迟、ad-hoc 方式查询 view;流计算层作为速度层,对实时数据计算近似的 real-time view,作为高延迟batch view 的补偿快速视图;所有的查询需要合并 batch view 和 real-time view;Lambda 架构设计推广了在不可变的事件流上生成视图,并且可以在必要时重新处理事件的原则,该原则保证了系统随需求演进时,始终可以创建相应的新视图出来,切实可行地满足了不断变化的历史数据和实时数据分析需求。 Lambda 架构的四个挑战 Lambda 架构非常复杂,在数据写入、存储、对接计算组件以及展示层都有复杂的子课题需要优化: 写入层上,Lambda 没有对数据写入进行抽象,而是将双写流批系统的一致性问题反推给了写入数据的上层应用;存储上,以 HDFS 为代表的master dataset 不支持数据更新,持续更新的数据源只能以定期拷贝全量 snapshot 到 HDFS 的方式保持数据更新,数据延迟和成本比较大;计算逻辑需要分别在流批框架中实现和运行,而在类似 Storm 的流计算框架和Hadoop MR 的批处理框架做 job 开发、调试、问题调查都是比较复杂的;结果视图需要支持低延迟的查询分析,通常还需要将数据派生到列存分析系统,并保证成本可控。流批融合的 Lambda 架构 针对 Lambda 架构的问题3,计算逻辑需要分别在流批框架中实现和运行的问题,不少计算引擎已经开始往流批统一的方向去发展,例如 Spark 和 Flink,从而简化lambda 架构中的计算部分。实现流批统一通常需要支持: ...

July 2, 2019 · 2 min · jiezi

Feed流系统设计总纲

简介差不多十年前,随着功能机的淘汰和智能机的普及,互联网开始进入移动互联网时代,最具代表性的产品就是微博、微信,以及后来的今日头条、快手等。这些移动化联网时代的新产品在过去几年间借着智能手机的风高速成长。 这些产品都是Feed流类型产品,由于Feed流一般是按照时间“从上往下流动”,非常适合在移动设备端浏览,最终这一类应用就脱颖而出,迅速抢占了上一代产品的市场空间。 Feed流是Feed + 流,Feed的本意是饲料,Feed流的本意就是有人一直在往一个地方投递新鲜的饲料,如果需要饲料,只需要盯着投递点就可以了,这样就能源源不断获取到新鲜的饲料。 在信息学里面,Feed其实是一个信息单元,比如一条朋友圈状态、一条微博、一条咨询或一条短视频等,所以Feed流就是不停更新的信息单元,只要关注某些发布者就能获取到源源不断的新鲜信息,我们的用户也就可以在移动设备上逐条去浏览这些信息单元。 当前最流行的Feed流产品有微博、微信朋友圈、头条的资讯推荐、快手抖音的视频推荐等,还有一些变种,比如私信、通知等,这些系统都是Feed流系统,接下来我们会介绍如何设计一个Feed流系统架构。 Feed流系统特点Feed流本质上是一个数据流,是将 “N个发布者的信息单元” 通过 “关注关系” 传送给 “M个接收者”。 Feed流系统是一个数据流系统,所以我们核心要看数据。从数据层面看,数据分为三类,分别是: 发布者的数据:发布者产生数据,然后数据需要按照发布者组织,需要根据发布者查到所有数据,比如微博的个人页面、朋友圈的个人相册等。关注关系:系统中个体间的关系,微博中是关注,是单向流,朋友圈是好友,是双向流。不管是单向还是双向,当发布者发布一条信息时,该条信息的流动永远是单向的。接收者的数据:从不同发布者那里获取到的数据,然后通过某种顺序(一般为时间)组织在一起,比如微博的首页、朋友圈首页等。这些数据具有时间热度属性,越新的数据越有价值,越新的数据就要排在最前面。针对这三类数据,我们可以有如下定义: 存储库:存储发布者的数据,永久保存。关注表:用户关系表,永久保存。同步库:存储接收者的时间热度数据,只需要保留最近一段时间的数据即可。设计Feed流系统时最核心的是确定清楚产品层面的定义,需要考虑的因素包括: 产品用户规模:用户规模在十万、千万、十亿级时,设计难度和侧重点会不同。关注关系(单向、双写):如果是双向,那么就不会有大V,否则会有大V存在。上述是选择数据存储系统最核心的几个考虑点,除此之外,还有一些需要考虑的:如何实现Meta和Feed内容搜索? 虽然Feed流系统本身可以不需要搜索,但是一个Feed流产品必须要有搜索,否则信息发现难度会加大,用户留存率会大幅下降。Feed流的顺序是时间还是其他分数,比如个人的喜好程度? 双向关系时由于关系很紧密,一定是按时间排序,就算一个关系很紧密的人发了一条空消息或者低价值消息,那我们也会需要关注了解的。单向关系时,那么可能就会存在大V,大V的粉丝数量理论极限就是整个系统的用户数,有一些产品会让所有用户都默认关注产品负责人,这种产品中,该负责人就是最大的大V,粉丝数就是用户规模。接下来,我们看看整个Feed流系统如何设计。Feed流系统设计上一节,我们提前思考了Feed流系统的几个关键点,接下来,在这一节,我们自顶向下来设计一个Feed流系统。 1. 产品定义第一步,我们首先需要定义产品,我们要做的产品是哪一种类型,常见的类型有: 微博类朋友圈类抖音类私信类接着,再详细看一下这几类产品的异同: 类型关注关系是否有大V时效性排序微博类单向有秒~分时间抖音类单向/无有秒~分推荐朋友圈类双向无秒时间私信类双向无秒时间上述对比中,只对比各类产品最核心、或者最根本特点,其他次要的不考虑。比如微博中互相关注后就是双向关注了,但是这个不是微博的立命之本,只是补充,无法撼动根本。 从上面表格可以看出来,主要分为两种区分: 关注关系是单向还是双向: 如果是单向,那么可能就会存在大V效应,同时时效性可以低一些,比如到分钟级别;如果是双向,那就是好友,好友的数量有限,那么就不会有大V,因为每个人的精力有限,他不可能主动加几千万的好友,这时候因为关系更精密,时效性要求会更高,需要都秒级别。排序是时间还是推荐: 用户对feed流最容易接受的就是时间,目前大部分都是时间。但是有一些场景,是从全网数据里面根据用户的喜好给用户推荐和用户喜好度最匹配的内容,这个时候就需要用推荐了,这种情况一般也会省略掉关注了,相对于关注了全网所有用户,比如抖音、头条等。确定了产品类型后,还需要继续确定的是系统设计目标:需要支持的最大用户数是多少?十万、百万、千万还是亿?用户数很少的时候,就比较简单,这里我们主要考虑 亿级用户 的情况,因为如果系统能支持亿级,那么其他量级也能支持。为了支持亿级规模的用户,主要子系统选型时需要考虑水平扩展能力以及一些子系统的可用性和可靠性了,因为系统大了后,任何一个子系统的不稳定都很容易波及整个系统。 2. 存储我们先来看看最重要的存储,不管是哪种同步模式,在存储上都是一样的,我们定义用户消息的存储为存储库。存储库主要满足三个需求: 可靠存储用户发送的消息,不能丢失。否则就找不到自己曾经发布到朋友圈状态了。读取某个人发布过的所有消息,比如个人主页等。数据永久保存。所以,存储库最重要的特征就是两点: 数据可靠、不丢失。由于数据要永久保存,数据会一直增长,所以要易于水平扩展。综上,可以选为存储库的系统大概有两类: 特点分布式NoSQL关系型数据库(分库分表)可靠性极高高水平扩展能力线性需要改造水平扩展速度毫秒无常见系统Tablestore、BigtableMySQL、PostgreSQL对于可靠性,分布式NoSQL的可靠性要高于关系型数据库,这个可能有违很多人的认知。主要是关系型数据库发展很长时间了,且很成熟了,数据放在上面大家放心,而分布式NoSQL数据库发展晚,使用的并不多,不太信任。但是,分布式NoSQL需要存储的数据量更多,对数据可靠性的要求也加严格,所以一般都是存储三份,可靠性会更高。目前在一些云厂商中的关系型数据库因为采用了和分布式NoSQL类似的方式,所以可靠性也得到了大幅提高。水平扩展能力:对于分布式NoSQL数据库,数据天然是分布在多台机器上,当一台机器上的数据量增大后,可以通过自动分裂两部分,然后将其中一半的数据迁移到另一台机器上去,这样就做到了线性扩展。而关系型数据库需要在扩容时再次分库分表。所以,结论是: 如果是自建系统,且不具备分布式NoSQL数据库运维能力,且数据规模不大,那么可以使用MySQL,这样可以撑一段时间。如果是基于云服务,那么就用分布式NoSQL,比如Tablestore或Bigtable。如果数据规模很大,那么也要用分布式NoSQL,否则就是走上一条不归路。如果使用Tablestore,那么存储库表设计结构如下: 主键列第一列主键第二列主键属性列属性列列名user_idmessage_idcontentother解释消息发送者用户ID消息顺序ID,可以使用timestamp。内容其他内容到此,我们确定了存储库的选型,那么系统架构的轮廓有了: 3. 同步系统规模和产品类型,以及存储系统确定后,我们可以确定同步方式,常见的方式有三种: 推模式(也叫写扩散):和名字一样,就是一种推的方式,发送者发送了一个消息后,立即将这个消息推送给接收者,但是接收者此时不一定在线,那么就需要有一个地方存储这个数据,这个存储的地方我们称为:同步库。推模式也叫写扩散的原因是,一个消息需要发送个多个粉丝,那么这条消息就会复制多份,写放大,所以也叫写扩散。这种模式下,对同步库的要求就是写入能力极强和稳定。读取的时候因为消息已经发到接收者的收件箱了,只需要读一次自己的收件箱即可,读请求的量极小,所以对读的QPS需求不大。归纳下,推模式中对同步库的要求只有一个:写入能力强。拉模式(也叫读扩散):这种是一种拉的方式,发送者发送了一条消息后,这条消息不会立即推送给粉丝,而是写入自己的发件箱,当粉丝上线后再去自己关注者的发件箱里面去读取,一条消息的写入只有一次,但是读取最多会和粉丝数一样,读会放大,所以也叫读扩散。拉模式的读写比例刚好和写扩散相反,那么对系统的要求是:读取能力强。另外这里还有一个误区,很多人在最开始设计feed流系统时,首先想到的是拉模式,因为这种和用户的使用体感是一样的,但是在系统设计上这种方式有不少痛点,最大的是每个粉丝需要记录自己上次读到了关注者的哪条消息,如果有1000个关注者,那么这个人需要记录1000个位置信息,这个量和关注量成正比的,远比用户数要大的多,这里要特别注意,虽然在产品前期数据量少的时候这种方式可以应付,但是量大了后就会事倍功半,得不偿失,切记切记。推拉结合模式:推模式在单向关系中,因为存在大V,那么一条消息可能会扩散几百万次,但是这些用户中可能有一半多是僵尸,永远不会上线,那么就存在资源浪费。而拉模式下,在系统架构上会很复杂,同时需要记录的位置信息是天量,不好解决,尤其是用户量多了后会成为第一个故障点。基于此,所以有了推拉结合模式,大部分用户的消息都是写扩散,只有大V是读扩散,这样既控制了资源浪费,又减少了系统设计复杂度。但是整体设计复杂度还是要比推模式复杂。用图表对比: 类型推模式拉模式推拉结合模式写放大高无中读放大无高中用户读取延时毫秒秒秒读写比例1:9999:1~50:50系统要求写能力强读能力强读写都适中常见系统Tablestore、Bigtable等LSM架构的分布式NoSQLRedis、memcache等缓存系统或搜索系统(推荐排序场景)两者结合架构复杂度简单复杂更复杂介绍完同步模式中所有场景和模式后,我们归纳下: 如果产品中是双向关系,那么就采用推模式。如果产品中是单向关系,且用户数少于1000万,那么也采用推模式,足够了。如果产品是单向关系,单用户数大于1000万,那么采用推拉结合模式,这时候可以从推模式演进过来,不需要额外重新推翻重做。永远不要只用拉模式。如果是一个初创企业,先用推模式,快速把系统设计出来,然后让产品去验证、迭代,等客户数大幅上涨到1000万后,再考虑升级为推拉集合模式。如果是按推荐排序,那么是另外的考虑了,架构会完全不一样,这个后面专门文章介绍。如果选择了Tablestore,那么同步库表设计结构如下: 主键列第一列主键第二列主键属性列属性列属性列列名user_idsequence_idsender_idmessage_idother解释消息接收者用户ID消息顺序ID,可以使用timestamp + send_user_id,也可以直接使用Tablestore的自增列。发送者的用户IDstore_table中的message_id列的值,也就是消息ID。通过sender_id和message_id可以到store_table中查询到消息内容其他内容,同步库中不需要包括消息内容。确定了同步库的架构如下: 4. 元数据前面介绍了同步和存储后,整个Feed流系统的基础功能完成了,但是对于一个完整Feed流产品而言,还缺元数据部分,接下来,我们看元数据如何处理: Feed流系统中的元数据主要包括: 用户详情和列表。关注或好友关系。推送session池。我们接下来逐一来看。 4.1 用户详情和列表 主要是用户的详情,包括用户的各种自定义属性和系统附加的属性,这部分的要求只需要根据用户ID查询到就可以了。 可以采用的分布式NoSQL系统或者关系型数据库都可以。 如果使用NoSQL数据库Tablestore,那么用户详情表设计结构如下: 主键顺序第一列主键属性列-1属性列-2......字段名user_idnick_namegenderother备注主键列,用于唯一确定一个用户用户昵称,用户自定义属性用户性别,用户自定义属性其他属性,包括用户自定义属性列和系统附加属性列。Tablestore是FreeSchema类型的,可以随时在任何一行增加新列而不影响原有数据。4.2 关注或好友关系 这部分是存储关系,查询的时候需要支持查询关注列表或者粉丝列表,或者直接好友列表,这里就需要根据多个属性列查询需要索引能力,这里,存储系统也可以采用两类,关系型、分布式NoSQL数据库。 如果已经有了关系型数据库了,且数据量较少,则选择关系型数据库,比如MySQL等。如果数据量比较大,这个时候就有两种选择: 需要分布式事务,可以采用支持分布式事务的系统,比如分布式关系型数据库。使用具有索引的系统,比如云上的Tablestore,更简单,吞吐更高,扩容能力也一并解决了。如果使用Tablestore,那么关注关系表设计结构如下: Table:user_relation_table 主键顺序第一列主键第一列主键属性列属性列Table字段名user_idfollow_user_idtimestampother备注用户ID粉丝用户ID关注时间其他属性列多元索引的索引结构: Table字段名user_idfollow_user_idtimestamp是否Index是是是是否enableSortAndAgg是是是是否store是是是查询的时候: 如果需要查询某个人的粉丝列表:使用TermQuery查询固定user_id,且按照timestamp排序。如果需要查询某个人的关注列表:使用TermQuery查询固定follow_user_id,且按照timestamp排序。当前数据写入Table后,需要5~10秒钟延迟后会在多元索引中查询到,未来会优化到2秒以内。除了使用多元索引外,还可以使用GlobalIndex。4.3 推送session池 ...

July 2, 2019 · 1 min · jiezi

浅析基于-Serverless-的前后端一体化框架

概述Serverless 是一种“无服务器架构”模式,它无需关心程序运行环境、资源及数量,只需要将精力聚焦到业务逻辑上的技术。基于 Serverless 开发 web 应用,架构师总是试图把传统的解决方案移植到 Serverless 上,虽然可以做到既拥有 Serverless 新技术带来的红利,又能维持住传统开发模式的开发体验。但是,Serverless 技术带来的改变可能不止这些,可能是颠覆整个传统 web 应用开发模式的革命性技术。 开发模式业务应用的开发模式发展是从一体到分裂为前后端,再到前后端融合为一体过程。 注意:后面所说的后端特指后端业务逻辑。 1、早期,一体 没有前后端的概念,那时候的应用都是单机版,所有的业务逻辑都写一起,开发人员不需要关心网络请求,这个时期的工程师完全专注于业务代码的开发。随着业务规模的增长,也暴露了很多问题: 高并发问题高可用问题说明:业务应用升级困难等一些问题,不是本篇文章所关心,所以就不一一列举出来。 2、现在,分裂 前端 + 高可用高并发运维裹挟着的后端业务逻辑: 说明:现在 Serverless 技术已经出现有一段时间了,不但没有解决开发体验的问题,反而带来更多开发体验问题,所以,在这里我并没有突出 Serverless 技术。 解决的问题: 高并发。通过分布式部署和多级负载均衡等技术解决了业务的高并发问题高可用。通过主从架构等技术解决了业务的高可用问题解决一个问题,带来一堆问题: 分裂业务应用。为了解决高可用和高并发,业务应用引入了分布式架构,通过负载均衡和主从模式来保证高可用和高并发问题,但是这种解决方案对业务应用是侵入式的,从而导致原本高内聚一体化的应用分裂成前端和后端污染业务代码。与高可用、高并发和运维相关的逻辑与后端业务逻辑交织在一起,让后端技术门槛变高,导致需要多个后端工程师才能掌握所有后端技术增加联调成本。前后端的联调工作做日益繁重,成了工程开发效率提升的瓶颈。新功能和 BUG 需要前后端工程师配合才能完成,你如果是全栈开发工程师,你肯定深有体会,很多 BUG 一看就知道是前端问题,还是后端问题不匹配的前后端技术发展速度,前端技术发展迅猛,后端技术相对稳定,前端只能被动的去适配后端,让前端最新的技术在使用体验上大打折扣。最理想的方式是前后端通盘考量,整体发展,不要出现本来后端只需要优化一行代码的事,让前端写一百行代码来实现限制了代码抽象。因为实现的是同一个业务需求,所以前后端代码有高度的相关性,如果我们能在前后端代码之上抽象代码逻辑,肯定能有很大的作为。同时,代码的开发和维护也有质的提升,前后端分裂导致我们不得不局限在前端或者后端进行代码的抽象,抽象出来的代码可能是片面而重复的增加技术复杂度。前后端分裂,前后端工程师各自为营,形成各自的技术栈,包括语言、工具和理念,导致单个工程师维护整个业务应用变得极度困难,也让前后端工程师排斥彼此的技术栈,随着时间的推移,技术栈差异越来越大,一个项目,不管多小,至少两位工程师以上,全栈开发工程师另当别论增加运维成本。需要专门的运维工程师来运维,虽然,现在通过技术手段降低了运维的成本,但是目前运维成本依然很高,难度依然很大这也是为什么创业小公司喜欢全栈开发工程师,因为在创业早期,高可用和高并发的需求不是那么迫切,因而运维也相对简单,使用全栈开发工程师,不仅缩短了项目交付周期,而且也降低了公司的运营成本,这对创业小公司是至关重要的。 3、未来,融合回到到一体 前端 + 后端 + Serverless + 平台服务   =>  业务应用 + Serverless + 平台服务: 说明:共享逻辑是前后端的共享逻辑,在过去,由于前后端分裂,是很难做到前后端层面的代码抽象的,前后端融合后,让这件事变得简单自然。 带来困惑: 前后端分工合作,不是很好吗?在过去,将一个复杂的问题分解成多个简单的子问题,高并发和高可用没法做到不侵入业务应用,这种确实是一种很好的解法,也是没办法中的办法。前后端分工合作带来的成本问题,越发凸显。现在 Serverless 透明的解决了高并发和高可用问题,那么我们为什么还需要从技术维度来划分,我们不是更加推荐按业务维度来划分吗?后端依然很难,驾驭前后端的门槛依然很高?后端代码逻辑虽然没有了高并发和高可用的裹挟,还是会很难,比如 AI。我相信类似这种很难的业务,现在可能有,未来一定会有相关的开发工具包或者平台服务为我们解决,让这些很难的技术平民化。难的技术交给专业的人解决。找回初心: 回归业务,前后端一体化。随着 Serverless 技术的出现,解决了高可用、高并发和运维问题,作为工程师的我们是不是应该回头看看,找回初心:专注于业务代码。让原本在一起的后端业务代码与前端代码再次融合。因此,前后端一体化难道不是我们失去已久的应用开发终极解决方案吗?现状Serverless 已经做到了以下两点: 工程师只需要关心业务逻辑上的技术拥有接近于传统应用开发体验(解决历史遗留问题,可能还有些距离)传统应用框架,食之无味,弃之可惜: 目前,很多用户已经感知到了 Serverless 带来的高可用、高并发和免运维的好处,用户能够很自然的想到如果能将现有的开发框架移植到 Serverless 上,那就太好不过了。Serverless 平台很自然会提供现有框架的移植方案。解决的问题是将传统的解决方案移植到 Serverless 上,让用户在 Serverless 上拥有传统的开发体验应用框架找回初心: ...

July 2, 2019 · 1 min · jiezi

TiDB-30-GA-Release-Notes

Overview2019 年 6 月 28 日,TiDB 发布 3.0 GA 版本,对应的 TiDB Ansible 版本为 3.0.0。相比于 V2.1,V3.0.0 版本在以下方面有重要改进: 稳定性方面,显著提升了大规模集群的稳定性,集群支持 150+ 存储节点,300+ TB 存储容量长期稳定运行。易用性方面有显著的提升,降低用户运维成本,例如:标准化慢查询日志,制定日志文件输出规范,新增 EXPLAIN ANALYZE,SQL Trace 功能方便排查问题等。性能方面,与 2.1 相比,TPC-C 性能提升约 4.5 倍,Sysbench 性能提升 50%+。 因支持 View,TPC-H 50G Q15 可正常运行。新功能方面增加了窗口函数、视图(实验特性)、分区表、插件系统、悲观锁(实验特性)、SQL Plan Management 等特性。TiDB新功能 新增 Window Function,支持所有 MySQL 8.0 中的窗口函数,包括 NTILE,LEAD,LAG、PERCENT_RANK、NTH_VALUE、CUME_DIST、FIRST_VALUE、LAST_VALUE、RANK、DENSE_RANK、ROW_NUMBER 函数新增 View 功能(实验特性)完善 Table Partition 功能: Range PartitionHash Partition新增插件系统,官方提供 IP 白名单(企业版特性),审记日志(企业版特性)等插件新增 SQL Plan Management 功能,通过绑定 SQL 执行计划确保查询的稳定性(实验特性)SQL 优化器 优化NOT EXISTS 子查询,转化为 Anti Semi Join 提升性能优化 Outer Join 常量传播,新增 Outer Join 消除优化规则,避免无效计算,提升性能优化 IN 子查询,先聚合后执行 Inner Join,提升性能优化 Index Join,适应更多的场景,提升性能优化 Range Partition 的 Partition Pruning 优化规则,提升性能优化 _tidb_rowid 查询逻辑,避免全表扫描,提升性能当过滤条件中包含相关列时,在抽取复合索引的访问条件时尽可能多地匹配索引的前缀列,提升性能利用列之间的顺序相关性,提升代价估算准确度基于统计信息的贪心算法及动态规划算法改进了 Join Order,提升多表关联的执行速度新增 Skyline Pruning,利用规则防止执行计划过于依赖统计信息,提升查询的稳定性提升单列索引上值为 NULL 时行数估算准确度新增 FAST ANALYZE,通过在各个 Region 中随机采样避免全表扫描的方式提升统计信息收集性能新增单调递增的索引列增量 Analyze 功能,提升统计信息收集性能支持 DO 语句中使用子查询支持在事务中使用 Index Join优化 prepare/execute,支持不带参数的 DDL 语句修改变量 stats-lease 值为 0 时系统的行为,使其自动加载统计新增导出历史统计信息功能新增导入导出列的关联性信息功能SQL 执行引擎 ...

June 29, 2019 · 3 min · jiezi

干货看云原生时代阿里云的四个最

云原生已经成为 IT 领域最热的词之一。到底有多火,大家感受一下:2015 年在旧金山召开的首届 KubeCon 只有 200 余参会者,而今年第二次在中国举办的KubeCon迎来了3000+现场观众,遍布全球的线上关注开者则更是不计其数。Gartner最近发布报告表示云原生时代已来,在未来三年中将有75%的全球化企业将在生产中使用容器化的应用。 作为云原生技术与应用的领先企业,阿里云在今年的 KubeCon + CloudNativeCon 大会上为全球企业和开发者分享了26场行业趋势和技术演讲。 阿里云智能容器平台负责人丁宇指出: 云原生正在重塑整个软件生命周期,容器、Kuberentes、云原生成为云时代的三个重要标准。阿里云将继续加大云原生技术栈产品体系的研发,并持续回馈开源社区,与生态合作伙伴一起,共同推动云原生标准制定以及应用的落地。 9年技术沉淀,阿里云云原生的四个“最”阿里巴巴是国内最早布局云原生技术的公司之一,丁宇在 26 日的主题演讲中表示:“早在 2011年,阿里巴巴就率先开始了容器化进程,开启了中国公司将云原生技术体系在电商、金融、制造等领域中大规模应用的先河。” 历经9年技术沉淀,阿里云成为国内唯一进入 Gartner《公有云容器服务竞争格局》报告的企业。今年 3 月,阿里云智能总裁张建锋表示,未来 1-2 年内,阿里巴巴要实现 100% 的业务跑在公共云之上,并且继续大力投入云原生技术的研发。 最丰富的云原生产品家族经过 9 年的内部技术实践,阿里云已拥有国内最丰富的云原生产品家族,覆盖八大类别 20 余款产品,涵盖底层基础设施、数据智能、分布式应用等,可以满足不同行业场景的需求。 目前阿里巴巴集团内部电商、城市大脑等核心业务已经大规模使用云原生技术,去年双 11,阿里云完成了 10 分钟 1000 台以上服务器的快速部署,容器部署规模达到百万级,两年内实现全部上云,是全球最大规模的云原生应用实践。 最全面的云原生开源贡献 阿里云一直致力于回馈社区、积极拥抱开源,是国内在云原生领域的开源贡献最全面的科技公司,涵盖编排调度、作业管理、无服务器框架等: ●主导维护 etcd、containerd、dragonfly 等多个 CNCF 明星项目的发展,已有超过 10 个项目进入 CNCFlandscape; ●项目建设层面:积极建设 Kubernetes 项目,贡献量位居全球前 10; ●开源生态支持:加入 CNCF、OCI、CDF 等基金会,成为多个基金会的顶级会员,共建开源生态。 今年 1 月,阿里云资深技术专家李响成为首个入选全球顶级开源社区 CNCF 技术监督委员会的中国工程师,致力于推动云原生技术的落地。 最大的容器集群和客户群体除了支持集团内部应用规模化运维,阿里云云原生技术还向全社会输出。阿里云 ACK(容器服务)遍布全球 18 个 region,拥有国内最大公共云容器集群以及客户群体。 ...

June 28, 2019 · 1 min · jiezi

谈谈接入各种第三方推送的技术方案和坑点

在移动互联网时代,为了运营好一个APP,消息推送是一个优质廉价的渠道。消息推送的使用场景简单来说,可以包括运营类的消息推送,如活动推广期间的推送等,还包括通知类的消息推送,如社交场景中的新消息提醒等。对于APP来说,消息推送能够起到内容告知、提高日活,甚至召回用户的作用。那么如何接入第三方推送平台呢?本篇文章中,网易云信资深研发工程师将和大家聊聊接入各种第三方推送平台的技术方案,分享接入推送平台的一些实用经验。 如何接入第三方推送1、 推送的一般流程推送是一种服务器主动push消息到设备端的行为,因此依赖于设备端和服务器的长连接。整体的架构和流程如下: 具体如下:1) 设备和推送服务器建立长连接2) 设备会根据某些规则生成或从推送服务器获取到一个DeviceToken,推送服务器可以根据DeviceToken定位到具体的设备3) 设备会上报DeviceToken到应用服务器(由应用自己完成)4) 应用服务器根据需要调用推送的服务端接口发起推送5) 推送服务器收到推送请求,根据请求中的DeviceToken定位到具体的设备,下发推送通知6) 设备收到推送消息,可以进行通知栏弹窗或者其他行为2、 IOS苹果官方提供了APNS推送,有很高的推送送达率。早先的APNS推送提供了一套基于TCP协议的接口,但是该接口使用方式比较复杂,稍有不慎就会导致推送失败,但调用方还误以为推送成功。后来苹果又提供了一套新的基于HTTP2协议的接口,新接口的一个好处是可以追踪到每个推送请求是被APNS服务器拒绝了还是成功了,再也不用去猜请求到底是被苹果服务器给丢了还是接受了。3、 安卓谷歌官方最早提供了GCM推送,后来又推出了FCM推送来代替GCM,但由于国内的环境不适合使用,因此各个手机厂商又相继推出了各自的推送,推送的原理都是类似的,都是依赖于设备和推送服务器的长连接,但是厂商推送的优势在于这样的长连接可以和自己的手机系统绑定到一起,从而可以不同应用共享同一条长连接,节省了心跳的流量消耗,并且这样的系统级长连接可以不用担心应用被杀导致的应用内长连接断连导致消息推送不可达。目前已经推出厂商推送的包括小米、华为、魅族、OPPO等,FCM也可以算安装了谷歌服务的设备的系统级推送。不同于IOS,安卓阵营的推送服务器接口都是HTTPS接口,并且通过SecretKey的方式来进行安全校验。 一点经验1、 DeviceToken的管理我们知道DeviceToken标识了一台具体的设备,但是推送服务本身是不知道应用本身的账号体系的,因此同一个APP,假设注销了A账号,改用B账号登录,此时DeviceToken一般来说是没有变化的,此时应用服务器需要去标识A账号的该设备属于注销状态,不然一条针对A账号的推送消息就会被B账号收到。2、 应用被卸载的情况应用被卸载的时候(这时候登录的A账号),应用本身感知不到,此时针对A账号的该设备的推送还是会发出去,推送服务器收到推送消息,找不到对应的设备,此时没有问题,只是会消耗一些资源。假设此时设备上的应用又重新安装了,然后登录了另一个账号B,假设DeviceToken没有变化,此时针对A账号的推送将会被B账号收到。上面这种情况出现的前提条件是DeviceToken没有发生变化,测试发现华为推送存在这个问题(经过询问华为推送技术支持,2018年3月之后的设备不存在该问题),其他推送没有。为了解决这个问题,服务器必须自己管理DeviceToken-用户账号的映射关系,并在发现有DeviceToken冲突的情况下去把老的账号设置为注销状态。3、 IM场景下推送时机问题IM场景下,应用服务器有自己长连接服务,此时第三方推送服务的作用是利用第三方厂商推送的系统级长连接来提高消息推送的送达率。首先对于IOS端,应用无法常驻后台,我们会在应用切换前后台的时候通过IM长连接发送一个标记位,服务器会在设备离线或者处于后台的情况下触发APNS推送,从而减少设备在前台情况下APNS推送的流量消耗。而对于安卓端,服务器会在设备处于离线的情况下触发第三方推送,否则会走IM长连接下发通知,当设备处于后台但还活着的时候,会在收到消息之后主动弹窗以便提醒用户有新消息。对于安卓端还有一个场景是这样的,安卓端在后台的某个时刻进程死了,此时过来一条需要推送的消息,服务器发现设备处于离线状态,尝试调用第三方推送(可能有也可能没有)。过了一会进程自己活回来了,重新连接到了IM服务器,拿到了未读消息,此时一般的逻辑下,进程会主动弹窗告知有消息到达,造成设备端的通知栏有两条推送。为了解决这个问题,需要IM服务器在设备重连的时候下发未读消息是否需要弹窗的信息。 以上就是网易云信对于第三方推送平台技术方案的介绍和经验分享。想要阅读更多技术干货文章,欢迎关注网易云信博客。了解网易云信,来自网易核心架构的通信与视频云服务。__网易云信(NeteaseYunXin)是集网易18年IM以及音视频技术打造的PaaS服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端SDK和云端OPEN API,即可快速实现包含IM、音视频通话、直播、点播、互动白板、短信等功能。

June 28, 2019 · 1 min · jiezi

蚂蚁金服-Service-Mesh-落地实践与挑战-GIAC-实录

本文整理自 GIAC(GLOBAL INTERNET ARCHITECTURE CONFERENCE)全球互联网架构大会,蚂蚁金服平台数据技术事业群技术专家石建伟(花名:卓与)的分享。分享基于 Service Mesh 的理念,结合蚂蚁金服内部实际场景,将中间件、数据层、安全层等能力从应用中剥离出来后下沉至独立的 Sidecar SOFAMosn 中,结合 Kubernetes 运维体系,提供应用无感知的情况下升级基础设施层能力的案例。 本次分享将从以如下次序展开进行: 蚂蚁金服当前的服务化现状在看蚂蚁金服的服务化架构之前我们先从一个简单的服务化调用示例说起,下图是 SOFARPC 基本原理: 图1. SOFARPC 基本原理 我们从上图可以看出,构建一个服务化框架需要有服务注册中心,有服务定义,调用方和服务提供方使用相同的服务定义来互相通讯。通过服务注册中心,调用方可以直接订阅到服务提供方的地址,采用点对点的方式直接发起请求。客户端内可实现服务发现、路由寻址、负载均衡、限流熔断等能力来增强服务通讯能力。通过我们开源的 SOFARPC、SOFARegistry、SOFABoot,用户已经可以直接构建起微服务体系,助力业务发展。 蚂蚁金服发展至今,双 11 系统需要应对的交易洪峰逐年递增: 图2. 历年双 11 交易额与峰值数据 每秒 26.5 万笔交易是 2017 年双 11 的峰值数据,这个数据背后有非常复杂的架构支持,LDC 单元化架构是蚂蚁金服沉淀多年的核心架构,依靠这个架构实现每年峰值交易量飞速增长下系统依然能平滑渡过。我们来简要看下 LDC 架构: 图3. LDC 架构示例 上图摘自 金融级分布式架构 中的 素描单元化 一文,这里不详细展开。LDC 的单元化架构给应用的服务化带来更多的规范与抽象,服务路由中需要考虑单元间的调用,跨机房调用等更多场景。这里主要希望表达的是 LDC 架构给 RPC 调用带来更高的复杂度。 服务化痛点中间件版本升级在上面介绍背景时,有介绍到目前 LDC 架构下服务调用的复杂度,这些复杂度目前是直接体现在应用的代码中。对于业务同学来讲,一个应用的关注重点是如何实现业务逻辑,至于高可用、容灾等能力更多是整体架构层面会考虑的点。应用内通过引入 RPC 的 jar 包即可获得 LDC 架构下服务调用各种能力的支撑,带来便利的同时也可以看到这种模式的缺点: 图4. APP 业务与 SDK 组成部分应用内除业务逻辑之外,由中间件的 SDK 引入大量外部依赖,来完成服务发现、路由寻址、负载均衡、限流熔断、序列化、通讯等能力,每个组件的引入都可能带来稳定性风险,以及更高的升级成本。 ...

June 28, 2019 · 3 min · jiezi

用Flink取代Spark-Streaming知乎实时数仓架构演进

作者 | 知乎数据工程团队 “数据智能” (Data Intelligence) 有一个必须且基础的环节,就是数据仓库的建设,同时,数据仓库也是公司数据发展到一定规模后必然会提供的一种基础服务。从智能商业的角度来讲,数据的结果代表了用户的反馈,获取结果的及时性就显得尤为重要,快速的获取数据反馈能够帮助公司更快的做出决策,更好的进行产品迭代,实时数仓在这一过程中起到了不可替代的作用。 本文主要讲述知乎的实时数仓实践以及架构的演进,这包括以下几个方面: 实时数仓 1.0 版本,主题:ETL 逻辑实时化,技术方案:Spark Streaming。实时数仓 2.0 版本,主题:数据分层,指标计算实时化,技术方案:Flink Streaming。实时数仓未来展望:Streaming SQL 平台化,元信息管理系统化,结果验收自动化。实时数仓 1.0 版本1.0 版本的实时数仓主要是对流量数据做实时 ETL,并不计算实时指标,也未建立起实时数仓体系,实时场景比较单一,对实时数据流的处理主要是为了提升数据平台的服务能力。实时数据的处理向上依赖数据的收集,向下关系到数据的查询和可视化,下图是实时数仓 1.0 版本的整体数据架构图。 第一部分是数据采集,由三端 SDK 采集数据并通过 Log Collector Server 发送到 Kafka。第二部分是数据 ETL,主要完成对原始数据的清洗和加工并分实时和离线导入 Druid。第三部分是数据可视化,由 Druid 负责计算指标并通过 Web Server 配合前端完成数据可视化。 其中第一、三部分的相关内容请分别参考:知乎客户端埋点流程、模型和平台技术,Druid 与知乎数据分析平台,此处我们详细介绍第二部分。由于实时数据流的稳定性不如离线数据流,当实时流出现问题后需要离线数据重刷历史数据,因此实时处理部分我们采用了 lambda 架构。 Lambda 架构有高容错、低延时和可扩展的特点,为了实现这一设计,我们将 ETL 工作分为两部分:Streaming ETL 和 Batch ETL。 Streaming ETL这一部分我会介绍实时计算框架的选择、数据正确性的保证、以及 Streaming 中一些通用的 ETL 逻辑,最后还会介绍 Spark Streaming 在实时 ETL 中的稳定性实践。 计算框架选择在 2016 年年初,业界用的比较多的实时计算框架有 Storm 和 Spark Streaming。Storm 是纯流式框架,Spark Streaming 用 Micro Batch 模拟流式计算,前者比后者更实时,后者比前者吞吐量大且生态系统更完善,考虑到知乎的日志量以及初期对实时性的要求,我们选择了 Spark Streaming 作为实时数据的处理框架。 ...

June 28, 2019 · 3 min · jiezi

坚持探索与落地并重阿里巴巴云原生之路全景揭秘

阿里妹导读:阿里云已经成功地规模化落地云原生,26日的 KubeCon 大会上,CNCF TOC 和阿里云资深技术专家李响发表主题演讲,分享了阿里巴巴在规模扩展、可靠性、开发效率、迁移策略等方面的经验,并探讨云原生的落地及应对若干技术挑战。为什么要做云原生?云原生究竟能带来什么价值?从最初的独自摸索到如今拥抱开源回馈社区,阿里巴巴走过了怎样的云原生旅程?又有哪些技术心得?今天,将全部分享出来。 多年沉淀,坚持探索与落地并重阿里巴巴从2011年开始通过容器实践云原生技术体系,在整个业界都还没有任何范例可供参考的大背境下,逐渐摸索出了一套比肩全球一线技术公司并且服务于整个阿里集团的容器化基础设施架构。这个探索历程虽然孤独,但却被始终如一的坚持至今。这正是在这个孤注一掷的技术探索与奋进的过程中,阿里巴巴的技术团队完整的经历了云原生技术浪潮里的所有关键节点,不仅成为了这次技术革命的重要见证者,也逐渐成为中国云原生技术体系当之无愧的推动者与引领者之一。 阿里的体量大、业务复杂,推动云原生要找到合适的切入点。在双十一成本压力的推动下,资源成本与效率优化成了阿里云原生的起点。 阿里从容器入手,研究低成本虚拟化与调度技术:提供灵活、标准的部署单元;将静态资源分配更换为动态按需调度,进一步提升部署效率,解决资源碎片化问题,提高部署密度;通过存储网络虚拟化和存储计算分离等技术,增强任务的可迁移性,进一步提高了资源的可靠性,降低了资源成本。 在资源成本的推动下,阿里完成了全面容器化,资源分配也被高效调度平台接管。阿里的云原生并未止步于此。提高研发效率与加快迭代周期是推动阿里业务增强的秘密武器。阿里希望通过云原生让开发者效率更高。 为了降低应用部署难度,提高部署自动化程度,阿里开始采用 Kubernetes 作为容器编排平台,并且持续推动 Kubernetes 的性能与可扩展性。具体 Kubernetes,阿里持续对研发、部署流程进行改进。为了构建更云原生化的 CI/CD,进一步做到标准化和自动化,从研发到上线流程,阿里引入了诸如 Helm 的应用标准化管理,也尝试了 GitOps 这样的部署流程,还推动了 PaaS 层的面向终态自动化改造。于此同时,阿里也开始探索服务网格,致力于进一步提高服务治理的普适性与标准性,降低开发者采用门槛,进一步推动微服务在多语言和多环境下的普及。 今年,阿里也展开了全站上云。经过云原生的探索与改造,阿里基础架构体系是现代化和标准化的。利用容器技术,应用与宿主机运行时完成了解耦;利用 Kubernetes 对 Pod 与 Volume 等的抽象,完成了对多种资源实现的统一化;通过智能调度与 PaaS 平台,让自动迁移应用,修复不稳定因素成为了可能,阿里通过云原生技术大大降低了上云的难度。 在这个提高资源和人员效率的过程中,阿里巴巴的整个基础设施也变得更加开放,连通开源生态,在交流互动中不断吸收和贡献好的理念、技术、思想。如今,阿里云不仅支撑着中国最大的云原生应用双11,而且拥有国内最大的公共云集群和镜像仓库。作为唯一入选 Gartner 的公有云容器服务竞争格局的厂商,阿里云也积累了最为丰富和宝贵的客户实践。 追求极致,优化扩展性和规模性弹性和规模性,这是支撑阿里巴巴各种类型的复杂场景以及流量高峰的关键因素。 经过不断打磨,阿里巴巴在 Kubernetes 规模与性能上取得了显著的成果:将存储object 的数量提升25倍,支持的节点数从5000提升到上万,在端到端调度延迟从5s变为100ms等等。其中有不少工作在阿里巴巴和社区中共同开展,而这些研发成果都已经贡献给社区,我们期望其他企业及开发者也可以享受阿里巴巴规模所带来的技术红利。 阿里巴巴持续优化性能,可以分为以下四个维度:工作负载追踪、性能分析、定制化调度、大规模镜像分发。首先对工作负载调度有完整的追踪、重放机制,其次将所有性能问题的进行细致分析,逐一攻克技术瓶颈。Kubernetes 本身的可定制性很强,阿里巴巴针对自身业务场景沉淀了定制化的调度能力和镜像分发系统。开源Dragonfly 项目脱胎于双十一,具备极强的镜像分发能力。数十个超级集群,每个超级集群具有数万节点,数百万的容器。 阿里巴巴落地 Kubernetes 可以分为三个阶段:首先通过 Kubernetes 提供资源供给,但是不过多干扰运维流程,这系统容器是富容器,将镜像标准化与轻量级虚拟化能力带给了上面的 PaaS 平台。第二步,通过 Kubernetes controller 的形式改造PaaS 平台的运维流程,给 PaaS 带来更强的面向终态的自动化能力。最后把运行环境等传统重模式改成原生容器与 pod 的轻量模式,同时将 PaaS 能力完全移交给Kubernetes controller,从而形成一个完全云原生的架构体系。 如何解决云原生的关键难点阿里巴巴云原生的探索,起步于自研容器和调度系统,到如今拥抱开源的标准化技术。对于当下开发者的建议是:如果想构建云原生架构,建议直接从 Kubernetes 入手即可。一方面,Kubernetes 为平台建设者而生,已经成为云原生生态的中流砥柱,它不仅向下屏蔽了底层细节,而且向上支撑各种周边业务生态;另一方面,更重要的是社区中有着越来越多围绕 Kubernetes 构建的开源项目,比如Service Mesh、Kubeflow。 ...

June 28, 2019 · 1 min · jiezi

分布式系统设计模式

layout: posttitle: 分布式系统设计模式category: 技术keywords: 架构,分布式,微服务,后端,分布式系统,设计模式 comments: true概述这篇文章是对于【分布式系统设计模式】的个人理解和部分翻译。 文章探讨了关于《基于容器化软件组件的微服务架构》。 其实容器化编程的发展路径和面向对象编程有异曲同工之妙--都是将复杂的系统进行抽象、解耦,然后通过一定的方式组合起来。 既然我们要组合,肯定会有面对不同情况的不同组合方式。所以,这些不同的组合方式也会有几个常用的固定模式。而这个正式我们要探讨的--分布式系统设计模式。 说到分布式,第一个联想到的应该就的容器化。为什么?其实容器化和分布式本没有交集,只是因为我们发现容器化是一个实现分布式的高效的方法。 容器化设置了一个天然的边界,边界之外用接口进行通信。有了这个边界的好处就是,任何意料之外的情况都可以被限制在最小的影响范围,毕竟我们构建的是一个大型的复杂系统。 我认为,用FMEA模型能很好的描述为什么会采用容器化去解构分布式系统。(FMEA,可以理解为:失控的状态一定会发生,我们要做的是控制失控的范围) 所以,我们接下来要说的设计模式基本上都是和容器相关,我们需要把容器作为一等公民去看。毕竟这是写 Kubernetes 的哥们写的。 单容器管理者模式 (Single-container management patterns)我们为容器增加一些可控接口,比如 run(), stop(), pause(),使得容器对外来说是可控的。 也正是因为广泛的 http 协议支持,你完全可以通过 http 和 JSON这样的序列化方式去构造你应用的对外的 API。 一般来说我们的设计方针都是一个容器提供一种服务。同时容器会为其上下游提供接口。 什么接口? 向上,提供容器本身丰富的信息接口。能够为特定的监控容器运行状态的应用提供信息。 向下,提供了控制容器本身的接口。使得分布式系统能够更有效的管理整个应用的生命周期,以及应用的优先级。 比如,一个集群的管理系统,能够设置集群处理任务的优先级。(比如 K8s 中的抢占式调度) 所以一旦采用这种模式的话,你会需要一个统一的管理平台,通过接口去管理(组管理)单个容器。 单节点-多容器应用模式 (Single-node, multi-container application patterns)这种模式比较好理解,有些容器应用是需要“共生”的,所以我们会将其放在同一个节点上。一旦这样,分布式系统会对容器组做联合调度。比如 K8s 里将调度单位描述成了 Pods(一个 Pod 可能包含多个容器),Nomad 则称其为 task groups。下面几个就是常用的单节点多容器的设计模式: 副载模式(Sidecar pattern)多容器部署最通用的一种模式,就是 sidecar 模式。其实大家都直接称呼 Sidecar 模式,不会翻译成副载。 那 Sidecar 是个啥样子呢? 举个例子吧:我们有一个主容器是 Web Server,我们需要收集 Web Server 所产生的日志。所以我们会有一个专门的 sidecar 容器,负责收集日志并把日志存储到集群的存储系统。 ...

June 27, 2019 · 1 min · jiezi

GMTC2019闲鱼基于Flutter的架构演进与创新

2012年应届毕业加入阿里巴巴,主导了闲鱼基于Flutter的新混合架构,同时推进了Flutter在闲鱼各业务线的落地。未来将持续关注终端技术的演变及趋势 Flutter的优势与挑战 Flutter是Google开源的跨端便携UI工具包,除了具有非常优秀的跨端渲染一致性,还具备非常高效的研发体验,丰富的开箱即用的UI组件,以及跟Native媲美的性能体验。由于它的众多优势,也使得Flutter成为了近些年来热门的新技术。 通过以上的特点可以看出,Flutter可以极大的加速客户端的研发效率,与此同时得到优秀的性能体验,基于我的思考,Flutter会为以下团队带来较大的收益: 中小型的客户端团队非常适合Flutter开发,不仅一端编写双端产出,还有效的解决了小团队需要双端人员(iOS:Android)占比接近1:1的限制,在项目快速推进过程中,能让整个团队的产能最大化。App在Android市场占比远高于iOS的团队,比如出海东南亚的一些App,Android市场整体占比在90%以上,通过Flutter可以将更多的人力Focus在Android市场上,同时通过在iOS端较小的投入,在结果上达到买一送一的效果。以量产App为主要策略的团队,不论是量产ToB的企业App,还是有针对性的产出不同领域的ToC的App的公司,都可以通过一端开发多端产出的Flutter得到巨大的产能提升。 闲鱼在以上的场景中属于第一种场景,服务3亿用户的闲鱼App的背后,开发资源投入很少,与竞对相比,我们是一只再小不过的团队,在这种场景下,Flutter为闲鱼业务的稳定发展以及提供更多的创新产品给予了很大的帮助。 但与此同时,Flutter在设计上带来的优势同时又会带来新的问题。所有的新技术都是脱胎于老技术的,Flutter也不例外,其身上带有很多Chrome的影子。我们再做一层简化,如果我们认为Flutter是一个使用Dart语言的浏览器容器,请大家思考一下两个问题如何解决。 如果在一个已经存在的App中加入Flutter,如何让Native与Flutter进行无缝的衔接,同时保证相互开发之间的隔离性如果在Flutter的容器中,使用已有的Native UI组件,在Flutter与Native渲染机制不同的情况下,怎么保证两者的无缝衔接以及高性能。闲鱼的架构演进与创新带着上面两个问题,我们来到闲鱼场景下的具体Case以及解决方案的演进过程。 已有App+Flutter容器 在这种情况下,闲鱼需要考虑的是首先要考虑引入Flutter容器后的内存压力,保证不要产生更多的内存溢出。与此同时我们希望能让Flutter和Native之间的页面切换是顺畅的,对不同技术栈之间的同学透明。因此我们有针对性的进行了多次迭代。 在没有任何改造的情况下以iOS为例,你可以通过创建新的FlutterViewController来创建一个新的Flutter容器,这个方案下,当创建多个FlutterViewController时会同时在内存中创建多个Flutter Engine的Runtime(虽然底层Dart VM依然只有一个),这对内存消耗是相当大的,同时多个Flutter Engine的Runtime会造成每个Runtime内的数据无法直接共享,造成数据同步困难。 这种情况下,闲鱼选择了全局共享同一个FlutterViewController的方式保证了内存占用的最小化,同时通过基础框架Flutter Boost提供了Native栈与Flutter栈的通信与管理,保证了当Native打开或关闭一个新的Flutter页面时,Dart侧的Navigator也做到自动的打开或关闭一个新的Widget。目前Google官方的提供的方案上就是参考闲鱼早先的这个版本进行的实现的。 然而在这种情况下,如果出现如闲鱼图中所示多个Tab的场景下,整个堆栈逻辑就会产生混乱,因此闲鱼在这个基础上对Flutter Boost的方案进行了升级并开源,通过在Dart侧提供一个BoostContainerManager的方式,提供了对多个Navigator的管理能力,如果打比方来看这件事,就相当于,针对Flutter的容器提供了一个类似WebView的OpenWindow的能力,每做一次OpenWindow的调用,就会产生一个新的Navigator,这样开发者就可以自由的选择是在Navigator里进行Push和Pop,还是直接通过Flutter Boost新开一个Navigator进行独立管理。 Flutter Boost目前已在github开源,由于闲鱼目前线上版本只支持Flutter 1.2的版本,因此需要支持1.5的同学等稍等,我们会在近期更新支持1.5的Flutter Boost版本。 Flutter页面+Native UI 由于闲鱼是一个闲置交易社区,因此图片和视频相对较多,对图片视频的线上性能以及内存占用有较严格的要求。目前Flutter已提供的几种方案中(Platform View以及Flutter Plugin),不论是对内存的占用还是整个的线上流畅度上还存在一定的问题,这就造成了当大部分同学跟闲鱼一样实现一个复杂的图文Feed推荐场景的时候,非常容易产生内存溢出。而实际上,闲鱼在以上的场景下有针对性的做出了较大的优化。 在整个的Native UI到Flutter渲染引擎桥接的过程中,我们选用了Flutter Plugin中提供的FlutterTextureRegistry的能力,在去年上半年我们优先针对视频的场景进行了优化,优化的思路主要是针对Flutter Engine底层的外接纹理接口进行修改,将原有接口中必须传入一个PixelBuffer的内存对象这一限制做了扩展,增加一个新的接口保证其可以传入一个GPU对象的TextureID。 如图中所示,优化后的整个链路Flutter Engine可以直接通过Native端已经生成好的TextureID进行Flutter侧的渲染,这样就将链路从Native侧生成的TextureID->copy的内存对象PixelBuffer->生成新的TextureID->渲染,转变为Native侧生成的TextureID->渲染。整个链路极大的缩短,保证了整个的渲染效率以及更小的内存消耗。闲鱼在将这套方案上线后,又尝试将该方案应用于图片渲染的场景下,使得图片的缓存,CDN优化,图片裁切等方案与Native归一,在享受已有集团中间件的性能优化的同时,也得到了更小的内存消耗,方案落地后,内存溢出大幅减少。 目前该方案由于需要配合Flutter Engine的修改,因此暂时无法提供完整的方案至开源社区,我们正在跟google积极沟通整个修改方案,相信在这一两个月内会将试验性的Engine Patch开源至社区,供有兴趣的同学参考。 复杂业务场景的架构创新实践 将以上两个问题解决以后,闲鱼开始了Flutter在业务侧的全面落地,然而很快又遇到新的问题,在多人协作过程中: 如何提供一些标准供大家进行参考保证代码的一致性如何将复杂业务进行有效的拆解变成子问题如何保证更多的同学可以快速上手并写出性能和稳定性都不错的代码 在方案的前期,我们使用了社区的Flutter Redux方案,由于最先落地的详情,发布等页面较为复杂,因此我们有针对性的对View进行了组件化的拆分,但由于业务的复杂性,很快这套方案就出现了问题,对于单个页面来说,State的属性以及Reducer的数量都非常多,当产生新需求堆叠的时候,修改困难,容易产生线上问题。 针对以上的情况,我们进行了整个方案的第二个迭代,在原有Page的基础上提供了Component的概念,使得每个Component具备完整的Redux元素,保证了UI,逻辑,数据的完整隔离,每个Component单元下代码相对较少,易于维护和开发,但随之而来的问题是,当页面需要产生数据同步时,整个的复杂性飙升,在Page的维度上失去了统一状态管理的优势。 在这种情况下闲鱼换个角度看端侧的架构设计,我们参考React Redux框架中的Connect的思想,移除掉在Component的Store,随之而来的是新的Connector作为Page和Component的数据联通的桥梁,我们基于此实现了Page State到Component State的转换,以及Component State变化后对Page State的自动同步,从而保证了将复杂业务有效的拆解成子问题,同时享受到统一状态管理的优势。与此同时基于新的框架,在统一了大家的开发标准的情况下,新框架也在底层有针对性的提供了对长列表,多列表拼接等case下的一些性能优化,保证了每一位同学在按照标准开发后,可以得到相对目前市面上其他的Flutter业务框架相比更好的性能。 目前这套方案Fish Redux已经在github开源,目前支持1.5版本,感兴趣的同学可以去github进行了解。 研发智能化在闲鱼的应用闲鱼在去年经历了业务的快速成长,在这个阶段上,我们同时进行了大量的Flutter的技术改造和升级,在尝试新技术的同时,如何能保证线上的稳定,线下的有更多的时间进行新技术的尝试和落地,我们需要一些新的思路和工作方式上的改变。 以我们日常工作为例,Flutter的研发同学,在每次开发完成后,需要在本地进行Flutter产物的编译并上传到远端Repo,以便对Native同学透明,保证日常的研发不受Flutter改造的干扰。在这个过程中,Flutter侧的业务开发同学面临着很多打包上传更新同步等繁琐的工作,一不小心就会出错,后续的排查等让Flutter前期的开发变成了开发5分钟,打包测试2小时。同时Flutter到底有没有解决研发效率快的问题,以及同学们在落地过程中有没有Follow业务架构的标准,这一切都是未知的。 在痛定思痛以后,我们认为数据化+自动化是解决这些问题的一个较好的思路。因此我们首先从源头对代码进行管控,通过commit,将代码与后台的需求以及bug一一关联,对于不符合要求的commit信息,不允许进行代码合并,从而保证了后续数据报表分析的数据源头是健康的。 在完成代码和任务关联后,通过webhook就可以比较轻松的完成后续的工作,将每次的commit有效的关联到我们的持续集成平台的任务上来,通过闲鱼CI工作平台将日常打包自动化测试等流程变为自动化的行为,从而极大的减少了日常的工作。粗略统计下来,在去年自动化体系落地的过程中单就自动打Flutter包上传以及触发最终的App打包这一流程就让每位同学每天节省一个小时以上的工作量,效果非常明显。另外,基于代码关联需求的这套体系,可以相对容易的构建后续的数据报表对整个过程和结果进行细化的分析,用数据驱动过程改进,保证新技术的落地过程的收益有理有据。 总结与展望回顾一下上下文 Flutter的特性非常适合中小型客户端团队/Android市场占比较高的团队/量产App的团队。同时由于Flutter的特性导致其在混合开发的场景下面存在一定劣势。闲鱼团队针对混合开发上的几个典型问题提供了对应的解决方案,使整个方案达到上线要求,该修改会在后续开放给google及社区。为全面推动Flutter在业务场景下的落地,闲鱼团队通过多次迭代演进出Fish Redux框架,保证了每位同学可以快速写出相对优秀的Flutter代码。新技术的落地过程中,在过程中通过数据化和自动化的方案极大的提升了过程中的效率,为Flutter在闲鱼的落地打下了坚实的基础。除了本文提及的各种方案外,闲鱼目前还在多个方向上发力,并对针对Flutter生态的未来进行持续的关注,分享几个现在在做的事情 Flutter整个上层基础设施的标准化演进,混合工程体系是否可以在上层完成类似Spring-boot的完整体系构架,帮助更多的Flutter团队解决上手难,无行业标准的问题。动态性能力的扩展,在符合各应用商店标准的情况下,助力业务链路的运营效率提升,保证业务效果。目前闲鱼已有的动态化方案会后续作为Fish-Redux的扩展能力提供动态化组件能力+工具链体系。Fish-Redux + UI2Code,打通代码生成链路和业务框架,保证在团队标准统一的情况下,将UI工作交由机器生成。Flutter + FaaS,让客户端同学可以成为全栈工程师,通过前后端一体的架构设计,极大的减少协同,提升效率。让工程师去从事更多创造性的工作,是我们一直努力的目标。闲鱼团队也会在新的一年更多的完善Flutter体系的建设,将更多已有的沉淀回馈给社区,帮助Flutter社区一起健康成长。 ...

June 26, 2019 · 1 min · jiezi

云上的Growth-hacking之路打造产品的增长引擎

增长关乎产品的存亡增长!增长!增长!业务增长是每一个创业者每天面临的最大问题。无论你的产品是APP,还是web,或者是小程序,只能不断的维持用户的增长,才能向资本市场讲出一个好故事,融资活下去。活到最后的产品,才有机会盈利。 为了获取用户的增长,可以投放广告,也可以内容营销、社交传播、销售地推,或者持续的专注于产品优化。无论哪一种方式,我们都面临这几个问题: 运营活动,覆盖了多少用户?多少用户,开始使用产品?多少用户付费?多少用户持续的活跃?下一步,我们应该把精力放在哪些方面?是持续运营?还是开发新功能? 如果不能回答这些问题,无疑我们的运营活动或者开发就是盲人摸象,完全靠运气。为了解答这些问题,我们不妨关注一下growth hacking这种数据驱动的手段。 Growth Hacker的核心思想传统的市场营销策略,例如投放电视广告,覆盖了多少人,有多少人看过广告后进行了购买,多少人进行了复购,没有准确的数据进行衡量,只能依赖于资深专家根据经验判断。在互联网行业,每一个产品都是新的,前所未有的。每一个产品能不能存活,每一次运营的效果如何,没有多少经验可供借鉴,结果是不确定的。 GrowthHacking是兴起于硅谷的创业公司的marketing手段,旨在使用少量预算获得巨量增长。由于其极高的性价比和有效性,非常适合于创业公司,因而得到了广泛传播。 Growth Hacker的核心思想是通过数据指标,驱动运营决策,以及优化产品。Growthacker通过关注用户获取、用户转化、用户留存、用户推荐、盈利等核心的一系列指标,以及通过各种维度拆解,分析出下一步的增长决策。通过Growth Hacking,打造一个产品增长策略的闭环。 那么我们如何才能搭建出GrowthHacking架构,为自己的产品赋能呢? GrowthHacking之架构Growth Hacking 包含了数据的采集、存储、分析、报表、A/B test等系统,首先我们来看,传统的解决方案,搭建出GrowthHacking有哪些痛点: 搭建运营体系的痛点搭建运营体系的过程中,常常面临以下问题: 缺少数据,数据散落在各个地方,有的是app数据,有的是web数据,有的是小程序数据,没有一个统一的架构来把数据采集到一个地方。缺少一个分析平台。传统的策略,需要运维团队帮助搭建hadoop集群,需要专门团队持久运维。离线跑报表,一晚上才能拿到一次结果,周期太长。手工跑一次,几个小时过去了,有什么新的想法,不能及时验证。严重影响运营效率。借助云服务搭建的GrowthHacking技术架构为了解决以上问题, 日志服务提供了日志采集、存储、交互分析、可视化的一整套基础设施,可以帮助用户快速搭建出来灵活易用的Growthing Hacking的技术架构,每天的工作只需要专注于运营分析即可。 Growth Hacking首先从数据采集开始,定义清楚要采集的日志内容、格式。把各个终端、服务器的日志集中采集到云端的日志服务。后续通过日志服务提供的SQL实时分析功能,交互式的分析。定义一些常规报表,每日打开报表自动计算最新结果,也可以定义报告,自动发送最新报表。全部功能参考用户手册 此外,除了日志数据的分析,还可以为用户定义一些标签,存储在rds中,通过rds和日志的联合分析,挖掘不同标签对应的指标。 日志服务有如下特点: 免运维:一次完成数据的埋点、数据接入,之后只需专注于运营分析即可,无需专门的运维团队。实时性:用SQL实时计算,秒级响应。快人一步得到分析结果。灵活性:任意调整SQL,实时获取结果,非常适合交互式分析。弹性:遇到运营活动,流量突然暴涨,动动手指快速扩容。性价比:市场上常见的分析类产品,多采用打包价格,限制使用量。日志服务按量付费,价格更低,功能更强大。借助于日志服务提供的这套数据采集、存储、分析的基础设施。运营者可以从繁重的数据准备工作重解脱出来,专注于使用SQL去分析数据,配置报表,验证运营想法。 开始搭建GrowthHacking系统具体而言,Growth Hacking的架构可以拆分如下: 数据收集 定义埋点的规范,定义要采集的事件内容、字段、格式。通过Android SDK,iOS SDK, Web tracking等手段在客户端埋点。存储 选择日志服务的region。定义每一种日志存储的Project & LogStore。分析 开启分析之路,定义常规报表,或者交互式分析。通过分析结果,调整运营策略,有针对性的优化产品。基于日志服务,可以完成Growth Hacking的分析策略: 定义北极星指标。拉新分析。留存分析。事件分析。漏斗分析。用户分群。A/B test。在日志服务中,可以通过定义一系列仪表盘,来沉淀数据分析的结果。接下来的几篇文章中,将依次介绍如何在日志服务实现上述几种策略。 总结本文主要介绍Growth Hacking的整体架构,之后将用一系列文章介绍step by step如何介入数据,如何分析数据。 本文作者:云雷 阅读原文 本文为云栖社区原创内容,未经允许不得转载。

June 25, 2019 · 1 min · jiezi

MySQL单表数据不要超过500万行是经验数值还是黄金铁律

原文地址:梁桂钊的博客博客地址:http://blog.720ui.com 欢迎关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,打破认知的局限性。 今天,探讨一个有趣的话题:MySQL 单表数据达到多少时才需要考虑分库分表?有人说 2000 万行,也有人说 500 万行。那么,你觉得这个数值多少才合适呢? 曾经在中国互联网技术圈广为流传着这么一个说法:MySQL 单表数据量大于 2000 万行,性能会明显下降。事实上,这个传闻据说最早起源于百度。具体情况大概是这样的,当年的 DBA 测试 MySQL性能时发现,当单表的量在 2000 万行量级的时候,SQL 操作的性能急剧下降,因此,结论由此而来。然后又据说百度的工程师流动到业界的其它公司,也带去了这个信息,所以,就在业界流传开这么一个说法。 再后来,阿里巴巴《Java 开发手册》提出单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。对此,有阿里的黄金铁律支撑,所以,很多人设计大数据存储时,多会以此为标准,进行分表操作。 那么,你觉得这个数值多少才合适呢?为什么不是 300 万行,或者是 800 万行,而是 500 万行?也许你会说这个可能就是阿里的最佳实战的数值吧?那么,问题又来了,这个数值是如何评估出来的呢?稍等片刻,请你小小思考一会儿。 事实上,这个数值和实际记录的条数无关,而与 MySQL 的配置以及机器的硬件有关。因为,MySQL 为了提高性能,会将表的索引装载到内存中。InnoDB buffer size 足够的情况下,其能完成全加载进内存,查询不会有问题。但是,当单表数据库到达某个量级的上限时,导致内存无法存储其索引,使得之后的 SQL 查询会产生磁盘 IO,从而导致性能下降。当然,这个还有具体的表结构的设计有关,最终导致的问题都是内存限制。这里,增加硬件配置,可能会带来立竿见影的性能提升哈。 那么,我对于分库分表的观点是,需要结合实际需求,不宜过度设计,在项目一开始不采用分库与分表设计,而是随着业务的增长,在无法继续优化的情况下,再考虑分库与分表提高系统的性能。对此,阿里巴巴《Java 开发手册》补充到:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。那么,回到一开始的问题,你觉得这个数值多少才合适呢?我的建议是,根据自身的机器的情况综合评估,如果心里没有标准,那么暂时以 500 万行作为一个统一的标准,相对而言算是一个比较折中的数值。 写在末尾【服务端思维】:我们一起聊聊服务端核心技术,探讨一线互联网的项目架构与实战经验。让所有孤军奋战的研发人员都找到属于自己的圈子,一起交流、探讨。在这里,我们可以认知升级,连接顶级的技术大牛,连接优秀的思维方式,连接解决问题的最短路径,连接一切优秀的方法,打破认知的局限。 更多精彩文章,尽在「服务端思维」!

June 21, 2019 · 1 min · jiezi

探秘金融级云原生发布工作负载-CafeDeployment

本文作者:蚂蚁金服 昊天,枫晟 本文简单介绍了蚂蚁金服 SOFAStack 的 Kubernetes 自定义资源 CafeDeployment 的开发背景和功能特性,我们将会在6月25日的 KubeConf 上对其做详细的介绍和演示,欢迎大家来交流。 背景介绍Kubernetes 原生社区 Deployment 和 StatefulSet 解决了“服务节点版本一致性”的问题,并且通过 Rolling Update 实现了滚动升级,提供了基本的回滚策略。对于高可用建设要求不高的“年轻”业务,是一个不错的选择。但是,在金融场景下,要解决的场景复杂得多。因此我们在金融分布式架构-云应用引擎(SOFAStack-CAFE,参见金融级云原生探索实践系列 - 开篇)中提出了 CafeDeployment 的云原生模型,致力于解决以下问题: 1、IP 不可变 对于很多运维体系建设较为早期的用户,使用的服务框架、监控、安全策略,大量依赖 IP 作为唯一标识而被广泛使用。迁移到 Kubernetes 最大的改变就是 IP 会飘,而这对于他们来说,无异于运维、服务框架的推倒重来。 2、金融体系下的高可用 Deployment/StatefulSet 无法根据特定属性进行差异化部署。而在以同城双活为建设基础的金融领域,为了强管控  Pod 的部署结构(即保证每个机房/部署单元都有副本运行),若通过原生组件进行部署,我们不得不维护多个几乎一模一样的 Deployment/StatefulSet,来保证 Pod 一定会飘到指定机房/部署单元的 node 上。在规模上到一定程度后,这无疑加大了运维管控的复杂度和成本。 3、灵活的部署策略 Deployment 无法控制发布步长,StatefulSet 虽然可以控制步长,但是每次都需要人工计算最新版本需要的副本数并修改 Partition,在多机房/部署单元的情况下,光想想发布要做的操作都脑袋炸裂。在面对以上这些问题的时候,我们思考:能不能有一个类似 Deployment 的东西,不仅可以实现副本保持,并且能协助用户管控应用节点部署结构、做 Beta 验证、分批发布,减少用户干预流程,实现最大限度减少发布风险的目标,做到快速止损,并进行修正干预。这就是我们为什么选择定义了自己的资源——CafeDeployment。 模型定义 CafeDeployment 主要提供跨部署单元的管理功能,其下管理多个 InPlaceSet。每个 InPlaceSet 对应一个部署单元。部署单元是逻辑概念,他通过 Node 上的 label 来划分集群中的节点,而 InPlaceSet 则通过 NodeAffinity 能力,将其下的 Pod 部署到同一个部署单元的机器上。由此实现 CafeDeployment 跨部署单元的管理。 ...

June 20, 2019 · 3 min · jiezi

重磅开源AOP-for-Flutter开发利器AspectD

https://github.com/alibaba-flutter/aspectd 问题背景随着Flutter这一框架的快速发展,有越来越多的业务开始使用Flutter来重构或新建其产品。但在我们的实践过程中发现,一方面Flutter开发效率高,性能优异,跨平台表现好,另一方面Flutter也面临着插件,基础能力,底层框架缺失或者不完善等问题。 举个栗子,我们在实现一个自动化录制回放的过程中发现,需要去修改Flutter框架(Dart层面)的代码才能够满足要求,这就会有了对框架的侵入性。要解决这种侵入性的问题,更好地减少迭代过程中的维护成本,我们考虑的首要方案即面向切面编程。 那么如何解决AOP for Flutter这个问题呢?本文将重点介绍一个闲鱼技术团队开发的针对Dart的AOP编程框架AspectD。 AspectD:面向Dart的AOP框架AOP能力究竟是运行时还是编译时支持依赖于语言本身的特点。举例来说在iOS中,Objective C本身提供了强大的运行时和动态性使得运行期AOP简单易用。在Android下,Java语言的特点不仅可以实现类似AspectJ这样的基于字节码修改的编译期静态代理,也可以实现Spring AOP这样的基于运行时增强的运行期动态代理。那么Dart呢?一来Dart的反射支持很弱,只支持了检查(Introspection),不支持修改(Modification);其次Flutter为了包大小,健壮性等的原因禁止了反射。 因此,我们设计实现了基于编译期修改的AOP方案AspectD。 设计详图 典型的AOP场景下列AspectD代码说明了一个典型的AOP使用场景: aop.dartimport 'package:example/main.dart' as app;import 'aop_impl.dart';void main()=> app.main();aop_impl.dartimport 'package:aspectd/aspectd.dart';@Aspect()@pragma("vm:entry-point")class ExecuteDemo { @pragma("vm:entry-point") ExecuteDemo(); @Execute("package:example/main.dart", "_MyHomePageState", "-_incrementCounter") @pragma("vm:entry-point") void _incrementCounter(PointCut pointcut) { pointcut.proceed(); print('KWLM called!'); }}面向开发者的API设计PointCut的设计 @Call("package:app/calculator.dart","Calculator","-getCurTime")PointCut需要完备表征以怎么样的方式(Call/Execute等),向哪个Library,哪个类(Library Method的时候此项为空),哪个方法来添加AOP逻辑。PointCut的数据结构: @pragma('vm:entry-point')class PointCut { final Map<dynamic, dynamic> sourceInfos; final Object target; final String function; final String stubId; final List<dynamic> positionalParams; final Map<dynamic, dynamic> namedParams; @pragma('vm:entry-point') PointCut(this.sourceInfos, this.target, this.function, this.stubId,this.positionalParams, this.namedParams); @pragma('vm:entry-point') Object proceed(){ return null; }}其中包含了源代码信息(如库名,文件名,行号等),方法调用对象,函数名,参数信息等。请注意这里的@pragma('vm:entry-point')注解,其核心逻辑在于Tree-Shaking。在AOT(ahead of time)编译下,如果不能被应用主入口(main)最终可能调到,那么将被视为无用代码而丢弃。AOP代码因为其注入逻辑的无侵入性,显然是不会被main调到的,因此需要此注解告诉编译器不要丢弃这段逻辑。此处的proceed方法,类似AspectJ中的ProceedingJoinPoint.proceed()方法,调用pointcut.proceed()方法即可实现对原始逻辑的调用。原始定义中的proceed方法体只是个空壳,其内容将会被在运行时动态生成。 ...

June 19, 2019 · 2 min · jiezi

为什么说优秀架构师往往是一个悲观主义者

阿里妹导读:18年前,200家企业由于在事故中信息系统遭到严重破坏而永远地关闭了。这样的事故引发了后人深思,对于工程师而言,不仅要求设计的系统足够强壮,还需要具备考虑失败的能力,当失败场景悉数被考虑周全、并且结合充分的演练,一切会不会不一样?我们熟知面向对象设计和面向程序设计,阿里巴巴资深技术专家游骥洞悉行业现状,抛出了一个新模式——面向失败设计。今天,听他娓娓道来,如何在一开始的系统设计阶段就考虑到各种失败场景,把面向失败当成是系统设计的一部分,准备好从失败中恢复的策略。引言一个优秀的架构师通常都是一个悲观主义者,除了设计好能够支撑业务持续发展的优雅架构,另一个容易被忽略的重要能力在于充分考虑失败场景。如果对失败场景考虑不够充分,轻则出现业务不可用,影响用户体验和企业声誉;重则导致数据永久丢失、业务再无恢复可能。 2001 年 9 月 11 日,美国世贸中心双子大厦遭受了谁也无法预料的恐怖打击,灾难发生前约有 350 家企业在世贸大厦中工作,事故发生一年后,重返世贸大厦的企业变成了 150 家,有200 家企业由于重要信息系统的破坏,关键数据的丢失而永远关闭、消失了,其中的一家公司声称自己要恢复到灾难前的状态需要 50 年的时间。 “Everything fails, all the time”,无论是在传统软件时代还是在互联网、云时代,系统终究会在某个时间点失败,面向失败的设计理念数十年来并没有多大的变化,不同的是在分布式、云架构的互联网时代:失败将由小概率偶发事件变成常态,同时应对和处理失败的具体实现方式也大相径庭。 无所不在的失败场景单个技术点在绝大部分时间都能按照设想正常工作,但是当规模和复杂度到达一定程度,失败其实无所不在。当你的业务场景从服务企业内部的几百号员工变成面向上亿的外部用户,你不确定你的用户群会有些什么样的角色,也不知道他们会在你的系统平台上创造出什么样的业务行为;当你的技术框架从单机、一体机演进到分布式的多层、多组件架构,原本5个以内的技术组件可能变成了今天的500个,并且为了用较低的成本保持服务能力的扩展能力,你可能放弃了稳定性更好但也昂贵的商业技术、转而用开源自建来替代。 互联网业务快速发展不仅直接带来了流量、安全等不确定性,同时促使了技术架构的快速演进,使架构变得越来越复杂,这些因素都将导致失败发生的概率大幅提升。当人类的工作、生活越来越依赖互联网,一旦出现失败,造成的影响和损失将是空前巨大的。在远古时代,人类没有自来水也没有电,一切都很好;今天如果停电停水一段时间,相信很多人都会无法适应,而互联网正在逐步演变成跟水和电一样的基础设施。失败的原因多种多样,抽象来看可以分为以下几类: 硬件问题 首先,硬件是有生命周期的,它一定会老化,并且你不知道它会在什么时候坏;其次,硬件是一个实体,它存在于客观环境当中,它的状态会受外部环境干扰,比如火灾、地震等外力因素都可能导致硬件损坏;最后,所有硬件都会存在残次品,你很可能就是那个不幸者。通常情况下单个硬件出问题的概率不高,但是当有几十万的硬件设备,硬件的失败问题每天都会发生。 软件bug 即便是最优秀程序员写出来的程序,经过最优秀测试同学的严格测试后的代码,上线依然无法做到完全没有bug。互联网业务迭代往往讲究一个“快”字,以往几个月或者几年升级一次的软件程序,现在一周就需要升级一次或者多次,这大幅提升了软件出错的可能性。 配置变更错误 系统运行态的日常运维过程当中,难免会因为疏忽或者考虑不周全导致灾难。当上万名技术同学跟上百个变更系统做笛卡尔积,哪怕是6个9的可靠性,依旧无法做到万无一失。全局的流量入口、权限与安全验证体系、统一网关与接口平台等技术环节是可能促发全站不可用的重要风险点,对于影响面大的配置的变更需要尤为谨慎。 系统恶化 原本工作得很好的程序随着时间的推移可能有一天不再正常工作,举几个常见的例子:自增变量运行了很长一段时间后出现越界、缓存随着数据量的逐渐变大而出现空间不足、数据库连接池随着机器的扩容而不够用等等。千万不要认为运行良好的系统是不会出问题的,它的代码里面可能藏了定时炸弹,只是你不知道会在什么时间点爆炸。 超预期流量 某一天你的系统可能突然会承受远超过预期的每秒请求数,特别是在“中国特色”的互联网场景之下,你很难精确预估系统各个时间点的业务访问量。 外部攻击 你需要考虑各种攻击行为,包含流量攻击和安全攻击。你的系统可能随时会面临着DDOS和CC类攻击,你传输的数据可能会被盗取或者篡改。 依赖库问题 你的系统很可能会用大量的二方库或者三方库,它们对你来说是黑盒子,你不了解它们存在哪些风险,并且你无法掌控。这些库可能会存在漏洞、可能会有bug,可能会大量消耗你的系统资源,总之不要太信任它们。 依赖服务问题 你依赖的服务也一定不会100%可用,它们可能会超时,可能会失败。当依赖服务超时的时候,如果你没有很好地处理,可能会导致你自己的系统无法工作,在分布式场景下,这种失败状态会持续辐射,最终导致大面积的不可用。 如何面向失败设计作为一个悲观主义者,你需要在一开始的系统设计阶段就考虑到以上各种失败场景,把面向失败当成系统设计的一部分,并且准备好从失败中恢复的策略,这有助于更好地提升整个系统的可用性。只有你意识到事情会随着时间的推移而失败,并将这种思想融入到体系结构中,那么在失败发生的时候你才能完全不受影响或者将失败损失降到最低。面向失败的设计理念数十年来并没有多大的变化,一些好的经典原则在今天依旧被广泛运用。 冗余设计避免单点故障 硬件和软件都不可靠,环境和人都存在极大的不确定性,虽然无法避免失败场景的发生,但是可以通过冗余设计来规避局部失败对系统的影响。冗余设计避免单点故障这一策略在互联网技术架构中处处可见,比如重要的服务通常都会部署多个、数据库的主备结构、服务调用的重试机制、存储的多副本等概念都属于这一范畴。 面向失败的宏观多活架构 除了局部失败场景,你的系统可能还面临着大范围的失败场景。大范围的原因有两个:天灾,比如火灾、地震、台风、雷电等大的自然灾害可能导致大面积的基础设备被毁坏;人祸:人的失误或者刻意破坏行为有时候也会酿成大祸,如操作错误、破坏、植入有害代码和恐怖袭击。“面向失败的宏观多活架构”从宏观架构的高可用层面来解决系统的整体可用性问题,随着技术的演进,冷备、热备、两地三中心、异地多活等应对大范围失败场景的技术体系这些年频频被提起。 服务能力与依赖调用自我保护 如何来衡量一个软件系统的设计是否优良?一条很重要的衡量标准——在任何情况之下你的软件系统都应该工作在当前环境的最优状态。每个人都知道机翼是飞机的重要部件,一旦机翼出现问题,飞机很可能就会坠落。然而在二战当中,许多战斗机即便机翼千疮百孔了,依然保持着最佳战斗能力;甚至还有更夸张的情况:1983年的一次战斗机演习当中,一架飞机由于事故损失了一个机翼,这架缺少一个机翼的飞机依然保持了飞行能力、最终完成安全着陆。 软件系统由两部分构成:系统自身的代码和依赖的库以及服务。“服务能力与依赖调用自我保护”需要从这两块分别切入构建系统在任意情况都始终工作在最佳状态的能力。服务限流、系统负载保护、给依赖的服务设置超时或者资源限制等都是相应的应对策略。 为一切不可预料的情况备好预案 能够抵抗失败和从失败中快速恢复是面向失败设计的核心思想,然而即便已经做了万全的设计,也并非所有的失败场景都是系统能够自动抵御的。你需要考虑到所有的失败场景,并准备好相应的应对预案。为一切不可预料的情况备好预案才能在失败场景真正发生时做到有条不紊。做好预案需要对失败场景有全面的考虑:会发生哪些失败?失败会带来什么问题?应对策略是什么?预期的恢复时间多久?恢复后的影响面有多大?需要通知到哪些角色?等这一系列的因子构成了一个完整的预案体系。 自动化运维管控 大量的系统故障是因为人的失误造成的,即便让一个优秀的运维工程师进行一万次同样的运维操作也难免不出错。唯一的解决办法便是在运维过程当中尽可能降低人为操作的比重。系统化、白屏化是第一个阶段——将人为的操作步骤固化成系统程序,避免操作失误;自动化以及智能化是第二个阶段——将正确的决策过程也固化成智能程序,避免决策失误。同时所有的运维动作都需要遵循灰度原则,做到可灰度、可监测、可回滚,即便出现了失误也能控制好爆炸半径,并且做到快速恢复。 精细化的监控体系 面向失败设计不仅要求你的系统足够健壮,同时要求你能够在第一时间感知到失败的发生。无论是自动化的系统恢复,还是人为介入,如果你压根都不知道是哪里出问题了,一切都将束手无策。精细化的监控体系一方面能够在出现问题的时候以最快的速度将最准确的信息传递到人或者运维系统,同时它还能够展现趋势、进行提前预警。AI技术的结合使得监控领域在近几年得到了新的发展驱动力:智能监控报警、根因定位、智能预测、智能决策等能力都是学术界和工程界非常热衷的课题。 故障与攻防演练锤炼容灾应急能力 最后,即便以上工作都做好了,你也不能高枕无忧去等待失败到来。你的设计、系统、流程、技术人员等需要通过不断演练,来保障能力和进化升级。对于代价非常巨大的事件,做好前期的充分演练是非常有必要的,比如军事演练、消防演练等都属于这一范畴。而系统不可用的代价对于企业来讲很可能是无法承受的,因此需要在平时做好充分的演练:通过故障与攻防演练锤炼容灾应急能力,对面向失败的设计做好充分验证。只有当所有的失败场景都被提前演练过,当失败真正来临时才能做到胸有成竹。 本文作者: 游骥阅读原文 本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

June 18, 2019 · 1 min · jiezi

支付宝技术风险负责人陈亮把事情做到极致技术的差异性才会体现出来

“很多事情,说出来很多人都在做,但是只有真正做到极致,技术的差异性才会体现出来”,蚂蚁金服技术风险部研究员陈亮(花名:俊义)在接受 InfoQ 采访时如是说道。在此前的支付宝技术嘉年华,InfoQ 对支付宝数次技术架构升级的见证者及主导架构师陈亮进行了独家采访,首次系统了解稳定支撑“双十一”等多次实战背后的支付宝技术风险体系。 支付宝技术风险体系2007 年,陈亮加入支付宝,负责支付宝搜索及通信中间件架构。在之后的十年时间里,陈亮先后负责过支付宝交易拆分整体架构,这成为支付宝数据库拆分架构标准;支付宝三代架构单元化及容灾整体架构,实现异地多活,这成为支付宝单元化架构标准。如果简单总结在支付宝工作的前十年,陈亮表示: 前十年,我一直在做可扩展性相关的工作。在这期间,问题和需求驱动占据上风。陈亮回忆道:“最初的支付宝是单体架构,一个小型机加两个 Java 写的 APP,那年 DBA 就找过来说如果不进行数据库拆分,很难扛住业务发展”。 经过系列改造,这一工作终于完成。当时,陈亮以为这个架构起码可以支撑支付宝未来五到十年的发展。然而,双十一很快就来了,超大规模瞬时流量的冲击对架构提出了全新挑战,整个团队又开始马不停蹄地进行异地多活相关项目研发。 彼时,支付宝有两个主要应对技术风险的团队,一个叫技术质量团队,另一个则是运维团队。技术质量主要是各种功能测试,并解决程序 Bug、故障等问题;运维团队主要是生产偏基础设施以及应用、DB 运维管理保障,同时也会自发性地做一些技术风险相关的事情,但并未形成体系化的技术风险组织阵型及打法。 2013 年,支付宝技术团队提出质量 2.0 战略,其目的是希望在技术风险领域有一些延展,体系化沉淀 Bug 检测等方面的能力。自此,支付宝的技术风险体系建设逐渐步入正轨。 组织架构演进 2014 年,质量技术部成立希望从全域视角解决技术风险问题。但是,质量技术部并没有运维团队,主要就是通用质量检测和高可用保障相关的技术解决方案,并驱动各业务部门的技术团队落地。当时,质量技术部人员并不多,是一个小而精悍的中台部门。 经过一年多的发展,质量技术部发现仅仅依靠质量技术并不能解决生产上的各种故障风险。虽然,质量技术部会关注生产研发过程,但主要精力在于对各业务技术团队输出技术风险,比如高可用及通用质量检测的解决方案,高可用及资金保障方面尚未出现成型的平台体系。虽然当时的全链路压测和持续集成平台已有所成型,但关于高可用等并没有成型的平台。 当时,技术团队判断,不能只从质量角度看风险,而需要从更高的维度和更全面的视角看待风险。2015 年,质量技术部升级为技术风险部,专注研发及架构技术风险问题,做相应的解决方案和落地平台。 2016 年,陈亮一手打造了支付宝的 SRE(Site Risk Engineer,参考谷歌的 Site Reliability Engineer)体系。技术风险部增加 PE 和 DBA 团队,PE 团队直接对生产环节中的运营、操作等做技术风险防控,整个大团队的职能属于 SRE。据了解,这也是国内第一个 SRE 团队。 陈亮发现,传统的运维思路和文化已经无法彻底解决支付宝的稳定性问题,因此需要成立 SRE 团队。事实上,传统的运维方式侧重于靠人肉解决风险,不管是调参还是更改配置,都无法从本质上解决支付宝的稳定性问题,相反会让运维人员的工作成就感很低。说到底,运维领域的问题终究还是软件问题,需要建立软件平台更好地管理风险。 在组建 SRE 团队的过程中,陈亮认为最难的反而不是技术层面的推进,而是让团队工程师,包括整个公司认同 SRE 的价值,这需要让所有人理解 SRE 可以解决哪些新的问题以及传统的思维方式为何不可取。 据了解,支付宝的 SRE 团队主要由研发、运维和测试人员组成,八成运维人员都需要写稳定性相关的代码。团队组建完成即全面开展故障自动定位、自适应容灾、防抖、精细化高可用等工作。其中,防抖要保证任何网络或基础设施抖动,用户都无感知;精细化高可用,又叫单笔高可用,其颗粒度可以精准到用户的每一笔交易,远远优于行业内的机房级高可用。 2016 年,SRE 团队建设了很多平台和能力。同时,技术团队发现了两个极为重要的现象,一是生产故障不是必然的,通常都是偶然性的;二是生产故障是低频的。这带来的问题就是故障样本很少,没有办法证明在真实故障到来时平台是否具备能力应对。也就是说,SRE 团队建设的防御系统的可靠性,无法充分验证。 2017 年,SRE 团队成立了专门的、独立职能的技术蓝军,其主要的工作就是发掘防御系统的弱点并发起真实的攻击。技术蓝军并不对各业务方负责,只对这套防御系统的稳定性和可靠性负责。 在技术蓝军看来,发生故障是必然的,只是时间早晚而已,技术蓝军会想尽办法触发这些故障,以保障在故障真实发生时,团队有足够的应付能力。目前,全栈级的技术攻防演练每周都在进行,而故障防御系统及不断优化的高可用架构则是由 SRE 团队的红军与各业务深度合作,沉淀、构建出来的。 ...

June 14, 2019 · 1 min · jiezi

从遇见到信任-Apache-Dubbo-的毕业之旅

所谓信任,就是多一次机会。 2018年2月16日,Apache Dubbo 加入 Apache 基金会孵化器。 ... 2019年5月16日,Apache 软件基金会董事会决议通过了 Apache Dubbo 的毕业申请,这意味着 Apache Dubbo 正式成为 Apache 的顶级项目。5月21日,Apache 官方发布了这一消息。这也是 阿里巴巴微服务 继 Apache RocketMQ 后的又一个 Apache 顶级项目。 What is Dubbo ?Apache Dubbo 起初的定位是一款轻量级、高性能的服务框架,自 2012 年开源以来,深受国内开发者的喜爱,并被国内许多企业选型作为服务化改造的方案首选和微服务架构的基石之一。其主要功能是: 提供基于RPC的高性能接口,对用户透明。智能负载均衡:支持多种开箱即用的负载均衡策略,可以感知下游服务状态,从而减少总体延迟并提高系统吞吐量。自动服务注册和发现:支持多个服务注册表,可以立即在线/离线检测服务。高可扩展性:微内核和插件设计确保可以通过协议,传输和序列化等核心功能轻松扩展第三方实施。运行时流量路由:可以在运行时配置,以便根据不同的规则路由流量,这样可以轻松支持蓝绿部署,数据中心感知路由等功能。可视化服务治理:为服务治理和维护提供丰富的工具,例如查询服务元数据,运行状况和统计信息。Dubbo meets Apache2018 年 2 月,阿里巴巴将 Apache Dubbo 捐献给 Apache 软件基金会,得到了社区广泛的好评。 在这1年多的孵化过程中,Dubbo 社区: 持续迭代,共计发布11个版本;多元化治理,新增了6位 PPMC Member (孵化项目管理管理会成员),他们来自阿里巴巴、京东、美团点评、去哪儿、网易、微店、有赞等企业;并发展了15位项目提交者(对 Dubbo 项目具有提交权限),他们来自阿里巴巴、曹操科技、滴滴出行、国美金融、韩都衣舍、华为、京东、Keep、科大讯飞、美团点评、去哪儿、融贯电商、网联清算、网易、微店、亚信安全等10多家公司;构建多元化社区,Dubbo 主项目的贡献者从70+提升到目前的200位;用户多元化,阿里巴巴、当当、滴滴、海尔、去哪儿、网联清算、网易考拉、微店、中国电信、中国工商银行、中国人寿、中国银联等140多家公司在 GitHub 上报告了已将 Apache Dubbo 运用于生产环境中 ;GitHub 上的 star 数从入住孵化器前的17520增加到26400+,fork 数更是达到了17500+,fork 数排在所有Java 项目中的第三位;孵化过程中,Dubbo 社区的多样性得到了极大的发展,并不断演进核心和丰富生态,旨在为开发者们构建微服务和云原生支撑的基石。 ...

June 14, 2019 · 2 min · jiezi

优酷背后的大数据秘密

在本文中优酷数据中台的数据技术专家门德亮分享了优酷从Hadoop迁移到阿里云MaxCompute后对业务及平台的价值。 本文内容根据演讲视频以及PPT整理而成。 大家好,我是门德亮,现在在优酷数据中台做数据相关的事情。很荣幸,我正好见证了优酷从没有MaxCompute到有的这样一个历程,因为刚刚好我就是入职优酷差不多5年的时间,我们正好是在快到5年的时候,去做了从Hadoop到MaxCompute的这样一个升级。这个是2016年5月到2019年现在的5月优酷的发展历程,上面是计算资源,下面是储存资源。大家可以看到整个用户数,还有表的数据,实际上是在呈一个指数式增长的。但是在2017年5月,当优酷完成了整个Hadoop迁移MaxCompute后,优酷的计算消耗,还有储存的消耗实际上是呈下降趋势的,整个迁移得到了一个非常大的收益。 下面说一下优酷的业务特点。 第一个特点从大数据平台整个的用户复杂度上面,不止是数据的同学和技术的同学在使用,还会包括一些BI同学,测试同学,甚至产品运营都可能去使用这个大数据的平台。 第二个特点就是业务复杂,优酷是一个视频网站,它有非常复杂的业务场景,从日志分类上,除了像页面浏览,还会有一些播放相关的数据、性能相关的数据。从整个的业务模式上,有直播、有会员、有广告、有大屏等这样一些非常不一样的场景。 第三个特点,就是数据量是非常巨大的,一天的日志量会达到千亿级别,这是一个非常旁大的数据量,而且会做非常复杂的计算。 第四个是比较有意思的,不管是小公司、大公司,对成本的意识是非常高的。优酷也是有非常严格的预算,包括在阿里集团内是有非常严格的预算系统的,但是我们也经常会去做一些重要的战役,像双十一战役,像我们暑期的世界杯战役,还有春节也会搞各种战役。这样的话,其实对计算资源的弹性要求是非常高的。 基于上面的优酷的业务特点,我整理了MaxCompute可以完美的支持我们业务的几个特点。 第一个,简单易用。第二个,完善的生态。第三个,性能非常强悍。第四个,资源使用非常弹性。 第一个特点,简单易用。MaxCompute有一个非常完整的链路,不管是从数据开发,还是数据运维,包括数据集成,数据质量的管控,还有整个数据地图,数据安全。当年优酷从Hadoop迁到MaxCompute之后,我们最大的体会是自己不用半夜经常起来去维护集群了,不用去跑任务了,写一个任务,别人之前提一个需求过来,我可能要给他排几周,而现在我可以告诉他,我给你马上跑一下,就可以出来了。包括之前像分析师BI还要登录客户端,写脚本,自己写调度,经常会说我的数今天为什么没出来?包括高层看的数,可能要到12点钟才能出来。而现在基本上所有重要的数据都会在7点钟产出,包括一些基本的业务需求,其实分析师或者产品,他们自己都可以实现了,不需要所有需求都提到数据这边。 第二个特点,完整的生态。优酷在2017年之前是完全基于Hadoop的生态,迁到MaxCompute之后,是基于阿里云提供的Serverless大数据服务的生态。大家可以在开源上看到的组件,在整个的MaxCompute上都是有的,而且比开源的要更好用、更简单。从架构图上可以看到,我们中间是MaxCompute,左侧依赖的Mysql、Hbase、ES、Redis这些都是由同步中心去做一个双向的同步。右侧会有资源管理、资源监控、数据监控,包括数据资产,还有一些数据规范。我们下层的数据输入,包括一些集团的采集工具,再往上边,有提供给开发人员用的DataWorks,包括一些命令行的工具;有提供给BI人员用的QuickBI及数据服务。 第三个特点,强悍的性能,MaxCompute支撑了优酷EB级的数据存储,千亿级的数据样本分析,包括千亿级的数据报表,10W级实例的并发、任务。这些在之前维护Hadoop的时候,是想都不敢想的。 第四个特点,资源使用的弹性。我们在2016年迁移之前,其实优酷的Hadoop集群规模已经达到了一千多台,这个当时还是一个比较大的规模。当时我们遇到了很多问题,包括像NameNode 这种内存的问题,机房没有办法再扩容的问题,当时是非常痛苦的,包括一些运维管理上面的问题。我们不断的去问运维要资源,运维告诉说,说你们已经花了多少多少资源,花了多少多少钱。我们面临的问题是计算资源如何按需使用,夜里的时候作业很多,到了下午之后,我的整个集群都空下来了,没有人用,造成了浪费。其实MaxCompute完美的解决了这个问题。 第一个,它是按用量计费的,不是说给你多少台机器,然后就收你多少钱的,真的是你用了多少资源收多少钱的,这个在成本上来说,比自己去维护集群,可能是一个砍半(降50%)这样的收益。 第二个,实际上MaxCompue计算资源是可以分时的,比如说生产队列,凌晨的时候会调高一些,保证报表能够尽快出来。到白天时候,让开发的计算资源高一些,可以让分析师、开发去临时跑一些数据,会更顺畅一些。 第三个,MaxCompute快速的扩容能力,比如说突然有一个比较强的业务需求,发现数据跑不动了,计算资源不够,所有的队列都堵死了,这个时候其实可以直接跟运维说一声,帮忙一键扩容,他两秒钟敲一个命令就搞定了。这样的话,所有的资源可以迅速的消化下去。 上面是优酷为什么采用MaxCompute,下面是在优酷的业务场景下,我们一些典型的方案、应用。这张图实际上是优酷,包括可能现在阿里集团内部一些非常典型的技术架构图。中间可以看到,MaxCompute在中间核心的位置,左侧主要是一个输入,右侧是一个输出的趋向,绿色的线是一个实时的链路,包括现在我们从整个的数据源上,比如DB也好或者服务器的本地日志Log也好,我们通过TT&Datahub存储到MaxCompute上面做分析。当然现在非常火的Flink实时计算,其实是作为一个实时处理的链路。 包括DB的同步,除了实时的链路,DB也会去通过按天/按小时,把数据同步到MaxCompute,数据计算结果也可以同步到Hbase、Mysql这种DB上面。再通过统一的服务层对应用提供服务。下面这个是机器学习Pai做的一些算法训练,再把训练的结果通过OSS传到一个算法的应用上面去。 这张图可能也是业界比较流行的一个数仓分层的图,因为我们这边是数据中台,所有的数据都是统一从ods层cdm层,然后ads层,去一层一层的往上去做精细,再到最上面,通过接口服务、文件服务、SQL服务,去提供多样化的服务。再往上面,提供对内的一些数据产品,对高管、对小二,可能还有一些对外的,比如说像优酷的播放数,包括热度这些对应用的数据。 这张图其实就是我们从Hadoop迁到MaxCompute平台上以来,两个非常经典的案例。我们通过数据中台对不同场景的用户打通,来去赋能到两个不同的场景,提升业务价值。 第二个,可能是内部的,我们通过优酷,还有集团内部的一些BU去做换量,我们通过统一的标签去做样本放大,把优酷的量导给其它的BU,把其它BU的量导给优酷,这样去达到一个共赢的效果。 这张图大部分互联网公司不太会涉及到,就是关于反作弊的问题。这个是我们在MaxCompute做的一个反作弊的架构,通过原始的数据去提取它的特征,然后再通过算法模型,包括机器学习、深度学习、图模型去支持流量反作弊、渠道反作弊等等。再通过业务场景上反作弊的监控工具,把监控到的作弊信息去打一个黑白样本,再把这个黑白样本跟特征一起来不断的迭代优化算法模型。同时针对算法模型,做一个模型的评价,不断来完善反作弊体系。 最后一点,其实还是跟成本相关,在日常使用中,一定是有小白用户或者一些新来的用户去错误的使用或者不在乎的使用一些资源,比如经常会有一些实习生或者是非技术的同学,如分析师,一个SQL消费比较高,这个其实是非常浪费资源,而且可能他一个任务,让其他所有人的任务都在这儿等着排队,实际上我们会去对整个的资源做一个治理。 从节点的粒度上,通过大数据来治理大数据,我们可以算出哪些表产出来之后,多少天没有被读取的,包括它的访问跨度可能没有那么大的,我们会去做下线或者去做治理,有一些业务场景可能并不是非常的重要或者它的时间要求没有那么高,比如一些算法训练,可以去做一些错峰的调度,保证水位不要太高。从MaxCompute任务的角度,可以算出哪些任务有数据倾斜、哪些数据可能会有相似计算,哪些任务需要去做MapJoin,哪些任务需要去做一些裁剪,然后来节省它的IO。还有哪些任务会去做暴力扫描,扫一个月、扫一年的数据,哪些数据可能会有这样一个数据膨胀,比如说它做了CUBE之类的这种复杂计算,一些算法模型的迭代;我们通过数据计算出来的这些迹象,去反推用户,来去提高它的这样一个数据的质量分,来去达到我们降低整个计算资源的目的。 在计算平台的角度,我们也持续的在使用MaxCompute推出的一些非常高级的用法,比如我们这边的HBO、Hash Cluster、Aliorc,HBO就是我们基于一个历史的优化,这样避免了用户不知道怎么调参,我可能为了自己任务快一点,就调一个特别大的参数,这样的话,对集成的资源是非常浪费的。通过这个功能,用户就不用去调参数,集群自动调好,用户就写好自己业务逻辑就好了。 第二块,可能就是最近两年推出的Hash Cluster,当时在使用Hadoop的时候经常会出现,两个大表Join的时候计算不出来,这个Hash Cluster其实是一个优化的利器。大表跟小表Join,可以做一些分发,做一些优化。大表跟大表就涉及到一个排序的问题。这个Hash Cluster,实际上就是提前把数据排好,中间省掉很多计算环节,来达到效率提升的目的。 第三个,Aliorc,在一些固定的场景上面,可以稳定的提升20%的计算效率。 第四个,Session。对一些比较小的数据,直接就放到SSD或缓存里面,一个节点下游有100个叶子场景,是非常友好的,因为低延迟秒出结果。同时,优酷也在使用Lightning解决计算加速,这个是在一个计算架构方案上的优化,它是一个MPP的架构。 最后一页是存储的优化,因为像一些关键的原始数据或者是需要审计的数据是不能删的,永久不能删的。实际上就会造成我们数据存储的趋势是一直往上不减的,计算会在某一个时间点达到一个平衡。当前用这么多的计算资源,再往后,其实应该也不会再大涨了,比如说旧的业务逻辑下掉了,会换新的业务逻辑,这样会保持在一个相对平稳的波动上面。但是储存,因为它有一些历史的数据是永远不能删的,可能会出现一直在增长,而且是指数级的。所以我们也会持续关注存储的情况,我们主要有四个手段。 第一个,还是通过大数据来治大数据,去看哪些表它的访问不够或者它的访问跨度不够。就是对一些生命周期的优化,来去控制它的增速。包括下面的,刚才提到的Aliorc,实际上是做压缩的,我们会去做一些大字段的拆分,来提高压缩的比例。 OK,这个是优酷在MaxCompute中的一些应用场景,感谢大家的聆听。 本文作者:隐林原文链接 本文为云栖社区原创内容,未经允许不得转载。

June 13, 2019 · 1 min · jiezi

一键托管阿里云全链路追踪服务正式商用成本仅自建15或更少

随着互联网架构的扩张,分布式系统变得日趋复杂,越来越多的组件开始走向分布式化,如微服务、消息收发、分布式数据库、分布式缓存、分布式对象存储、跨域调用,这些组件共同构成了繁杂的分布式网络。 在一次800多人的开发者调研中,当回答“现阶段构建一个高可用的分布式系统,您遇到的三个最大的难题是什么?”时,57%的开发者选择了全链路追踪。 6月12日,阿里云发布了链路追踪服务 Tracing Analysis,提供分布式系统的全链路追踪能力,帮助客户快速发现和定位分布式系统下的各类性能瓶颈,成本仅自建链路追踪系统的1/5甚至更少。 微服务架构下的分布式应用架构虽然满足了应用横向扩展需求,但是如何进行分布式应用诊断成为挑战。虽然,业内有链路追踪相关的开源解决方案,但存在着研发投入较高、自建成本较高、技术风险较大、运维难度较大的挑战。 链路追踪 Tracing Analysis源自阿里巴巴内部的经过大规模实战验证过的 EagleEye,基于 Opentracing 标准,全面兼容开源社区,可实现 Jaeger, Zipkin 和 Skywalking等开源方案在阿里云上的托管,客户无需搭建基础设施,节省运维投入和技术风险。同时,支持多语言客户端将应用的链路数据上报至链路追踪控制台,实现链路追踪的目的。 据介绍,链路追踪 Tracing Analysis 可用于链路拓扑分析,慢请求、异常请求、流量异常的问题发现和定位,并可以根据业务Tag 对业务进行统计。以某教育行业客户为例,链路追踪 Tracing Analysis 帮助客户将异常请求数从原先的3%降低到0.1%,排查5个以上线上问题。 此外,链路追踪 Tracing Analysis可帮助用户收集所有分布式微服务应用和相关PaaS产品的分布式调用信息,查看应用的依赖路径,用于业务分析和稳定性评估。以某金融行业客户为例,链路追踪 Tracing Analysis 帮助客户将将应用的平均响应时间从2秒降低到500毫秒。 值得注意的是,链路追踪 Tracing Analysis 省去了客户自建基础设施的本地存储费用,仅通过云端日志存储收取存储费用,总体的机器成本是自建全链路追踪系统的1/5或更少,并提供了每天1000请求数的免费使用额度。 目前,阿里云链路追踪 Tracing Analysis已应用于金融、游戏、教育、零售、人工智能等多个行业,帮助开发者高效的分析和诊断分布式应用架构下的性能瓶颈。 Q&A: Q1:可以通过 API 拉取链路追踪的数据吗?A1:支持,收集的链路可以通过OpenAPI的方式获取,也可以嵌入链路追踪的页面展示,也可以直接在日志服务中查看。 Q2:非阿里云服务,可以接入链路追踪?A2:链路是追踪是开放的,只要客户的应用可以访问公网,就可以接入,和有没部署在阿里云上没关系。 Q3:埋点对性能的影响有相关分析么?A3:埋点数据是异步批量上报的,会对性能有影响有限,一般在1%左右,主要看埋点的量,埋的多会影响大一点。从目前的压测数据来看,对性能影响比较小。 本文作者:中间件小哥原文链接  本文为云栖社区原创内容,未经允许不得转载。

June 13, 2019 · 1 min · jiezi

分表后需要注意的二三事

前言本篇是上一篇《一次分表踩坑实践的探讨》,所以还没看过的朋友建议先看上文。 还是先来简单回顾下上次提到了哪些内容: 分表策略:哈希、时间归档等。分表字段的选择。数据迁移方案。而本篇文章的背景是在我们上线这段时间遇到的一些问题并尝试解决的方案。 问题产生之前提到在分表应用上线前我们需要将原有表的数据迁移到新表中,这样才能保证业务不受影响。 所以我们单独写了一个迁移应用,它负责将大表中的数据迁移到 64 张分表,而再迁移过程中产生的数据毕竟是少数,最后在上线当晚再次迁移过去即可。 一切想的很美好,当这个应用上线后却发现没这么简单。 数据库负载升高首先第一个问题是数据库自己就顶不住了,在我们上这个迁移程序之前数据库的压力本身就比较大,这个应用一上去就成了最后一根稻草。 最后导致的结果是:所有连接了数据库的程序大部分的操作都出现超时,获取不到数据库连接等一系列的异常。 最后没办法我们只能把这个应用放到凌晨执行,但其实后面观察发现依然不行。 虽说凌晨的业务量下降,但依然有少部分的请求过来,也会出现各种数据库异常。 再一个是迁移程序的效率也非常低下,按照这样是速度,我们预估了一下迁移时间,大约需要 10 几天才能把三张最大的表(3、4亿的数据)迁移到分表中。 于是我们换了一个方案,将这个迁移程序在从库中运行,最后再用运维的方法将分表直接导入进主库。 因为从库的压力要比主库小很多,对业务的影响很小,同时迁移的效率也要快很多。 即便是这样也花了一晚上+一个白天的时间才将一张 1亿的数据迁移完成,但是业务上的压力越来越大,数据量再不断新增,这个效率依然不够。 兼容方案最终没办法只有想一个不迁移数据的方案,但是新产生的数据还是往分表里写,至少保证大表的数据不再新增。 但这样对于以前的数据咋办呢?总不能不让看了吧。 其实对于数据的操作无非就分为增删改查,就这四种操作来看看如何兼容。 新增 新增最简单,所有的数据根据分表规则直接写入新表,这样可以保证老表的数据不再新增。 删除删除就要比新增稍微复杂一些,比如用户想要删除他个人产生的一条信息(比如说是订单数据),有可能这个数据在新表也可能在老表。 所以删除时优先删除新表(毕竟新产生的数据访问的频次越高),如果删除失败再从老表删除一次。 修改 而修改同理,同样的会不确定数据存在于哪里,所以先要修改新表,失败后再次修改老表。 查询查询相对就要复杂一些了,因为这些大表的数据大部分都是存放一个用户产生的多条记录(比如一个用户的订单信息)。 这时在页面上通常都会有分页,并且按照时间进行排序。 麻烦的地方就出在这里:既然是要分页那就有可能出现要查询一部分分表数据和原来的大表数据做组合。 所以这里的查询其实分为三种情况。 首先查询的时候要计算这个用户所在分表中的数据可以分为几页。第一步首先判断当前页是否可以在分表中全部获取,如果可以则直接从分表中取出数据返回(假设分页中总共可以查询 2 页数据,当前为第 1 页,那就全部取分表数据)。如果不可以就要判断当前页数在分表中是否取不到任何一条数据,如果是则直接取老表数据(比如现在要取第 5 页的数据,分表中一共才只有 2 页数据,所以第 5 页数据只能全部从老表中获取)。但如果分表和老表都存在一部分数据时,则需要同时取两张表然后做一个汇总再返回。这种逻辑只适用于根据分表字段进行查询分页的前提下 我想肯定会有朋友提出这样是否会有性能问题? 同时如果在计算分表分页数量时出现并发写入的情况,导致分页数量不准从而对后续的查询出现影响该怎么处理? 首先第一个性能问题: 其实这个要看怎么取舍,为了这样的兼容目的其实会比常规查询多出几个步骤: 判断当前页是否可以在分表中查询。当新老表中都有数据时候需要额外多查询一张大表。第一个判断逻辑其实是在内存中计算,这个损耗我觉得完全可以忽略不计。 至于第二步确实会有损耗,毕竟多查了一张表。 但在分表之前所有的数据都是从老表中获取的,当时的业务也没有出现问题;现在多的只是查询分表而已,但分表的数据量肯定要比大表小的多,而且有索引,所以这个效率也不会慢多少。 而且根据局部性原理及用户的使用习惯来看,老表中的数据很少会去查询,随着时间的推移所有的数据肯定都会从分表中获取,逐渐老表就会成为历史表。 而第二个并发带来的问题我觉得影响也不大,一定要这个分页准的前提肯定得是加锁了,但为了这样一个不痒的小问题却带来性能的下降,我觉得是不划算的。 而且后续我们也可以慢慢的将老表的数据迁移到新表,这样就可以完全去掉这个兼容逻辑了,所有的数据都从分表中获取。 总结还是之前那句话,这里的各种操作、方法不适合所有人,毕竟脱离场景都是耍牛氓。 比如分表搞的早,业务上允许一定的时间将数据迁移到分表那就不会有这次的兼容处理。 甚至一开始业务规划合理、团队架构师看的长远,一来就将关键数据分表存储那根本就不会有数据迁移这个流程(大厂有经验的团队可能,小公司小作坊都得靠自己摸索)。 这段期间也被数据库折腾惨了,数据库是最后一根稻草果然也不是瞎说的。 你的点赞与分享是对我最大的支持

June 13, 2019 · 1 min · jiezi

一文读懂架构整洁之道附知识脉络图

程序的世界飞速发展,今天所掌握的技能可能明年就过时了,但有一些东西是历久弥新,永远不变的,掌握了这些,在程序的海洋里就不会迷路,架构思想就是这样一种东西。 本文是《架构整洁之道》的读书笔记,文章从软件系统的价值出发,认识架构工作的价值和目标, 依次了解架构设计的基础、指导思想(设计原则)、组件拆分的方法和粒度、组件之间依赖设计、组件边界多种解耦方式以及取舍、降低组件之间通信成本的方法,从而在做出正确的架构决策和架构设计方面,给出作者自己的解读。 阿里巴巴中间件微信公众号对话框,发送“架构”,可获取《架构整洁之道》知识脉络图。直接访问,点击这里。 一、软件系统的价值架构是软件系统的一部分,所以要明白架构的价值,首先要明确软件系统的价值。软件系统的价值有两方面,行为价值和架构价值。 行为价值是软件的核心价值,包括需求的实现,以及可用性保障(功能性 bug 、性能、稳定性)。这几乎占据了我们90%的工作内容,支撑业务先赢是我们工程师的首要责任。如果业务是明确的、稳定的,架构的价值就可以忽略不计,但业务通常是不明确的、飞速发展的,这时架构就无比重要,因为架构的价值就是让我们的软件(Software)更软(Soft)。可以从两方面理解: 当需求变更时,所需的软件变更必须简单方便。变更实施的难度应该和变更的范畴(scope)成等比,而与变更的具体形状(shape)无关。当我们只关注行为价值,不关注架构价值时,会发生什么事情?这是书中记录的一个真实案例,随着版本迭代,工程师团队的规模持续增长,但总代码行数却趋于稳定,相对应的,每行代码的变更成本升高、工程师的生产效率降低。从老板的视角,就是公司的成本增长迅猛,如果营收跟不上就要开始赔钱啦。 可见架构价值重要性,接下来从著名的紧急重要矩阵出发,看我们如何处理好行为价值和架构价值的关系。 重要紧急矩阵中,做事的顺序是这样的:1.重要且紧急 > 2.重要不紧急 > 3.不重要但紧急 > 4.不重要且不紧急。实现行为价值的需求通常是 PD 提出的,都比较紧急,但并不总是特别重要;架构价值的工作内容,通常是开发同学提出的,都很重要但基本不是很紧急,短期内不做也死不了。所以行为价值的事情落在1和3(重要且紧急、不重要但紧急),而架构价值落在2(重要不紧急)。我们开发同学,在低头敲代码之前,一定要把杂糅在一起的1和3分开,把我们架构工作插进去。 二、架构工作的目标前面讲解了架构价值,追求架构价值就是架构工作的目标,说白了,就是用最少的人力成本满足构建和维护该系统的需求,再细致一些,就是支撑软件系统的全生命周期,让系统便于理解、易于修改、方便维护、轻松部署。对于生命周期里的每个环节,优秀的架构都有不同的追求: 开发阶段:组件不要使用大量复杂的脚手架;不同团队负责不同的组件,避免不必要的协作。部署阶段:部署工作不要依赖成堆的脚本和配置文件;组件越多部署工作越繁重,而部署工作本身是没有价值的,做的越少越好,所以要减少组件数量。运行阶段:架构设计要考虑到不同的吞吐量、不同的响应时长要求;架构应起到揭示系统运行的作用:用例、功能、行为设置应该都是对开发者可见的一级实体,以类、函数或模块的形式占据明显位置,命名能清晰地描述对应的功能。维护阶段:减少探秘成本和风险。探秘成本是对现有软件系统的挖掘工作,确定新功能或修复问题的最佳位置和方式。风险是做改动时,可能衍生出新的问题。三、编程范式其实所谓架构就是限制,限制源码放在哪里、限制依赖、限制通信的方式,但这些限制比较上层。编程范式是最基础的限制,它限制我们的控制流和数据流:结构化编程限制了控制权的直接转移,面向对象编程限制了控制权的间接转移,函数式编程限制了赋值,相信你看到这里一定一脸懵逼,啥叫控制权的直接转移,啥叫控制权的间接转移,不要着急,后边详细讲解。 这三个编程范式最近的一个也有半个世纪的历史了,半个世纪以来没有提出新的编程范式,以后可能也不会了。因为编程范式的意义在于限制,限制了控制权转移限制了数据赋值,其他也没啥可限制的了。很有意思的是,这三个编程范式提出的时间顺序可能与大家的直觉相反,从前到后的顺序为:函数式编程(1936年)、面向对象编程(1966年)、结构化编程(1968年)。 1.结构化编程 结构化编程证明了人们可以用顺序结构、分支结构、循环结构这三种结构构造出任何程序,并限制了 goto 的使用。遵守结构化编程,工程师就可以像数学家一样对自己的程序进行推理证明,用代码将一些已证明可用的结构串联起来,只要自行证明这些额外代码是确定的,就可以推导出整个程序的正确性。 前面提到结构化编程对控制权的直接转移进行了限制,其实就是限制了 goto 语句。什么叫做控制权的直接转移?就是函数调用或者 goto 语句,代码在原来的流程里不继续执行了,转而去执行别的代码,并且你指明了执行什么代码。为什么要限制 goto 语句?因为 goto 语句的一些用法会导致某个模块无法被递归拆分成更小的、可证明的单元。而采用分解法将大型问题拆分正是结构化编程的核心价值。 其实遵守结构化编程,工程师们也无法像数学家那样证明自己的程序是正确的,只能像物理学家一样,说自己的程序暂时没被证伪(没被找到bug)。数学公式和物理公式的最大区别,就是数学公式可被证明,而物理公式无法被证明,只要目前的实验数据没把它证伪,我们就认为它是正确的。程序也是一样,所有的 test case 都通过了,没发现问题,我们就认为这段程序是正确的。 2.面向对象编程 面向对象编程包括封装、继承和多态,从架构的角度,这里只关注多态。多态让我们更方便、安全地通过函数调用的方式进行组件间通信,它也是依赖反转(让依赖与控制流方向相反)的基础。 在非面向对象的编程语言中,我们如何在互相解耦的组件间实现函数调用?答案是函数指针。比如采用C语言编写的操作系统中,定义了如下的结构体来解耦具体的IO设备, IO 设备的驱动程序只需要把函数指针指到自己的实现就可以了。 struct FILE { void (*open)(char* name, int mode); void (*close)(); int (*read)(); void (*write)(char); void (*seek)(long index, int mode);}这种通过函数指针进行组件间通信的方式非常脆弱,工程师必须严格按照约定初始化函数指针,并严格地按照约定来调用这些指针,只要一个人没有遵守约定,整个程序都会产生极其难以跟踪和消除的 Bug。所以面向对象编程限制了函数指针的使用,通过接口-实现、抽象类-继承等多态的方式来替代。 前面提到面向对象编程对控制权的间接转移进行了限制,其实就是限制了函数指针的使用。什么叫做控制权的间接转移?就是代码在原来的流程里不继续执行了,转而去执行别的代码,但具体执行了啥代码你也不知道,你只调了个函数指针或者接口。 ...

June 12, 2019 · 1 min · jiezi

NoSQL-数据库不应该放弃-Consistency

本文发于infoq,https://www.infoq.cn/article/rhzs0KI2G*Y2r9PMdeNv 。转回自己的博客。 谈到 NoSQL,一定会提及一致性(Consistency),按照 CAP 定理,有些 NoSQL 数据库放弃了一致性,但是 NoSQL 放弃是必然的选择吗? 从 1970’s,关系型数据库(RDB,Relational Database)被发明以来,关系型数据库就是构建应用的通常的选择。关系型数据库对用户提供 ACID 保证,非常方便开发者使用。从 1990’s 开始,NoSQL 系统开始出现。NoSQL 系统是一类对立于关系数据库的数据库系统,他们从架构上放弃了传统的关系型数据库的的关系模型和 SQL 的接口。 与 NoSQL 系统相伴而来的 2 个词是 BASE 和 CAP,这 2 个词对分布式系统有着非常深远的影响。我相信就是在这 2 个词的影响下,很多 NoSQL 系统从架构的初始就放弃了一致性(consistency)选择了一种最终一致性(Eventual consistency)和可用性 (Availability)。虽然我非常认同 CAP 和 BASE 这 2 个词,但是我不认为在 CAP 和 BASE 的作用下,NoSQL 系统选择放弃一致性是一个必然的事情。 首先来回顾一下 CAP 和 BASE 这 2 个概念的历史。这 2 个概念都是由 Eric Brewer 提出的,Brewer 目前是 Google 公司的基础设施部门(Infrastructure)的副总裁(VP,Vice President)。在 1997 年,在 SOSP(Symposium on Operating Systems Principles) 上,名为的演讲 [1] 总结了 Brewer 等人的近期工作,演讲中说他们正在工作的集群服务并没有采用当时公认的具有 ACID 特性的关系型数据库作为架构,而是在架构上放弃了关系型数据库的 ACID 特性。并且为他们的这个架构选择构造了一个新的词 BASE,BASE 这个词的选择有刻意为之成分,ACID 在英语里有酸性的意思,而 BASE 有碱性的意思,很明显 BASE 是与?ACID 对立的。 ...

June 12, 2019 · 2 min · jiezi

高性能服务器架构思路不仅是思路

在服务器端程序开发领域,性能问题一直是备受关注的重点。业界有大量的框架、组件、类库都是以性能为卖点而广为人知。然而,服务器端程序在性能问题上应该有何种基本思路,这个却很少被这些项目的文档提及。本文正式希望介绍服务器端解决性能问题的基本策略和经典实践,并分为几个部分来说明: 缓存策略的概念和实例2.缓存策略的难点:不同特点的缓存数据的清理机制 3.分布策略的概念和实例 4.分布策略的难点:共享数据安全性与代码复杂度的平衡 缓存缓存策略的概念我们提到服务器端性能问题的时候,往往会混淆不清。因为当我们访问一个服务器时,出现服务卡住不能得到数据,就会认为是“性能问题”。但是实际上这个性能问题可能是有不同的原因,表现出来都是针对客户请求的延迟很长甚至中断。我们来看看这些原因有哪些:第一个是所谓并发数不足,也就是同时请求的客户过多,导致超过容纳能力的客户被拒绝服务,这种情况往往会因为服务器内存耗尽而导致的;第二个是处理延迟过长,也就是有一些客户的请求处理时间已经超过用户可以忍受的长度,这种情况常常表现为CPU占用满额100%。 我们在服务器开发的时候,最常用到的有下面这几种硬件:CPU、内存、磁盘、网卡。其中CPU是代表计算机处理时间的,硬盘的空间一般很大,主要是读写磁盘会带来比较大的处理延迟,而内存、网卡则是受存储、带宽的容量限制的。所以当我们的服务器出现性能问题的时候,就是这几个硬件某一个甚至几个都出现负荷占满的情况。这四个硬件的资源一般可以抽象成两类:一类是时间资源,比如CPU和磁盘读写;一类是空间资源,比如内存和网卡带宽。所以当我们的服务器出现性能问题,有一个最基本的思路,就是——时间空间转换。我们可以举几个例子来说明这个问题。 当我们访问一个WEB的网站的时候,输入的URL地址会被服务器变成对磁盘上某个文件的读取。如果有大量的用户访问这个网站,每次的请求都会造成对磁盘的读操作,可能会让磁盘不堪重负,导致无法即时读取到文件内容。但是如果我们写的程序,会把读取过一次的文件内容,长时间的保存在内存中,当有另外一个对同样文件的读取时,就直接从内存中把数据返回给客户端,就无需去让磁盘读取了。由于用户访问的文件往往很集中,所以大量的请求可能都能从内存中找到保存的副本,这样就能大大提高服务器能承载的访问量了。这种做法,就是用内存的空间,换取了磁盘的读写时间,属于用空间换时间的策略。 举另外一个例子:我们写一个网络游戏的服务器端程序,通过读写数据库来提供玩家资料存档。如果有大量玩家进入这个服务器,必定有很多玩家的数据资料变化,比如升级、获得武器等等,这些通过读写数据库来实现的操作,可能会让数据库进程负荷过重,导致玩家无法即时完成游戏操作。我们会发现游戏中的读操作,大部分都是针是对一些静态数据的,比如游戏中的关卡数据、武器道具的具体信息;而很多写操作,实际上是会覆盖的,比如我的经验值,可能每打一个怪都会增加几十点,但是最后记录的只是最终的一个经验值,而不会记录下打怪的每个过程。所以我们也可以使用时空转换的策略来提供性能:我们可以用内存,把那些游戏中的静态数据,都一次性读取并保存起来,这样每次读这些数据,都和数据库无关了;而玩家的资料数据,则不是每次变化都去写数据库,而是先在内存中保持一个玩家数据的副本,所有的写操作都先去写内存中的结构,然后定期再由服务器主动写回到数据库中,这样可以把多次的写数据库操作变成一次写操作,也能节省很多写数据库的消耗。这种做法也是用空间换时间的策略。 最后说说用时间换空间的例子:假设我们要开发一个企业通讯录的数据存储系统,客户要求我们能保存下通讯录的每次新增、修改、删除操作,也就是这个数据的所有变更历史,以便可以让数据回退到任何一个过去的时间点。那么我们最简单的做法,就是这个数据在任何变化的时候,都拷贝一份副本。但是这样会非常的浪费磁盘空间,因为这个数据本身变化的部分可能只有很小一部分,但是要拷贝的副本可能很大。这种情况下,我们就可以在每次数据变化的时候,都记下一条记录,内容就是数据变化的情况:插入了一条内容是某某的联系方法、删除了一条某某的联系方法……,这样我们记录的数据,仅仅就是变化的部分,而不需要拷贝很多份副本。当我们需要恢复到任何一个时间点的时候,只需要按这些记录依次对数据修改一遍,直到指定的时间点的记录即可。这个恢复的时间可能会有点长,但是却可以大大节省存储空间。这就是用CPU的时间来换磁盘的存储空间的策略。我们现在常见的MySQL InnoDB日志型数据表,以及SVN源代码存储,都是使用这种策略的。 另外,我们的Web服务器,在发送HTML文件内容的时候,往往也会先用ZIP压缩,然后发送给浏览器,浏览器收到后要先解压,然后才能显示,这个也是用服务器和客户端的CPU时间,来换取网络带宽的空间。 在我们的计算机体系中,缓存的思路几乎无处不在,比如我们的CPU里面就有1级缓存、2级缓存,他们就是为了用这些快速的存储空间,换取对内存这种相对比较慢的存储空间的等待时间。我们的显示卡里面也带有大容量的缓存,他们是用来存储显示图形的运算结果的。 缓存的本质,除了让“已经处理过的数据,不需要重复处理”以外,还有“以快速的数据存储读写,代替较慢速的存储读写”的策略。我们在选择缓存策略进行时空转换的时候,必须明确我们要转换的时间和空间是否合理,是否能达到效果。比如早期有一些人会把WEB文件缓存在分布式磁盘上(例如NFS),但是由于通过网络访问磁盘本身就是一个比较慢的操作,而且还会占用可能就不充裕的网络带宽空间,导致性能可能变得更慢。 在设计缓存机制的时候,我们还容易碰到另外一个风险,就是对缓存数据的编程处理问题。如果我们要缓存的数据,并不是完全无需处理直接读写的,而是需要读入内存后,以某种语言的结构体或者对象来处理的,这就需要涉及到“序列化”和“反序列化”的问题。如果我们采用直接拷贝内存的方式来缓存数据,当我们的这些数据需要跨进程、甚至跨语言访问的时候,会出现那些指针、ID、句柄数据的失效。因为在另外一个进程空间里,这些“标记型”的数据都是不存在的。因此我们需要更深入的对数据缓存的方法,我们可能会使用所谓深拷贝的方案,也就是跟着那些指针去找出目标内存的数据,一并拷贝。一些更现代的做法,则是使用所谓序列化方案来解决这个问题,也就是用一些明确定义了的“拷贝方法”来定义一个结构体,然后用户就能明确的知道这个数据会被拷贝,直接取消了指针之类的内存地址数据的存在。比如著名的Protocol Buffer就能很方便的进行内存、磁盘、网络位置的缓存;现在我们常见的JSON,也被一些系统用来作为缓存的数据格式。 但是我们需要注意的是,缓存的数据和我们程序真正要操作的数据,往往是需要进行一些拷贝和运算的,这就是序列化和反序列化的过程,这个过程很快,也有可能很慢。所以我们在选择数据缓存结构的时候,必须要注意其转换时间,否则你缓存的效果可能被这些数据拷贝、转换消耗去很多,严重的甚至比不缓存更差。一般来说,缓存的数据越解决使用时的内存结构,其转换速度就越快,在这点上,Protocol Buffer采用TLV编码,就比不上直接memcpy的一个C结构体,但是比编码成纯文本的XML或者JSON要来的更快。因为编解码的过程往往要进行复杂的查表映射,列表结构等操作。 缓存策略的难点虽然使用缓存思想似乎是一个很简单的事情,但是缓存机制却有一个核心的难点,就是——缓存清理。我们所说的缓存,都是保存一些数据,但是这些数据往往是会变化的,我们要针对这些变化,清理掉保存的“脏”数据,却可能不是那么容易。 首先我们来看看最简单的缓存数据——静态数据。这种数据往往在程序的运行时是不会变化的,比如Web服务器内存中缓存的HTML文件数据,就是这种。事实上,所有的不是由外部用户上传的数据,都属于这种“运行时静态数据”。一般来说,我们对这种数据,可以采用两种建立缓存的方法:一是程序一启动,就一股脑把所有的静态数据从文件或者数据库读入内存;二就是程序启动的时候并不加载静态数据,而是等有用户访问相关数据的时候,才去加载,这也就是所谓lazy load的做法。第一种方法编程比较简单,程序的内存启动后就稳定了,不太容易出现内存漏洞(如果加载的缓存太多,程序在启动后立刻会因内存不足而退出,比较容易发现问题);第二种方法程序启动很快,但要对缓存占用的空间有所限制或者规划,否则如果要缓存的数据太多,可能会耗尽内存,导致在线服务中断。 一般来说,静态数据是不会“脏”的,因为没有用户会去写缓存中的数据。但是在实际工作中,我们的在线服务往往会需要“立刻”变更一些缓存数据。比如在门户网站上发布了一条新闻,我们会希望立刻让所有访问的用户都看到。按最简单的做法,我们一般只要重启一下服务器进程,内存中的缓存就会消失了。对于静态缓存的变化频率非常低的业务,这样是可以的,但是如果是新闻网站,就不能每隔几分钟就重启一下WEB服务器进程,这样会影响大量在线用户的访问。常见的解决这类问题有两种处理策略: 第一种是使用控制命令。简单来说,就是在服务器进程上,开通一个实时的命令端口,我们可以通过网络数据包(如UDP包),或者Linux系统信号(如kill SIGUSR2进程号)之类的手段,发送一个命令消息给服务器进程,让进程开始清理缓存。这种清理可能执行的是最简单的“全部清理”,也有的可以细致一点的,让命令消息中带有“想清理的数据ID”这样的信息,比如我们发送给WEB服务器的清理消息网络包中会带一个字符串URL,表示要清理哪一个HTML文件的缓存。这种做法的好处是清理的操作很精准,可以明确的控制清理的时间和数据。但是缺点就是比较繁琐,手工去编写发送这种命令很烦人,所以一般我们会把清理缓存命令的工作,编写到上传静态数据的工具当中,比如结合到网站的内容发布系统中,一旦编辑提交了一篇新的新闻,发布系统的程序就自动的发送一个清理消息给WEB服务器。 第二种是使用字段判断逻辑。也就是服务器进程,会在每次读取缓存前,根据一些特征数据,快速的判断内存中的缓存和源数据内容,是否有不一致(是否脏)的地方,如果有不一致的地方,就自动清理这条数据的缓存。这种做法会消耗一部分CPU,但是就不需要人工去处理清理缓存的事情,自动化程度很高。现在我们的浏览器和WEB服务器之间,就有用这种机制:检查文件MD5;或者检查文件最后更新时间。具体的做法,就是每次浏览器发起对WEB服务器的请求时,除了发送URL给服务器外,还会发送一个缓存了此URL对应的文件内容的MD5校验串、或者是此文件在服务器上的“最后更新时间”(这个校验串和“最后更新时间”是第一次获的文件时一并从服务器获得的);服务器收到之后,就会把MD5校验串或者最后更新时间,和磁盘上的目标文件进行对比,如果是一致的,说明这个文件没有被修改过(缓存不是“脏”的),可以直接使用缓存。否则就会读取目标文件返回新的内容给浏览器。这种做法对于服务器性能是有一定消耗的,所以如果往往我们还会搭配其他的缓存清理机制来用,比如我们会在设置一个“超时检查”的机制:就是对于所有的缓存清理检查,我们都简单的看看缓存存在的时间是否“超时”了,如果超过了,才进行下一步的检查,这样就不用每次请求都去算MD5或者看最后更新时间了。但是这样就存在“超时”时间内缓存变脏的可能性。 上面说了运行时静态的缓存清理,现在说说运行时变化的缓存数据。在服务器程序运行期间,如果用户和服务器之间的交互,导致了缓存的数据产生了变化,就是所谓“运行时变化缓存”。比如我们玩网络游戏,登录之后的角色数据就会从数据库里读出来,进入服务器的缓存(可能是堆内存或者memcached、共享内存),在我们不断进行游戏操作的时候,对应的角色数据就会产生修改的操作,这种缓存数据就是“运行时变化的缓存”。这种运行时变化的数据,有读和写两个方面的清理问题:由于缓存的数据会变化,如果另外一个进程从数据库读你的角色数据,就会发现和当前游戏里的数据不一致;如果服务器进程突然结束了,你在游戏里升级,或者捡道具的数据可能会从内存缓存中消失,导致你白忙活了半天,这就是没有回写(缓存写操作的清理)导致的问题。这种情况在电子商务领域也很常见,最典型的就是火车票网上购买的系统,火车票数据缓存在内存必须有合适的清理机制,否则让两个买了同一张票就麻烦了,但如果不缓存,大量用户同时抢票,服务器也应对不过来。因此在运行时变化的数据缓存,应该有一些特别的缓存清理策略。 在实际运行业务中,运行变化的数据往往是根据使用用户的增多而增多的,因此首先要考虑的问题,就是缓存空间不够的可能性。我们不太可能把全部数据都放到缓存的空间里,也不可能清理缓存的时候就全部数据一起清理,所以我们一般要对数据进行分割,这种分割的策略常见的有两种:一种是按重要级来分割,一种是按使用部分分割。 先举例说说“按重要级分割”,在网络游戏中,同样是角色的数据,有些数据的变化可能会每次修改都立刻回写到数据库(清理写缓存),其他一些数据的变化会延迟一段时间,甚至有些数据直到角色退出游戏才回写,如玩家的等级变化(升级了),武器装备的获得和消耗,这些玩家非常看重的数据,基本上会立刻回写,这些就是所谓最重要的缓存数据。而玩家的经验值变化、当前HP、MP的变化,就会延迟一段时间才写,因为就算丢失了缓存,玩家也不会太过关注。最后有些比如玩家在房间(地区)里的X/Y坐标,对话聊天的记录,可能会退出时回写,甚至不回写。这个例子说的是“写缓存”的清理,下面说说“读缓存”的按重要级分割清理。 假如我们写一个网店系统,里面容纳了很多产品,这些产品有一些会被用户频繁检索到,比较热销,而另外一些商品则没那么热销。热销的商品的余额、销量、评价都会比较频繁的变化,而滞销的商品则变化很少。所以我们在设计的时候,就应该按照不同商品的访问频繁程度,来决定缓存哪些商品的数据。我们在设计缓存的结构时,就应该构建一个可以统计缓存读写次数的指标,如果有些数据的读写频率过低,或者空闲(没有人读、写缓存)时间超长,缓存应该主动清理掉这些数据,以便其他新的数据能进入缓存。这种策略也叫做“冷热交换”策略。实现“冷热交换”的策略时,关键是要定义一个合理的冷热统计算法。一些固定的指标和算法,往往并不能很好的应对不同硬件、不同网络情况下的变化,所以现在人们普遍会用一些动态的算法,如Redis就采用了5种,他们是: 1.根据过期时间,清理最长时间没用过的 2.根据过期时间,清理即将过期的 3.根据过期时间,任意清理一个 4.无论是否过期,随机清理 5.无论是否过期,根据LRU原则清理:所谓LRU,就是Least Recently Used,最近最久未使用过。这个原则的思想是:如果一个数据在最近一段时间没有被访问到,那么在将来他被访问的可能性也很小。LRU是在操作系统中很常见的一种原则,比如内存的页面置换算法(也包括FIFO,LFU等),对于LRU的实现,还是非常有技巧的,但是本文就不详细去说明如何实现,留待大家上网搜索“LRU”关键字学习。 数据缓存的清理策略其实远不止上面所说的这些,要用好缓存这个武器,就要仔细研究需要缓存的数据特征,他们的读写分布,数据之中的差别。然后最大化的利用业务领域的知识,来设计最合理的缓存清理策略。这个世界上不存在万能的优化缓存清理策略,只存在针对业务领域最优化的策略,这需要我们程序员深入理解业务领域,去发现数据背后的规律。 分布分布策略的概念任何的服务器的性能都是有极限的,面对海量的互联网访问需求,是不可能单靠一台服务器或者一个CPU来承担的。所以我们一般都会在运行时架构设计之初,就考虑如何能利用多个CPU、多台服务器来分担负载,这就是所谓分布的策略。分布式的服务器概念很简单,但是实现起来却比较复杂。因为我们写的程序,往往都是以一个CPU,一块内存为基础来设计的,所以要让多个程序同时运行,并且协调运作,这需要更多的底层工作。 首先出现能支持分布式概念的技术是多进程。在DOS时代,计算机在一个时间内只能运行一个程序,如果你想一边写程序,同时一边听mp3,都是不可能的。但是,在WIN95操作系统下,你就可以同时开多个窗口,背后就是同时在运行多个程序。在Unix和后来的Linux操作系统里面,都普遍支持了多进程的技术。所谓的多进程,就是操作系统可以同时运行我们编写的多个程序,每个程序运行的时候,都好像自己独占着CPU和内存一样。在计算机只有一个CPU的时候,实际上计算机会分时复用的运行多个进程,CPU在多个进程之间切换。但是如果这个计算机有多个CPU或者多个CPU核,则会真正的有几个进程同时运行。所以进程就好像一个操作系统提供的运行时“程序盒子”,可以用来在运行时,容纳任何我们想运行的程序。当我们掌握了操作系统的多进程技术后,我们就可以把服务器上的运行任务,分为多个部分,然后分别写到不同的程序里,利用上多CPU或者多核,甚至是多个服务器的CPU一起来承担负载。 这种划分多个进程的架构,一般会有两种策略:一种是按功能来划分,比如负责网络处理的一个进程,负责数据库处理的一个进程,负责计算某个业务逻辑的一个进程。另外一种策略是每个进程都是同样的功能,只是分担不同的运算任务而已。使用第一种策略的系统,运行的时候,直接根据操作系统提供的诊断工具,就能直观的监测到每个功能模块的性能消耗,因为操作系统提供进程盒子的同时,也能提供对进程的全方位的监测,比如CPU占用、内存消耗、磁盘和网络I/O等等。但是这种策略的运维部署会稍微复杂一点,因为任何一个进程没有启动,或者和其他进程的通信地址没配置好,都可能导致整个系统无法运作;而第二种分布策略,由于每个进程都是一样的,这样的安装部署就非常简单,性能不够就多找几个机器,多启动几个进程就完成了,这就是所谓的平行扩展。 现在比较复杂的分布式系统,会结合这两种策略,也就是说系统既按一些功能划分出不同的具体功能进程,而这些进程又是可以平行扩展的。当然这样的系统在开发和运维上的复杂度,都是比单独使用“按功能划分”和“平行划分”要更高的。由于要管理大量的进程,传统的依靠配置文件来配置整个集群的做法,会显得越来越不实用:这些运行中的进程,可能和其他很多进程产生通信关系,当其中一个进程变更通信地址时,势必影响所有其他进程的配置。所以我们需要集中的管理所有进程的通信地址,当有变化的时候,只需要修改一个地方。在大量进程构建的集群中,我们还会碰到容灾和扩容的问题:当集群中某个服务器出现故障,可能会有一些进程消失;而当我们需要增加集群的承载能力时,我们又需要增加新的服务器以及进程。这些工作在长期运行的服务器系统中,会是比较常见的任务,如果整个分布系统有一个运行中的中心进程,能自动化的监测所有的进程状态,一旦有进程加入或者退出集群,都能即时的修改所有其他进程的配置,这就形成了一套动态的多进程管理系统。开源的ZooKeeper给我们提供了一个可以充当这种动态集群中心的实现方案。由于ZooKeeper本身是可以平行扩展的,所以它自己也是具备一定容灾能力的。现在越来越多的分布式系统都开始使用以ZooKeeper为集群中心的动态进程管理策略了。 在调用多进程服务的策略上,我们也会有一定的策略选择,其中最著名的策略有三个:一个是动态负载均衡策略;一个是读写分离策略;一个是一致性哈希策略。动态负载均衡策略,一般会搜集多个进程的服务状态,然后挑选一个负载最轻的进程来分发服务,这种策略对于比较同质化的进程是比较合适的。读写分离策略则是关注对持久化数据的性能,比如对数据库的操作,我们会提供一批进程专门用于提供读数据的服务,而另外一个(或多个)进程用于写数据的服务,这些写数据的进程都会每次写多份拷贝到“读服务进程”的数据区(可能就是单独的数据库),这样在对外提供服务的时候,就可以提供更多的硬件资源。一致性哈希策略是针对任何一个任务,看看这个任务所涉及读写的数据,是属于哪一片的,是否有某种可以缓存的特征,然后按这个数据的ID或者特征值,进行“一致性哈希”的计算,分担给对应的处理进程。这种进程调用策略,能非常的利用上进程内的缓存(如果存在),比如我们的一个在线游戏,由100个进程承担服务,那么我们就可以把游戏玩家的ID,作为一致性哈希的数据ID,作为进程调用的KEY,如果目标服务进程有缓存游戏玩家的数据,那么所有这个玩家的操作请求,都会被转到这个目标服务进程上,缓存的命中率大大提高。而使用“一致性哈希”,而不是其他哈希算法,或者取模算法,主要是考虑到,如果服务进程有一部分因故障消失,剩下的服务进程的缓存依然可以有效,而不会整个集群所有进程的缓存都失效。具体有兴趣的读者可以搜索“一致性哈希”一探究竟。 以多进程利用大量的服务器,以及服务器上的多个CPU核心,是一个非常有效的手段。但是使用多进程带来的额外的编程复杂度的问题。一般来说我们认为最好是每个CPU核心一个进程,这样能最好的利用硬件。如果同时运行的进程过多,操作系统会消耗很多CPU时间在不同进程的切换过程上。但是,我们早期所获得的很多API都是阻塞的,比如文件I/O,网络读写,数据库操作等。如果我们只用有限的进程来执行带这些阻塞操作的程序,那么CPU会大量被浪费,因为阻塞的API会让有限的这些进程停着等待结果。那么,如果我们希望能处理更多的任务,就必须要启动更多的进程,以便充分利用那些阻塞的时间,但是由于进程是操作系统提供的“盒子”,这个盒子比较大,切换耗费的时间也比较多,所以大量并行的进程反而会无谓的消耗服务器资源。加上进程之间的内存一般是隔离的,进程间如果要交换一些数据,往往需要使用一些操作系统提供的工具,比如网络socket,这些都会额外消耗服务器性能。因此,我们需要一种切换代价更少,通信方式更便捷,编程方法更简单的并行技术,这个时候,多线程技术出现了。 多线程的特点是切换代价少,可以同时访问内存。我们可以在编程的时候,任意让某个函数放入新的线程去执行,这个函数的参数可以是任何的变量或指针。如果我们希望和这些运行时的线程通信,只要读、写这些指针指向的变量即可。在需要大量阻塞操作的时候,我们可以启动大量的线程,这样就能较好的利用CPU的空闲时间;线程的切换代价比进程低得多,所以我们能利用的CPU也会多很多。线程是一个比进程更小的“程序盒子”,他可以放入某一个函数调用,而不是一个完整的程序。一般来说,如果多个线程只是在一个进程里面运行,那其实是没有利用到多核CPU的并行好处的,仅仅是利用了单个空闲的CPU核心。但是,在JAVA和C#这类带虚拟机的语言中,多线程的实现底层,会根据具体的操作系统的任务调度单位(比如进程),尽量让线程也成为操作系统可以调度的单位,从而利用上多个CPU核心。比如Linux2.6之后,提供了NPTL的内核线程模型,JVM就提供了JAVA线程到NPTL内核线程的映射,从而利用上多核CPU。而Windows系统中,据说本身线程就是系统的最小调度单位,所以多线程也是利用上多核CPU的。所以我们在使用JAVAC#编程的时候,多线程往往已经同时具备了多进程利用多核CPU、以及切换开销低的两个好处。 早期的一些网络聊天室服务,结合了多线程和多进程使用的例子。一开始程序会启动多个广播聊天的进程,每个进程都代表一个房间;每个用户连接到聊天室,就为他启动一个线程,这个线程会阻塞的读取用户的输入流。这种模型在使用阻塞API的环境下,非常简单,但也非常有效。 当我们在广泛使用多线程的时候,我们发现,尽管多线程有很多优点,但是依然会有明显的两个缺点:一个内存占用比较大且不太可控;第二个是多个线程对于用一个数据使用时,需要考虑复杂的“锁”问题。由于多线程是基于对一个函数调用的并行运行,这个函数里面可能会调用很多个子函数,每调用一层子函数,就会要在栈上占用新的内存,大量线程同时在运行的时候,就会同时存在大量的栈,这些栈加在一起,可能会形成很大的内存占用。并且,我们编写服务器端程序,往往希望资源占用尽量可控,而不是动态变化太大,因为你不知道什么时候会因为内存用完而当机,在多线程的程序中,由于程序运行的内容导致栈的伸缩幅度可能很大,有可能超出我们预期的内存占用,导致服务的故障。而对于内存的“锁”问题,一直是多线程中复杂的课题,很多多线程工具库,都推出了大量的“无锁”容器,或者“线程安全”的容器,并且还大量设计了很多协调线程运作的类库。但是这些复杂的工具,无疑都是证明了多线程对于内存使用上的问题。 由于多线程还是有一定的缺点,所以很多程序员想到了一个釜底抽薪的方法:使用多线程往往是因为阻塞式API的存在,比如一个read()操作会一直停止当前线程,那么我们能不能让这些操作变成不阻塞呢?——selector/epoll就是Linux退出的非阻塞式API。如果我们使用了非阻塞的操作函数,那么我们也无需用多线程来并发的等待阻塞结果。我们只需要用一个线程,循环的检查操作的状态,如果有结果就处理,无结果就继续循环。这种程序的结果往往会有一个大的死循环,称为主循环。在主循环体内,程序员可以安排每个操作事件、每个逻辑状态的处理逻辑。这样CPU既无需在多线程间切换,也无需处理复杂的并行数据锁的问题——因为只有一个线程在运行。这种就是被称为“并发”的方案。 实际上计算机底层早就有使用并发的策略,我们知道计算机对于外部设备(比如磁盘、网卡、显卡、声卡、键盘、鼠标),都使用了一种叫“中断”的技术,早期的电脑使用者可能还被要求配置IRQ号。这个中断技术的特点,就是CPU不会阻塞的一直停在等待外部设备数据的状态,而是外部数据准备好后,给CPU发一个“中断信号”,让CPU转去处理这些数据。非阻塞的编程实际上也是类似这种行为,CPU不会一直阻塞的等待某些I/O的API调用,而是先处理其他逻辑,然后每次主循环去主动检查一下这些I/O操作的状态。 多线程和异步的例子,最著名就是Web服务器领域的Apache和Nginx的模型。Apache是多进程/多线程模型的,它会在启动的时候启动一批进程,作为进程池,当用户请求到来的时候,从进程池中分配处理进程给具体的用户请求,这样可以节省多进程/线程的创建和销毁开销,但是如果同时有大量的请求过来,还是需要消耗比较高的进程/线程切换。而Nginx则是采用epoll技术,这种非阻塞的做法,可以让一个进程同时处理大量的并发请求,而无需反复切换。对于大量的用户访问场景下,apache会存在大量的进程,而nginx则可以仅用有限的进程(比如按CPU核心数来启动),这样就会比apache节省了不少“进程切换”的消耗,所以其并发性能会更好。 在现代服务器端软件中,nginx这种模型的运维管理会更简单,性能消耗也会稍微更小一点,所以成为最流行的进程架构。但是这种好处,会付出一些另外的代价:非阻塞代码在编程的复杂度变大。 分布式编程复杂度以前我们的代码,从上往下执行,每一行都会占用一定的CPU时间,这些代码的直接顺序,也是和编写的顺序基本一致,任何一行代码,都是唯一时刻的执行任务。当我们在编写分布式程序的时候,我们的代码将不再好像那些单进程、单线程的程序一样简单。我们要把同时运行的不同代码,在同一段代码中编写。就好像我们要把整个交响乐团的每个乐器的乐谱,全部写到一张纸上。为了解决这种编程的复杂度,业界发展出了多种编码形式。 在多进程的编码模型上,fork()函数可以说一个非常典型的代表。在一段代码中,fork()调用之后的部分,可能会被新的进程中执行。要区分当前代码的所在进程,要靠fork()的返回值变量。这种做法,等于把多个进程的代码都合并到一块,然后通过某些变量作为标志来划分。这样的写法,对于不同进程代码大部份相同的“同质进程”来说,还是比较方便的,最怕就是有大量的不同逻辑要用不同的进程来处理,这种情况下,我们就只能自己通过规范fork()附近的代码,来控制混乱的局面。比较典型的是把fork()附近的代码弄成一个类似分发器(dispatcher)的形式,把不同功能的代码放到不同的函数中,以fork之前的标记变量来决定如何调用。 ...

June 12, 2019 · 1 min · jiezi

优酷背后的大数据秘密

在本文中优酷数据中台的数据技术专家门德亮分享了优酷从Hadoop迁移到阿里云MaxCompute后对业务及平台的价值。 本文内容根据演讲视频以及PPT整理而成。 大家好,我是门德亮,现在在优酷数据中台做数据相关的事情。很荣幸,我正好见证了优酷从没有MaxCompute到有的这样一个历程,因为刚刚好我就是入职优酷差不多5年的时间,我们正好是在快到5年的时候,去做了从Hadoop到MaxCompute的这样一个升级。这个是2016年5月到2019年现在的5月优酷的发展历程,上面是计算资源,下面是储存资源。大家可以看到整个用户数,还有表的数据,实际上是在呈一个指数式增长的。但是在2017年5月,当优酷完成了整个Hadoop迁移MaxCompute后,优酷的计算消耗,还有储存的消耗实际上是呈下降趋势的,整个迁移得到了一个非常大的收益。 下面说一下优酷的业务特点。 第一个特点从大数据平台整个的用户复杂度上面,不止是数据的同学和技术的同学在使用,还会包括一些BI同学,测试同学,甚至产品运营都可能去使用这个大数据的平台。 第二个特点就是业务复杂,优酷是一个视频网站,它有非常复杂的业务场景,从日志分类上,除了像页面浏览,还会有一些播放相关的数据、性能相关的数据。从整个的业务模式上,有直播、有会员、有广告、有大屏等这样一些非常不一样的场景。 第三个特点,就是数据量是非常巨大的,一天的日志量会达到千亿级别,这是一个非常旁大的数据量,而且会做非常复杂的计算。 第四个是比较有意思的,不管是小公司、大公司,对成本的意识是非常高的。优酷也是有非常严格的预算,包括在阿里集团内是有非常严格的预算系统的,但是我们也经常会去做一些重要的战役,像双十一战役,像我们暑期的世界杯战役,还有春节也会搞各种战役。这样的话,其实对计算资源的弹性要求是非常高的。 基于上面的优酷的业务特点,我整理了MaxCompute可以完美的支持我们业务的几个特点。 第一个,简单易用。第二个,完善的生态。第三个,性能非常强悍。第四个,资源使用非常弹性。 第一个特点,简单易用。MaxCompute有一个非常完整的链路,不管是从数据开发,还是数据运维,包括数据集成,数据质量的管控,还有整个数据地图,数据安全。当年优酷从Hadoop迁到MaxCompute之后,我们最大的体会是自己不用半夜经常起来去维护集群了,不用去跑任务了,写一个任务,别人之前提一个需求过来,我可能要给他排几周,而现在我可以告诉他,我给你马上跑一下,就可以出来了。包括之前像分析师BI还要登录客户端,写脚本,自己写调度,经常会说我的数今天为什么没出来?包括高层看的数,可能要到12点钟才能出来。而现在基本上所有重要的数据都会在7点钟产出,包括一些基本的业务需求,其实分析师或者产品,他们自己都可以实现了,不需要所有需求都提到数据这边。 第二个特点,完整的生态。优酷在2017年之前是完全基于Hadoop的生态,迁到MaxCompute之后,是基于阿里云提供的Serverless大数据服务的生态。大家可以在开源上看到的组件,在整个的MaxCompute上都是有的,而且比开源的要更好用、更简单。从架构图上可以看到,我们中间是MaxCompute,左侧依赖的Mysql、Hbase、ES、Redis这些都是由同步中心去做一个双向的同步。右侧会有资源管理、资源监控、数据监控,包括数据资产,还有一些数据规范。我们下层的数据输入,包括一些集团的采集工具,再往上边,有提供给开发人员用的DataWorks,包括一些命令行的工具;有提供给BI人员用的QuickBI及数据服务。 第三个特点,强悍的性能,MaxCompute支撑了优酷EB级的数据存储,千亿级的数据样本分析,包括千亿级的数据报表,10W级实例的并发、任务。这些在之前维护Hadoop的时候,是想都不敢想的。 第四个特点,资源使用的弹性。我们在2016年迁移之前,其实优酷的Hadoop集群规模已经达到了一千多台,这个当时还是一个比较大的规模。当时我们遇到了很多问题,包括像NameNode 这种内存的问题,机房没有办法再扩容的问题,当时是非常痛苦的,包括一些运维管理上面的问题。我们不断的去问运维要资源,运维告诉说,说你们已经花了多少多少资源,花了多少多少钱。我们面临的问题是计算资源如何按需使用,夜里的时候作业很多,到了下午之后,我的整个集群都空下来了,没有人用,造成了浪费。其实MaxCompute完美的解决了这个问题。 第一个,它是按用量计费的,不是说给你多少台机器,然后就收你多少钱的,真的是你用了多少资源收多少钱的,这个在成本上来说,比自己去维护集群,可能是一个砍半(降50%)这样的收益。 第二个,实际上MaxCompue计算资源是可以分时的,比如说生产队列,凌晨的时候会调高一些,保证报表能够尽快出来。到白天时候,让开发的计算资源高一些,可以让分析师、开发去临时跑一些数据,会更顺畅一些。 第三个,MaxCompute快速的扩容能力,比如说突然有一个比较强的业务需求,发现数据跑不动了,计算资源不够,所有的队列都堵死了,这个时候其实可以直接跟运维说一声,帮忙一键扩容,他两秒钟敲一个命令就搞定了。这样的话,所有的资源可以迅速的消化下去。 上面是优酷为什么采用MaxCompute,下面是在优酷的业务场景下,我们一些典型的方案、应用。这张图实际上是优酷,包括可能现在阿里集团内部一些非常典型的技术架构图。中间可以看到,MaxCompute在中间核心的位置,左侧主要是一个输入,右侧是一个输出的趋向,绿色的线是一个实时的链路,包括现在我们从整个的数据源上,比如DB也好或者服务器的本地日志Log也好,我们通过TT&Datahub存储到MaxCompute上面做分析。当然现在非常火的Flink实时计算,其实是作为一个实时处理的链路。 包括DB的同步,除了实时的链路,DB也会去通过按天/按小时,把数据同步到MaxCompute,数据计算结果也可以同步到Hbase、Mysql这种DB上面。再通过统一的服务层对应用提供服务。下面这个是机器学习Pai做的一些算法训练,再把训练的结果通过OSS传到一个算法的应用上面去。 这张图可能也是业界比较流行的一个数仓分层的图,因为我们这边是数据中台,所有的数据都是统一从ods层cdm层,然后ads层,去一层一层的往上去做精细,再到最上面,通过接口服务、文件服务、SQL服务,去提供多样化的服务。再往上面,提供对内的一些数据产品,对高管、对小二,可能还有一些对外的,比如说像优酷的播放数,包括热度这些对应用的数据。 这张图其实就是我们从Hadoop迁到MaxCompute平台上以来,两个非常经典的案例。我们通过数据中台对不同场景的用户打通,来去赋能到两个不同的场景,提升业务价值。 第二个,可能是内部的,我们通过优酷,还有集团内部的一些BU去做换量,我们通过统一的标签去做样本放大,把优酷的量导给其它的BU,把其它BU的量导给优酷,这样去达到一个共赢的效果。 这张图大部分互联网公司不太会涉及到,就是关于反作弊的问题。这个是我们在MaxCompute做的一个反作弊的架构,通过原始的数据去提取它的特征,然后再通过算法模型,包括机器学习、深度学习、图模型去支持流量反作弊、渠道反作弊等等。再通过业务场景上反作弊的监控工具,把监控到的作弊信息去打一个黑白样本,再把这个黑白样本跟特征一起来不断的迭代优化算法模型。同时针对算法模型,做一个模型的评价,不断来完善反作弊体系。 最后一点,其实还是跟成本相关,在日常使用中,一定是有小白用户或者一些新来的用户去错误的使用或者不在乎的使用一些资源,比如经常会有一些实习生或者是非技术的同学,如分析师,一个SQL消费比较高,这个其实是非常浪费资源,而且可能他一个任务,让其他所有人的任务都在这儿等着排队,实际上我们会去对整个的资源做一个治理。 从节点的粒度上,通过大数据来治理大数据,我们可以算出哪些表产出来之后,多少天没有被读取的,包括它的访问跨度可能没有那么大的,我们会去做下线或者去做治理,有一些业务场景可能并不是非常的重要或者它的时间要求没有那么高,比如一些算法训练,可以去做一些错峰的调度,保证水位不要太高。从MaxCompute任务的角度,可以算出哪些任务有数据倾斜、哪些数据可能会有相似计算,哪些任务需要去做MapJoin,哪些任务需要去做一些裁剪,然后来节省它的IO。还有哪些任务会去做暴力扫描,扫一个月、扫一年的数据,哪些数据可能会有这样一个数据膨胀,比如说它做了CUBE之类的这种复杂计算,一些算法模型的迭代;我们通过数据计算出来的这些迹象,去反推用户,来去提高它的这样一个数据的质量分,来去达到我们降低整个计算资源的目的。 在计算平台的角度,我们也持续的在使用MaxCompute推出的一些非常高级的用法,比如我们这边的HBO、Hash Cluster、Aliorc,HBO就是我们基于一个历史的优化,这样避免了用户不知道怎么调参,我可能为了自己任务快一点,就调一个特别大的参数,这样的话,对集成的资源是非常浪费的。通过这个功能,用户就不用去调参数,集群自动调好,用户就写好自己业务逻辑就好了。 第二块,可能就是最近两年推出的Hash Cluster,当时在使用Hadoop的时候经常会出现,两个大表Join的时候计算不出来,这个Hash Cluster其实是一个优化的利器。大表跟小表Join,可以做一些分发,做一些优化。大表跟大表就涉及到一个排序的问题。这个Hash Cluster,实际上就是提前把数据排好,中间省掉很多计算环节,来达到效率提升的目的。 第三个,Aliorc,在一些固定的场景上面,可以稳定的提升20%的计算效率。 第四个,Session。对一些比较小的数据,直接就放到SSD或缓存里面,一个节点下游有100个叶子场景,是非常友好的,因为低延迟秒出结果。同时,优酷也在使用Lightning解决计算加速,这个是在一个计算架构方案上的优化,它是一个MPP的架构。 最后一页是存储的优化,因为像一些关键的原始数据或者是需要审计的数据是不能删的,永久不能删的。实际上就会造成我们数据存储的趋势是一直往上不减的,计算会在某一个时间点达到一个平衡。当前用这么多的计算资源,再往后,其实应该也不会再大涨了,比如说旧的业务逻辑下掉了,会换新的业务逻辑,这样会保持在一个相对平稳的波动上面。但是储存,因为它有一些历史的数据是永远不能删的,可能会出现一直在增长,而且是指数级的。所以我们也会持续关注存储的情况,我们主要有四个手段。 第一个,还是通过大数据来治大数据,去看哪些表它的访问不够或者它的访问跨度不够。就是对一些生命周期的优化,来去控制它的增速。包括下面的,刚才提到的Aliorc,实际上是做压缩的,我们会去做一些大字段的拆分,来提高压缩的比例。 OK,这个是优酷在MaxCompute中的一些应用场景,感谢大家的聆听。 本文作者:隐林阅读原文 本文为云栖社区原创内容,未经允许不得转载。

June 12, 2019 · 1 min · jiezi

Istio-on-ACK集成生态1-集成TSDB助力可观测性存储

阿里云容器服务Kubernetes(简称ACK)支持一键部署Istio,可以参考文档在ACK上部署使用Isito。Istio on ACK提供了丰富的监控能力,为网格中的服务收集遥测数据,其中Mixer是负责提供策略控制和遥测收集的Istio组件。使用Prometheus进行监控是Istio提供的监控能力之一。Prometheus是一个开源的监控和报警系统,Prometheus依赖少,功能齐全,广泛用于Kubernetes集群的监控系统中。Istio自0.8版本开始默认将Prometheus包含在内,Mixer支持对接到Prometheus监控设施的Adapter。用户可以通过查询service或pod看到Prometheus的运行状态和地址。也可以通过简洁明了的Prometheus的UI界面查看监测数据。 Prometheus的存储挑战及解决方案Prometheus的本地存储设计可以减少其自身运维和管理的复杂度,能够满足大部分用户监控规模的需求,但是本地存储也意味着Prometheus无法持久化数据,无法存储大量历史数据,同时也无法灵活扩展。Prometheus本身没有尝试解决以上问题,而是通过定义一组remote storage adapter标准接口,让用户可以基于这组标准接口自主决定将Promthues中的监控样本数据存储至第三方的远端存储服务中,来解决本地存储带来的问题。 TSDB for Prometheus是一种高性能,低成本,稳定可靠的在线时序数据库服务,通过内置实现的Prometheus的remote storage adapter,天然原生支持作为Promtheus的第三方在线远端存储服务。 相较于其他第三方远端存储而言,TSDB for Prometheus具有集成程度高,同时支持读写等优势。 集成程度高目前Prometheus对接第三方存储系统的主流做法是实现一个独立于第三方存储系统的remote storage adapter, 这个adapter需要单独部署和运维,另外单独部署的remote storage adapter还存在单点故障和读写性能问题。TSDB for Prometheus在服务端内置实现的Prometheus remote storage adapter,只需在Prometheus的配置文件prometheus.yaml中修改下远程读写配置,即可原生支持Prometheus直接读写TSDB,集成程度高,无需额外单独部署adapter,极大地降低了adapter的单点故障风险和运维成本。 同时支持读写当前一些第三方远端存储仅支持Prometheus将监控样本数据写入,而不支持读取。比如对于OpenTSDB、Graphite和Elasticsearch等第三方存储,Prometheus社区提供的adapter只支持写入模式,不支持读取模式。而TSDB for Prometheus同时支持读写。如要了解更多第三方存储系统对于Prometheus读写的支持程度,请参考Remote Endpoints and Storage。TSDB for Prometheus时序时空数据库(Time Series & Spatial Temporal Database,简称 TSDB)是一种高性能、低成本、稳定可靠的在线时序时空数据库服务,提供高效读写、高压缩比存储、时序数据插值及聚合计算等服务。TSDB 具备秒级写入百万级时序数据的性能,提供高压缩比低成本存储、预降采样、插值、多维聚合计算、可视化查询结果等功能。 TSDB for Prometheus是阿里云时序时空数据库TSDB为Prometheus提供的一种高性能、低成本、稳定可靠的在线远端存储服务,具备以下能力: 提供高效读写、高压缩比存储的能力,可无缝被Prometheus集成,在协议上原生支持Prometheus远端存储对接至TSDB。解决了以往需要为Prometheus额外开发remote storage adapter的问题,极大的降低了Prometheus远端存储对接TSDB的成本。TSDB for Prometheus最大程度的兼容Prometheus的PromQL查询语法,从而降低了用户的开发,迁移和维护成本。解决Prometheus local stroge 无法存储大量历史数据的场景,且无法扩展的问题。通过内置实现的Prometheus的remote storage adapter,天然原生支持作为Promtheus的第三方在线远端存储服务。相较于其他第三方远端存储而言,TSDB for Prometheus具有集成程度高,同时支持读写等优势。TSDB for Prometheus的使用要求具体可以参见使用要求 阿里云提供的不同规格的TSDB实例,设置了不同的最大写入TPS,避免过大TPS导致TSDB示例不可用,保护TSDB实例正常运行。当写入TPS超过TSDB实例允许的最大TPS时,将触发TSDB实例限流保护规则,会造成写入失败异常。因此需要根据TSDB实例规格来调整Prometheus的remote_write配置,从而实现平稳可靠的将Prometheus采集到的指标写入TSDB中。 关于Remote Write配置,除了参考Prometheus官方提供的Remote Write配置说明之外,还可以参考Prometheus对接阿里云TSDB时的写入配置最佳实践。 创建TSDB实例创建一个TSDB实例非常简单,登录TSDB 控制台,参照创建实例文档即可创建。获取开通的TSDB实例的地址,可以参考TSDB官方文档快速入门 确认Prometheus所在机器能够正常访问TSDB实例。直接使用http访问TSDB实例的地址,如果能够得到包含”Welcome to use the TSDB”的字符串,表示Prometheus所在机器能够正常访问TSDB实例。 ...

June 11, 2019 · 1 min · jiezi

使用阿里云极速型NAS构建高可用的GitLab

GitLab简介GitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。Ruby on Rails 是一个可以使你开发、部署、维护 web 应用程序变得简单的框架。GitLab拥有与Github类似的功能,能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。由于Git的分布式特性,即使Gitlab不可用,开发人员仍然可以在本地提交代码。但是,某些Gitlab功能,比如CI,问题跟踪和持续集成会不可用,也会严重影响线上使用。因此高可用架构还是不可缺少的。GitLab软件架构如下图所示: GitLab高可用设计主备模式:启动2个实例,只有一个工作提供服务,数据通过分布式存储保持一致 主主模式(scales):Rails server启动多个,同时提供服务,数据库保持独立,数据通过NAS文件存储共享 GitLab高可用方案水平扩展 这种架构适用于许多Gitlab客户访问的使用场景,解决高API使用率,大量排队的Sidekiq作业的问题。 3 PostgreSQL nodes2 Redis nodes3 Consul/Sentinel nodes2 or more GitLab application nodes (Unicorn, Workhorse, Sidekiq, PGBouncer)1 NFS/Gitaly server 混合扩展 这种架构通过组件在专用节点上分离,提供高资源使各组件不会相互干扰,解决服务争用/高负载的问题。 3 PostgreSQL nodes1 PgBouncer node2 Redis nodes3 Consul/Sentinel nodes2 or more Sidekiq nodes2 or more GitLab application nodes (Unicorn, Workhorse)1 or more NFS/Gitaly servers1 Monitoring node (Prometheus, Grafana) ...

June 11, 2019 · 1 min · jiezi

数据仓库介绍与实时数仓案例

1.数据仓库简介数据仓库是一个面向主题的(Subject Oriented)、集成的(Integrate)、相对稳定的(Non-Volatile)、反映历史变化(Time Variant)的数据集合,用于支持管理决策。 数据仓库是伴随着企业信息化发展起来的,在企业信息化的过程中,随着信息化工具的升级和新工具的应用,数据量变的越来越大,数据格式越来越多,决策要求越来越苛刻,数据仓库技术也在不停的发展。 数据仓库的趋势: 实时数据仓库以满足实时化&自动化决策需求;大数据&数据湖以支持大量&复杂数据类型(文本、图像、视频、音频); 2.数据仓库的发展数据仓库有两个环节:数据仓库的构建与数据仓库的应用。 早期数据仓库构建主要指的是把企业的业务数据库如ERP、CRM、SCM等数据按照决策分析的要求建模并汇总到数据仓库引擎中,其应用以报表为主,目的是支持管理层和业务人员决策(中长期策略型决策)。 随着业务和环境的发展,这两方面都在发生着剧烈变化。 随着IT技术走向互联网、移动化,数据源变得越来越丰富,在原来业务数据库的基础上出现了非结构化数据,比如网站log,IoT设备数据,APP埋点数据等,这些数据量比以往结构化的数据大了几个量级,对ETL过程、存储都提出了更高的要求;互联网的在线特性也将业务需求推向了实时化,随时根据当前客户行为而调整策略变得越来越常见,比如大促过程中库存管理,运营管理等(即既有中远期策略型,也有短期操作型);同时公司业务互联网化之后导致同时服务的客户剧增,有些情况人工难以完全处理,这就需要机器自动决策。比如欺诈检测和用户审核。 总结来看,对数据仓库的需求可以抽象成两方面:实时产生结果、处理和保存大量异构数据。 注:这里不讨论数据湖技术。3.数据仓库建设方法论1)面向主题 从公司业务出发,是分析的宏观领域,比如供应商主题、商品主题、客户主题和仓库主题 2)为多维数据分析服务 数据报表;数据立方体,上卷、下钻、切片、旋转等分析功能。 3)反范式数据模型 以事实表和维度表组成的星型数据模型 4.数据仓库架构的演变数据仓库概念是Inmon于1990年提出并给出了完整的建设方法。随着互联网时代来临,数据量暴增,开始使用大数据工具来替代经典数仓中的传统工具。此时仅仅是工具的取代,架构上并没有根本的区别,可以把这个架构叫做离线大数据架构。 后来随着业务实时性要求的不断提高,人们开始在离线大数据架构基础上加了一个加速层,使用流处理技术直接完成那些实时性要求较高的指标计算,这便是Lambda架构。 再后来,实时的业务越来越多,事件化的数据源也越来越多,实时处理从次要部分变成了主要部分,架构也做了相应调整,出现了以实时事件处理为核心的Kappa架构。 4.1离线大数据架构 数据源通过离线的方式导入到离线数仓中。 下游应用根据业务需求选择直接读取DM或加一层数据服务,比如mysql 或 redis。 数据仓库从模型层面分为三层: ODS,操作数据层,保存原始数据;DWD,数据仓库明细层,根据主题定义好事实与维度表,保存最细粒度的事实数据;DM,数据集市/轻度汇总层,在DWD层的基础之上根据不同的业务需求做轻度汇总;典型的数仓存储是HDFS/Hive,ETL可以是MapReduce脚本或HiveSQL。 4.2 Lambda架构 随着大数据应用的发展,人们逐渐对系统的实时性提出了要求,为了计算一些实时指标,就在原来离线数仓的基础上增加了一个实时计算的链路,并对数据源做流式改造(即把数据发送到消息队列),实时计算去订阅消息队列,直接完成指标增量的计算,推送到下游的数据服务中去,由数据服务层完成离线&实时结果的合并。 注:流处理计算的指标批处理依然计算,最终以批处理为准,即每次批处理计算后会覆盖流处理的结果。(这仅仅是流处理引擎不完善做的折中)Lambda架构问题: 1.同样的需求需要开发两套一样的代码这是Lambda架构最大的问题,两套代码不仅仅意味着开发困难(同样的需求,一个在批处理引擎上实现,一个在流处理引擎上实现,还要分别构造数据测试保证两者结果一致),后期维护更加困难,比如需求变更后需要分别更改两套代码,独立测试结果,且两个作业需要同步上线。2.资源占用增多:同样的逻辑计算两次,整体资源占用会增多(多出实时计算这部分) 4.3 Kappa架构 Lambda架构虽然满足了实时的需求,但带来了更多的开发与运维工作,其架构背景是流处理引擎还不完善,流处理的结果只作为临时的、近似的值提供参考。后来随着Flink等流处理引擎的出现,流处理技术很成熟了,这时为了解决两套代码的问题,LickedIn 的Jay Kreps提出了Kappa架构 Kappa架构可以认为是Lambda架构的简化版(只要移除lambda架构中的批处理部分即可)。 在Kappa架构中,需求修改或历史数据重新处理都通过上游重放完成。 Kappa架构最大的问题是流式重新处理历史的吞吐能力会低于批处理,但这个可以通过增加计算资源来弥补。 Kappa架构的重新处理过程 重新处理是人们对Kappa架构最担心的点,但实际上并不复杂: 1.选择一个具有重放功能的、能够保存历史数据并支持多消费者的消息队列,根据需求设置历史数据保存的时长,比如Kafka,可以保存全部历史数据。2.当某个或某些指标有重新处理的需求时,按照新逻辑写一个新作业,然后从上游消息队列的最开始重新消费,把结果写到一个新的下游表中。3.当新作业赶上进度后,应用切换数据源,读取2中产生的新结果表。4.停止老的作业,删除老的结果表。 4.4 Lambda架构与Kappa架构的对比对比项Lambda架构Kappa架构实时性实时实时计算资源批和流同时运行,资源开销大只有流处理,仅针对新需求开发阶段运行两个作业,资源开销小重新计算时吞吐批式全量处理,吞吐较高流式全量处理,吞吐较批处理低开发、测试每个需求都需要两套不同代码,开发、测试、上线难度较大只需实现一套代码,开发、测试、上线难度相对较小运维成本维护两套系统(引擎),运维成本大只需维护一套系统(引擎),运维成本小在真实的场景中,很多时候并不是完全规范的Lambda架构或Kappa架构,可以是两者的混合,比如大部分实时指标使用Kappa架构完成计算,少量关键指标(比如金额相关)使用Lambda架构用批处理重新计算,增加一次校对过程。(1) Kappa架构并不是中间结果完全不落地,现在很多大数据系统都需要支持机器学习(离线训练),所以实时中间结果需要落地对应的存储引擎供机器学习使用,另外有时候还需要对明细数据查询,这种场景也需要把实时明细层写出到对应的引擎中。(2)参考后面的案例 另外,随着数据多样性的发展,数据仓库这种提前规定schema的模式显得越来难以支持灵活的探索&分析需求,这时候便出现了一种数据湖技术,即把原始数据全部缓存到某个大数据存储上,后续分析时再根据需求去解析原始数据。简单的说,数据仓库模式是schema on write,数据湖模式是schema on read。(3) 5.实时数仓案例菜鸟仓配实时数据仓库 本案例参考自菜鸟仓配团队的分享,涉及全局设计、数据模型、数据保障等几个方面。 注:特别感谢缘桥同学的无私分享。 5.1 整体设计 整体设计如右图,基于业务系统的数据,数据模型采用中间层的设计理念,建设仓配实时数仓;计算引擎,选择更易用、性能表现更佳的实时计算作为主要的计算引擎;数据服务,选择天工数据服务中间件,避免直连数据库,且基于天工可以做到主备链路灵活配置秒级切换;数据应用,围绕大促全链路,从活动计划、活动备货、活动直播、活动售后、活动复盘五个维度,建设仓配大促数据体系。 5.2 数据模型 不管是从计算成本,还是从易用性,还是从复用性,还是从一致性……,我们都必须避免烟囱式的开发模式,而是以中间层的方式建设仓配实时数仓。与离线中间层基本一致,我们将实时中间层分为两层。 ...

June 11, 2019 · 1 min · jiezi

拔掉数据库的电源会怎样阿里云数据库新型灾备架构让云端容灾有备无患

拔掉数据库的电源会怎样?假设我们拔掉数据库的电源会怎样? 在日前举行的阿里云“企业级”云灾备解决方案发布会上,阿里云智能技术战略总监陈绪就来了一场现场“断电”演示,拔掉了数据库的电源。 (直播回放:https://yq.aliyun.com/live/1104/event) 猜猜现场发生了什么? 数据丢失,业务瘫痪,企业资金受损? 上述情况统统没有出现!没有出现任何数据丢失,也没有业务瘫痪,10秒后,上云企业的业务就完全恢复了。 那么这是如何实现的呢? 在会上,阿里云智能数据库产品事业部技术总监天羽为大家全面解析《云时代,数据库新型灾备架构》,详细介绍了在混合云架构下,从异地备份、容灾、双活到统一管理的数据库一站式灾备解决方案。 有了云数据库新型灾备架构,即使断电又何妨?通过阿里云提供的DBS、DTS、HDM等服务,您的企业也可轻松构建灾备体系,做到“有备无患”。 墨菲定律 鸡蛋不能放在一个篮子里对于每个企业而言,数据库都是其最为核心的资产。但是单点故障是不可避免的,因此为了提升数据安全,需要做的就是数据冗余。 国家对于数据库灾难恢复能力也定义了相应的标准。对于位于等级2~3的一般业务而言,需要每天进行备份;对于位于等级4的重要业务而言,需要每天全量+增量备份;对于等级5的关键业务而言,要求数据丢失不能超过半个小时,并且要求在分钟级别恢复业务;对于位于等级6的核心业务而言,则需要做到数据零丢失。 阿里巴巴数据库从备份到多活的发展经过了以下历程: 2012年之前,阿里巴巴采用的是异地冷备+热备方案,提供只读副本,当时异地冷备和热备可能出现异地延时比较长的问题,导致出现灾难之后敢不敢进行数据库切换成为一个问题,可能现在很多传统企业还在使用该方案。 2013年,阿里巴巴通过数据库实时日志的解析能力实现了同城双活。 2014年,阿里巴巴实现了异地双活。 2015年,阿里巴巴就实现了中美同步以及多个地域、多点写入的数据同步策略。 2016年,阿里巴巴实现了分布式数据强一致的能力以及异地多活能力。 在不断提升阿里巴巴灾备能力的过程中,我们也在阿里云上孵化了数据库备份(DBS)、数据传输(DTS)、混合云数据库管理(HDM),搭建从备份、容灾、双活及混合云统一管理的一站式云灾备解决方案。 对于等级1到等级4的业务而言,可以通过DBS将数据实时备份到阿里云OSS上,该方案具有低成本、秒级RPO的优势; 对于等级5的业务而言,可以通过DTS数据传输服务将本地IDC或者其他云产商的数据库备份到阿里云上去,实现热备或者双活解决方案,实现秒级RPO和秒级RTO。 阿里云数据库新型灾备方案众所周知,传统灾备解决方案存在成本高昂、实施困难、运维复杂、RTO和RPO无法保障等问题。 阿里云拥有遍布全球安全可靠的数据中心,是企业用户天然的异地灾备中心。阿里云的新型灾备方案可以为您提供低成本、高质量、开箱即用的数据库灾备服务。 1、数据库备份服务DBS数据库备份服务DBS结合阿里云对象存储服务OSS,能够为用户提供秒级RPO以及低成本的特性,并且实现了国家灾备等级4的相应能力。 用户自建的IDC或者来自其他云厂商的数据库可以通过DBS备份到阿里云OSS之上,而且整个备份的实现过程非常简单,只需要打通网络就可以通过DBS实现数据备份到云上,当出现灾难的时候就能够完成云上数据库快速恢复。 除了和云上数据库进行打通之外,对于数据的备份集而言,也可以通过数据湖服务直接进行查询和验证(无需恢复),这也是阿里云特有的能力之一。 阿里云数据库备份服务DBS主要有如下优势: 秒级RPO:因为数据库发生变更的时候,首先会记录日志,再刷新数据。而阿里巴巴沉淀了一整套数据库解析技术,通过这个技术能够实现秒级冷备到阿里云上的能力,并且其冷备数据和在线数据之间仅存在秒级延时。低成本:借助OSS的能力可以实现对于数据的周期性归档,并且允许数据库只备份核心关注的数据业务表,仅备份有效数据,同时进行加密和压缩。备份数据可在线读,验证有效性:基于DLA的数据湖能力,备份逻辑数据集允许用户直接进行备份集查询,查询里面的数据内容并且校验其中的数据。基于RDS的能力能够帮助用户在出现灾难时实现数据库的快速恢复。丰富的备份数据源:阿里云数据库备份服务DBS能够支持非常丰富的数据源,包括Oracle、MySQL、SQLServer、MongoDB以及Redis等。2、数据库热备以及双活架构DTS 结合DTS和RDS就能够实现云上数据库热备,可以实现国标等级5的灾备能力。无论是将业务中心建立在自建IDC还是其他云厂商上,通过DTS热备到阿里云上,当出现本地IDC出现数据库故障或者误操作的时候,用户就可以一键切换到云热备之上,实现秒级RPO和秒级RTO。 您还可以更进一步,借助DTS和RDS实现多活,除了将业务切换到阿里云上之外,还可以反向建立阿里云到本地IDC数据库的同步链路,从而建立双向同步通道,这样就能够提供异地双活能力,两端都可以进行写入和切换。业务也可以在云上和本地IDC之间进行分流,从而实现就近写入和就近服务的查询能力,同时能够支持实现容灾。 如果采用传统热备方案,将数据热备到云上之后可以支持实现秒级RPO的数据库切换,但是当切换完成之后如果想要去恢复灾备系统,则需要一定的恢复过程,但是当建立了双向同步通道之后,可以很快地切换到阿里云,同时很快地切换回来,因此能够支持企业实现在线的容灾演练。 关于阿里云数据库传输服务DTS: 阿里巴巴在2011年左右开始投入做数据库的日志解析,而DTS除了能够实现日志解析之外,还能够实现高效的数据同步,是阿里巴巴内部实现异地多活的基础设施,也是阿里巴巴的数据从生产到消费的数据流基础设施。 DTS也支持了非常丰富的数据源,包括关系型数据库、NoSQL及大数据等17种数据源,承担了阿里云上的40多万的数据传输任务。 3、基于DMS+HDM的数据库统一管理方案 除了上述的DBS和DTS两款灾备产品之外,当用户使用线下到线上的数据同步或者线下到线上数据热备之后,就会形成一个混合云数据库架构。 阿里云为此提供了一整套数据库混合云统一管理解决方案,该方案沉淀了阿里在脱敏审计、变更管控以及研发协同等多方面的能力。 在混合云上,如果数据库分布在自建的IDC、其他云厂商以及阿里云上,就可以通过阿里云的混合云数据库管理(HDM)进行统一管理,通过One Console实现统一监控、告警、性能优化和风险识别。 了解企业级云灾备解决方案——“十万先行者计划”,请点击:https://promotion.aliyun.com/ntms/act/hclouddr/index.html 相关阅读阿里云发布企业级云灾备解决方案,十万先行者计划开启普惠灾备专访阿里数据库备份专家 教你Pick最有效的备份系统 本文作者:七幕阅读原文 本文为云栖社区原创内容,未经允许不得转载。

June 10, 2019 · 1 min · jiezi

移动研发-DevOps-落地实践

作者:姚兰天(十镜),蚂蚁金服技术专家。概要:传统的研发模式已经无法适应企业在数字化转型中快速迭代以及研发协同的要求,建设符合业务场景特性和有效支撑高并发、持续迭代集成需求的研发效能实践迫在眉睫。本文将围绕支付宝如何随着移动市场的高速发展,逐步沉淀优化出适用业务发展需求的研发效能实践。 现场视频):http://t.cn/Ai9HuCNT 大家好,我是来自支付宝终端工程技术团队的十境。本文将带领大家了解支付宝移动端如何随着移动市场的告诉发展,逐步沉淀优化出适用业务发展需求的研发效能实践。 0. 背景如何解决百万级代码的极速构建?如何让上百开发者在同一个 App 上高效研发协同?如何保障代码频繁变更下的交付质量?显然,传统的研发模式已经无法适应企业在数字化转型中快速迭代以及研发协同的要求,建设符合业务场景特性和有效支撑高并发、持续迭代集成需求的研发效能实践迫在眉睫。 1. 研发协作平台现状关于支付宝在移动端研发平台构建的历程,首先我们先展开看看目前平台的现状,并讲述如何参考 DevOps “三步工作法” 来正向建模我们的交付价值流,以及这些活动中比较核心的分支模型,构建,持续集成等。 研发协作平台大概从 2014 年开始建设,如今支持的 iOS 和 Android 客户端代码量都已经超过 300w 行,拆分的 Bundle 数量也都在 300 个以上。我们每周的构建次数在 1.4W,安装包平均每天会灰度 2~3 次,开发测试同学达到近千人的规模。 我们支撑了蚂蚁集团支付宝、网商银行、财富、口碑等产品的交付,支持的技术栈从最开始的 Android 和 iOS,演进到厂商 SDK、小程序、IoT 及桌面应用等。在这些能力输出的下层是我们沉淀的一套研发协作流程,从需求到开发、测试、交付、及发布后的反馈闭环。 支付宝业务的飞速发展,从工具到超级 App,代码量猛增到 300W+。技术架构上,采用了模块化动态加载的技术,这就给我们提了一个问题,如何将 300+ 个 Bundle,在不同的团队里开发,集成,变成一个高质量的 App 推送到用户手机上。 2. DevOps 三步工作法 DevOps 三步工作法,第一步,我们正向价值流建模,把研发划分为 5 个阶段(需求阶段、开发阶段、测试阶段、集成阶段以及发布阶段),定义每个阶段的准入准出标准。比如需求分析的结果需要拆分到 User Story 级别,通过大家需求评审,达成一致。接着,每个阶段我们提炼出最重要的活动,比如开发阶段,开发同学每天最多的就是写代码,代码 Review,以及代码 MR/Push 后触发的自动化流水线,如编译、扫描、自动化测试等。这些阶段和每个阶段的活动以及人员之间的协作,就构成了我们交付大图的脉络,即我们常说的价值流。 通过正向价值流的建模,结合团队的开发实践,便可以得到研发协作平台产品的一个信息架构图。 如上图所示,随时间演进,我们沉淀出了一套产品信息图:从最开始仅仅是安装包构建的一个在线工具,到产物管理,版本管理,架构拆分后的模块信息、模块构建管理,根据构建的产物及场景的不同,抽象出了构建配置、渠道配置、持续集成的配置,当然还有其它元数据如证书信息的配置。 我们参考了敏捷、Scrum 实践,抽象出迭代的概念来组织每个模块涉及的资源如代码仓库、需求、缺陷、任务、持续集成流水线还有最重要的团队和人员。发布定义了我们交付的产物,同时也是各团队工作集成到一起的大容器。 这是我们研发协作平台的门户首页,开发者能直观地看到自己关注项目的日常发布、迭代信息,以及每天需要解决的待办等,每个类目和我们上一页提炼的信息架构相对应。 拆解「依赖配置」 前面提到我们通过架构拆分,团队模块化协作的方式来应对激增的业务需求。那么之所以有这张截图,是想让大家对我们的依赖配置有个直观的感受,每个模块的产物可以理解为一个 Zip 包,在某一个安装包发布中管理这样由 300 多个 Bundle 构成的一个依赖列表。我们的需求集成某种意义上就是这个依赖列表中中模块版本的升级。模块拆分也让我们的小批量快速交付成为得以践行、拥有 2 周发布一个大版本的能力。 ...

June 10, 2019 · 1 min · jiezi

开源项目几点心得Java架构必会几大技术点

Java架构必会几大技术点 关于学习架构,必须会的几点技术 列表项目java反射技术xml文件处理properties属性文件处理线程安全机制annocation注解设计模式代理机制(aop)serlvet基础(过滤器等等)几样比较实用的技术:  - 1. 模板语言freemarker  - 2. ognl  - 3. gson json工具类   大家对于几大框架望而生畏,实际上只要明白他的原理,就会触类旁通,在这里我说说自己的几点拙见!架构QQ交流群: 39596137MVC层(Struts,Springmvc):非常简单就是采用一个servlet实现统一跳转,配置文件保存了请求、处理类、转发请求的关系(通过xml文件或者注解)操作流程:页面触发请求,框架通过读取配置文件获取到处理类,然后通过反射实例化该类,进行对应的业务处理(现在流行的零配置,更是简化了mvc层的编写)持久层(Mybatis/Hibernate):     mybatis其实就是sql+mybatis逻辑标签     逻辑标签的理解如何大家用过模板语言freemarer或者velocity应该会很容易理解,就是自定义的规则标签     Hibernate略显高级,也很简单,他是采用注解或者配置的方式将实体字段和表字段进行一个配置,在启动的时候动态生成sql; 大家可以看下开源项目minidao,就会知道持久层原来写很简单;所以架构可以简单理解为:     配置+反射+设计模式+脚本+AOP     配置常用做法:       1.xml文件       2.annocation注解       3.properties属性文件       4.零配置思想 脚本处理方法:      可以自己写,也可以采用模板语言freemarker等等

June 8, 2019 · 1 min · jiezi

UI2CODE再进化结合Redux的框架升级

摘要: 自从有了ui2code,妈妈再也不用担心我加班背景UI2CODE的目标是通过分析视觉稿得到对应的代码,让AI提高开发效率。然而过去静态化页面的产出,不能得到业务场景的需求。针对于此,我们以UI2CODE自动化开发为基底,结合Redux的消息机制,将自动化生成的维度提升到页面的处理。 透过框架,可自动化生成页面代码,并且具有数据驱动展示、消息派送等动态性能力。期望在复杂的业务场景下,简化开发的工作。并且在使用一致化的架构下,避免未来业务代码耦合严重,使代码分工明确,容易修改维护。 进化后的UI2CODE? 开发者可以透过Intellij Plugin分析视觉稿后会生成对应的视图代码,以及和此页面框架结合的能力。 在整体开发的定位上我们的野心是,提供一套可扩充的页面消息框架,并且自动生成大部分的UI代码。目标带来以下的好处: 快速建构新应用,框架将完成大部分的事,业务开发同学只要专注于业务代码让开发人员的进入门槛降低,在我们落地的经验中,后端同学只要有基本的概念,无需花费太多经历,可直接上手帮忙写代码让页面的架构统一化,让页面的开发有统一的规则,也方便后续的维护提供通用的组件库,可重复利用核心设计思路我们在设计上主要参考于MVP、CLEAN、VIPER以及FISH_REDUX等框架。目的在实践高聚合低耦合的前提下,分拆为视图组装层、视图展示层、数据层、事件交互层。层层分离职责,不互相干扰,又可互相通讯。 分层拆开的好处为容易维护,并且可以单元测试"业务展示"以及"业务逻辑",框架上清晰,容易有一个统一的遵循规则,达到简单编写重复可利用。 UI2CODE页面框架的设计概念为,主要分为Page、Card、Reaction三大元素。在上层的Page负责组装页面,制定页面的风格。Card则为可重复利用的视图展示元素。Reaction则为事件反应的监听。 在整个页面框架上,可以透过UI2CODE Plugin分析自动化生成业务UI,产生出Page、Card、Card(DataModel)。仅需修改Card上额外的业务展示,以及撰写Reaction中的业务逻辑。 具体实现架构在介绍框架组件前,先理解UI2CODE的基本组成页面目录如下: 以Page为单位,页面本体demo_page为其他页面路由调用的起点,透过设置Config.dart决定内部含的卡片列表以及事件处理列表,组合出Card以及Reaction的关联。 其详细的架构关系如下: PagePage为框架基础的单位,为单一页面,负责决定视图的组装以及页面的样式(Template)。 在Page之内可包含若干的Card以及Reaction,分别为视图的展示以及视图的事件处理。可以很清晰地将业务场景做分割成小模块,不互相影响。 Abstract class PageStatelessWidget extends StatelessWidgetimplements Lifecycle 可由UI2CODE Plugin自动化产生框架统一分发管理页面生命周期Lifecycle透过设定Template指定页面要呈现的样版,或者修改如背景等属性透过设定Config指定这个页面含有的Cards和Reactions透过设定PageState可添加额外的数据 Page TemplateTemplate样板为页面的抽象化,在整体页面上分为多个样板可选择。并且支持设置AppBar(非必选)、Header(非必选)、Body、Stack(非必选)等子样板。 样板可比喻为页面的容器,目前支持以下样板,并且可扩充: PageTemplate,通用页面容器,并支持NestedScrollView的Silver Header滚动(若需要)PageBottomNavigatorTemplate,含有底部导航的容器,如首页PageSwitchTabTemplate,含有分页Tab功能的容器各个子样板也有相对应的Template可选择,如在Body内的样板功能为决定内部Cards排列的方式。举例来说,BodyListViewTemplate则是列表展示。 使用Template最大的好处为减少开发工作,可直接使用封装后的接口。并且页面内的所有样板将共用消息机制,可以互相传递消息,如Body内部的卡片很容易发送消息给AppBar等。这是框架上的有力之处。 Page ConfigConfig决定页面的组装,包含了元件有哪些,以及事件处理反射的类绑定。 Extends PageConfig 可由UI2CODE Plugin自动化产生透过设定cards注册这个页面所载入的卡片透过设定actions注册这个页面所响应的类,支持卡片事件以及页面事件支持额外设置AppBar、Header、Stack等组件(非必须)如何绑定,举例来说: void actionConfig(List< List < Function>> actions) {//卡片Card8575, 响应事件的类为Card8575Reactionactions.add(< Function>[() => Card8575, () => new Card8575Reaction()]);} CardCard代表基本的视图展示,业务UI,其中包含了View widget以及DataModel数据。框架内会将两者Data binding起来,由数据来驱动最终展示的呈现。达到如MVP中View和ViewModel的隔离效果。 Abstract class BaseCard<T extends DataModel> extends StatefulWidget 可由UI2CODE Plugin分析视觉稿产生透过BaseCard<T extends DataModel>的标准化,指定数据DataModel绑定Card可以发出事件,不直接操控数据,而让接收者响应 ...

June 6, 2019 · 1 min · jiezi

漫谈分布式计算框架

摘要: 本文主要谈了一些分布式计算框架方面的心得。如果问 mapreduce 和 spark 什么关系,或者说有什么共同属性,你可能会回答他们都是大数据处理引擎。如果问 spark 与 tensorflow 呢,就可能有点迷糊,这俩关注的领域不太一样啊。但是再问 spark 与 MPI 呢?这个就更远了。虽然这样问多少有些不严谨,但是它们都有共同的一部分,这就是我们今天谈论的一个话题,一个比较大的话题:分布式计算框架。 不管是 mapreduce,还是 spark 亦或 tensorflow,它们都是利用分布式的能力,运行某些计算,解决一些特定的问题。从这个 level 讲,它们都定义了一种“分布式计算模型”,即提出了一种计算的方法,通过这种计算方法,就能够解决大量数据的分布式计算问题。它们的区别在于提出的分布式计算模型不同。Mapreduce 正如其名,是一个很基本的 map-reduce 式的计算模型(好像没说一样)。Spark 定义了一套 RDD 模型,本质上是一系列的 map/reduce 组成的一个 DAG 图。Tensorflow 的计算模型也是一张图,但是 tensorflow 的图比起 spark 来,显得更“复杂”一点。你需要为图中的每个节点和边作出定义。根据这些定义,可以指导 tensorflow 如何计算这张图。Tensorflow 的这种具体化的定义使它比较适合处理特定类型的的计算,对 tensorflow 来讲就是神经网络。而 spark 的 RDD 模型使它比较适合那种没有相互关联的的数据并行任务。那么有没有一种通用的、简单的、性能还高的分布式计算模型?我觉着挺难。通用往往意味着性能不能针对具体情形作出优化。而为专门任务写的分布式任务又做不到通用,当然也做不到简单。 插一句题外话,分布式计算模型有一块伴随的内容,就是调度。虽然不怎么受关注,但这是分布式计算引擎必备的东西。mapreduce 的调度是 yarn,spark 的调度有自己内嵌的调度器,tensorflow 也一样。MPI 呢?它的调度就是几乎没有调度,一切假设集群有资源,靠 ssh 把所有任务拉起来。调度实际上应当分为资源调度器和任务调度器。前者用于向一些资源管理者申请一些硬件资源,后者用于将计算图中的任务下发到这些远程资源进行计算,其实也就是所谓的两阶段调度。近年来有一些 TensorflowOnSpark 之类的项目。这类项目的本质实际上是用 spark 的资源调度,加上 tensorflow 的计算模型。 当我们写完一个单机程序,而面临数据量上的问题的时候,一个自然的想法就是,我能不能让它运行在分布式的环境中?如果能够不加改动或稍加改动就能让它分布式化,那就太好了。当然现实是比较残酷的。通常情况下,对于一个一般性的程序,用户需要自己手动编写它的分布式版本,利用比如 MPI 之类的框架,自己控制数据的分发、汇总,自己对任务的失败做容灾(通常没有容灾)。如果要处理的目标是恰好是对一批数据进行批量化处理,那么 可以用 mapreduce 或者 spark 预定义的 api。对于这一类任务,计算框架已经帮我们把业务之外的部分(脚手架代码)做好了。同样的,如果我们的任务是训练一个神经网络,那么用 tensorflow pytorch 之类的框架就好了。这段话的意思是,如果你要处理的问题已经有了对应框架,那么拿来用就好了。但是如果没有呢?除了自己实现之外有没有什么别的办法呢? ...

June 6, 2019 · 2 min · jiezi

达摩院首席数据库科学家李飞飞云原生新战场我们如何把握先机

阿里妹导读:云计算大潮来袭,传统数据库市场正面临重新洗牌的情境,包括云数据库在内的一批新生力量崛起,动摇了传统数据库的垄断地位,而由云厂商主导的云原生数据库则将这种“改变”推向了高潮。云时代的数据库将面临怎样的变革?云原生数据库有哪些独特优势?在 DTCC 2019大会上,阿里巴巴副总裁 李飞飞博士就《下一代云原生数据库技术与趋势》进行了精彩分享。 李飞飞(花名:飞刀),阿里巴巴集团副总裁,高级研究员,达摩院首席数据库科学家,阿里云智能事业群数据库产品事业部负责人,ACM 杰出科学家。 大势所趋:云数据库市场份额增速迅猛如下图所示的是 Gartner 关于全球数据库市场份额的报告,该报告指出目前全球数据库市场份额大约为400亿美金,其中,中国数据库市场份额占比为3.7%,大约为14亿美金。 具体到数据库市场分布,传统五大数据库厂商 Oracle、Microsoft、IBM、SAP、Teradata 占比达到了80%,云数据库的份额占比接近10%,并且云数据库市场份额占比每年也在快速增长,因此, Oracle、MongoDB 等也在大力布局其在云数据库市场的竞争态势。 根据 DB-Engines 数据库市场分析显示,数据库系统正朝着多样化、多元化的方向发展,从传统的 TP 关系型数据库发展到今天的多源异构的数据库形态。目前,处于主流位置的还是大家耳熟能详的数据库系统,比如商业数据库 Oracle、SQL Server以及开源的 MySQL、PostgreSQL 等。而一些比较新的数据库系统,比如MongoDB、Redis 则开辟了一个新的赛道。数据库 License 的传统销售方式在逐渐走下坡路,而开源以及云上数据库 License 的流行程度却在不断提升。 数据库:云上应用关键的一环正如 AWS 创始人 Jeff Bezos 所说:“The real battle will be in databases”。因为云最早是从 IaaS 做起来的,从虚拟机、存储、网络,到现在如火如荼的语音识别、计算机视觉以及机器人等智能化应用,都是基于 IaaS 的,而数据库就是连接 IaaS 与智能化应用 SaaS 最为关键的一环。从数据产生、存储到消费的各个环节,数据库都至关重要。 数据库主要包括四大板块,即 OLTP、OLAP、NoSQL 以及数据库服务和管理类工具,也是云数据库厂商发力的四个方向。对于 OLTP 而言,技术发展已经历经了40年,而如今大家还在做的一件事情就是“加10元和减10元”,也就是所谓的事务处理。当数据量变得越来越大和读写冲突的原因,对数据进行在线实时分析的需求衍生出了 OLAP。由于需要 Scale out,而数据强一致性不能够得到保证,就有了NoSQL 。而最近又出现了一个新名词—— NewSQL,这是因为 NoSQL 也有所不足,故将传统 OLTP 的 ACID 保证与 NoSQL 的 Scale out 能力进行了整合,变成了NewSQL。 ...

June 6, 2019 · 2 min · jiezi

Lambda-plus-云上大数据解决方案

本文会简述大数据分析场景需要解决的技术挑战,讨论目前主流大数据架构模式及其发展。最后我们将介绍如何结合云上存储、计算组件,实现更优的通用大数据架构模式,以及该模式可以涵盖的典型数据处理场景。 大数据处理的挑战现在已经有越来越多的行业和技术领域需求大数据分析系统,例如金融行业需要使用大数据系统结合VaR(value at risk)或者机器学习方案进行信贷风控,零售、餐饮行业需要大数据系统实现辅助销售决策,各种IOT场景需要大数据系统持续聚合和分析时序数据,各大科技公司需要建立大数据分析中台等等。抽象来看,支撑这些场景需求的分析系统,面临的都是大致相同的技术挑战: 业务分析的数据范围横跨实时数据和历史数据,既需求低延迟的实时数据分析,也需求对PB级的历史数据进行探索性的数据分析;可靠性和可扩展性问题,用户可能会存储海量的历史数据,同时数据规模有持续增长的趋势,需要引入分布式存储系统来满足可靠性和可扩展性需求,同时保证成本可控;技术栈深,需要组合流式组件、存储系统、计算组件和;可运维性要求高,复杂的大数据架构难以维护和管控;简述大数据架构发展Lambda架构Lambda架构是目前影响最深刻的大数据处理架构,它的核心思想是将不可变的数据以追加的方式并行写到批和流处理系统内,随后将相同的计算逻辑分别在流和批系统中实现,并且在查询阶段合并流和批的计算视图并展示给用户。Lambda的提出者Nathan Marz还假定了批处理相对简单不易出现错误,而流处理相对不太可靠,因此流处理器可以使用近似算法,快速产生对视图的近似更新,而批处理系统会采用较慢的精确算法,产生相同视图的校正版本。 Lambda架构典型数据流程是(http://lambda-architecture.net/)): 所有的数据需要分别写入批处理层和流处理层;批处理层两个职责:(i)管理master dataset(存储不可变、追加写的全量数据), (ii)预计算batch view;服务层对batch view建立索引,以支持低延迟、ad-hoc方式查询view;流计算层作为速度层,对实时数据计算近似的real-time view,作为高延迟batch view的补偿快速视图;所有的查询需要合并batch view和real-time view;Lambda架构设计推广了在不可变的事件流上生成视图,并且可以在必要时重新处理事件的原则,该原则保证了系统随需求演进时,始终可以创建相应的新视图出来,切实可行的满足了不断变化的历史数据和实时数据分析需求。 Lambda架构的四个挑战Lambda架构非常复杂,在数据写入、存储、对接计算组件以及展示层都有复杂的子课题需要优化: 写入层上,Lambda没有对数据写入进行抽象,而是将双写流批系统的一致性问题反推给了写入数据的上层应用;存储上,以HDFS为代表的master dataset不支持数据更新,持续更新的数据源只能以定期拷贝全量snapshot到HDFS的方式保持数据更新,数据延迟和成本比较大;计算逻辑需要分别在流批框架中实现和运行,而在类似Storm的流计算框架和Hadoop MR的批处理框架做job开发、调试、问题调查都是比较复杂的;结果视图需要支持低延迟的查询分析,通常还需要将数据派生到列存分析系统,并保证成本可控;流批融合的Lambda架构针对Lambda架构的问题3,计算逻辑需要分别在流批框架中实现和运行的问题,不少计算引擎已经开始往流批统一的方向去发展,例如Spark和Flink,从而简化lambda架构中的计算部分。实现流批统一通常需要支持:1.以相同的处理引擎来处理实时事件和历史回放事件;2.支持exactly once语义,保证有无故障情况下计算结果完全相同;3.支持以事件发生时间而不是处理时间进行窗口化; Kappa架构Kappa架构由Jay Kreps提出,不同于Lambda同时计算流计算和批计算并合并视图,Kappa只会通过流计算一条的数据链路计算并产生视图。Kappa同样采用了重新处理事件的原则,对于历史数据分析类的需求,Kappa要求数据的长期存储能够以有序log流的方式重新流入流计算引擎,重新产生历史数据的视图。 Kappa方案通过精简链路解决了1数据写入和3计算逻辑复杂的问题,但它依然没有解决存储和展示的问题,特别是在存储上,使用类似kafka的消息队列存储长期日志数据,数据无法压缩,存储成本很大,绕过方案是使用支持数据分层存储的消息系统(如Pulsar,支持将历史消息存储到云上存储系统),但是分层存储的历史日志数据仅能用于Kappa backfill作业,数据的利用率依然很低。 Lambda和Kappa的场景区别:Kappa不是Lambda的替代架构,而是其简化版本,Kappa放弃了对批处理的支持,更擅长业务本身为append-only数据写入场景的分析需求,例如各种时序数据场景,天然存在时间窗口的概念,流式计算直接满足其实时计算和历史补偿任务需求;Lambda直接支持批处理,因此更适合对历史数据有很多ad hoc查询的需求的场景,比如数据分析师需要按任意条件组合对历史数据进行探索性的分析,并且有一定的实时性需求,期望尽快得到分析结果,批处理可以更直接高效地满足这些需求;Kappa+Kappa+是Uber提出流式数据处理架构,它的核心思想是让流计算框架直读HDFS类的数仓数据,一并实现实时计算和历史数据backfill计算,不需要为backfill作业长期保存日志或者把数据拷贝回消息队列。Kappa+将数据任务分为无状态任务和时间窗口任务,无状态任务比较简单,根据吞吐速度合理并发扫描全量数据即可,时间窗口任务的原理是将数仓数据按照时间粒度进行分区存储,窗口任务按时间序一次计算一个partition的数据,partition内乱序并发,所有分区文件全部读取完毕后,所有source才进入下个partition消费并更新watermark。事实上,Uber开发了Apache hudi框架来存储数仓数据,hudi支持更新、删除已有parquet数据,也支持增量消费数据更新部分,从而系统性解决了问题2存储的问题。下图3是完整的Uber大数据处理平台,其中Hadoop -> Spark -> Analytical data user涵盖了Kappa+数据处理架构。 混合分析系统的Kappa架构Lambda和Kappa架构都还有展示层的困难点,结果视图如何支持ad-hoc查询分析,一个解决方案是在Kappa基础上衍生数据分析流程,如下图4,在基于使用Kafka + Flink构建Kappa流计算数据架构,针对Kappa架构分析能力不足的问题,再利用Kafka对接组合ElasticSearch实时分析引擎,部分弥补其数据分析能力。但是ElasticSearch也只适合对合理数据量级的热数据进行索引,无法覆盖所有批处理相关的分析需求,这种混合架构某种意义上属于Kappa和Lambda间的折中方案。 Lambda plus:Tablestore + Blink流批一体处理框架Lambda plus是基于Tablestore和Blink打造的云上存在可以复用、简化的大数据架构模式,架构方案全serverless即开即用,易搭建免运维。表格存储(Tablestore)是阿里云自研的NoSQL多模型数据库,提供PB级结构化数据存储、千万TPS以及毫秒级延迟的服务能力,表格存储提供了通道服务(TunnelService)支持用户以按序、流式地方式消费写入表格存储的存量数据和实时数据,同时表格存储还提供了多元索引功能,支持用户对结果视图进行实时查询和分析。Blink是阿里云在Apache Flink基础上深度改进的实时计算平台,Blink旨在将流处理和批处理统一,实现了全新的 Flink SQL 技术栈,在功能上,Blink支持现在标准 SQL 几乎所有的语法和语义,在性能上,Blink也比社区Flink更加强大。在TableStore + blink的云上Lambda架构中,用户可以同时使用表格存储作为master dataset和batch&stream view,批处理引擎直读表格存储产生batch view,同时流计算引擎通过Tunnel Service流式处理实时数据,持续生成stream view。 如上图5,其具体组件分解: Lambda batch层: Tablestore直接作为master dataset,支持用户直读,配合Tablestore多元索引,用户的线上服务直读、ad-hoc查询master dataset并将结果返回给用户;blink批处理任务向Tablestore下推SQL的查询条件,直读Tablestore master dataset,计算batch view,并将batch view重新写回Tablestore;Streaming层: ...

June 5, 2019 · 1 min · jiezi

基于大数据的舆情分析系统架构-架构篇

前言互联网的飞速发展促进了很多新媒体的发展,不论是知名的大V,明星还是围观群众都可以通过手机在微博,朋友圈或者点评网站上发表状态,分享自己的所见所想,使得“人人都有了麦克风”。不论是热点新闻还是娱乐八卦,传播速度远超我们的想象。可以在短短数分钟内,有数万计转发,数百万的阅读。如此海量的信息可以得到爆炸式的传播,如何能够实时的把握民情并作出对应的处理对很多企业来说都是至关重要的。大数据时代,除了媒体信息以外,商品在各类电商平台的订单量,用户的购买评论也都对后续的消费者产生很大的影响。商家的产品设计者需要汇总统计和分析各类平台的数据做为依据,决定后续的产品发展,公司的公关和市场部门也需要根据舆情作出相应的及时处理,而这一切也意味着传统的舆情系统升级成为大数据舆情采集和分析系统。分析完舆情场景后,我们再来具体细化看下大数据舆情系统,对我们的数据存储和计算系统提出哪些需求: 海量原始数据的实时入库:为了实现一整套舆情系统,需要有上游原始输出的采集,也就是爬虫系统。爬虫需要采集各类门户,自媒体的网页内容。在抓取前需要去重,抓取后还需要分析提取,例如进行子网页的抓取。原始网页数据的处理:不论是主流门户还是自媒体的网页信息,抓取后我们需要做一定的数据提取,把原始的网页内容转化为结构化数据,例如文章的标题,摘要等,如果是商品点评类消息也需要提取有效的点评。结构化数据的舆情分析:当各类原始输出变成结构化的数据后,我们需要有一个实时的计算产品把各类输出做合理的分类,进一步对分类后的内容进行情感打标。根据业务的需求这里可能会产生不同的输出,例如品牌当下是否有热点话题,舆情影响力分析,转播路径分析,参与用户统计和画像,舆论情感分析或者是否有重大预警。舆情分析系统中间和结果数据的存储,交互分析查询:从网页原始数据清洗到最终的舆情报表这中间会产生很多类型的数据。这些数据有的会提供给数据分析同学进行舆情分析系统的调优,有的数据会提供给业务部门根据舆情结果进行决策。这些查询可能会很灵活,需要我们的存储系统具备全文检索,多字段组合灵活的交互分析能力。重大舆情事件的实时预警:对于舆情的结果除了正常的搜索和展示需求以外,当有重大事件出现我们需要能做到实时的预警。我们计划分两篇介绍完整的舆情新架构,第一篇主要是提供架构设计,会先介绍时下主流的大数据计算架构,并分析一些优缺点,然后引入舆情大数据架构。第二篇会有完整的数据库表设计和部分示例代码。大家敬请期待。 系统设计需求分析 结合文章开头对舆情系统的描述,海量大数据舆情分析系统流程图大体如下: 原始网页存储库,这个库需要能支持海量数据,低成本,低延时写入。网页数据写入后,要做实时结构化提取,提取出来的数据再进行降噪,分词,图片ocr处理等。对分词文本,图片进行情感识别产生舆情数据结果集。传统的离线全量计算很难满足舆情系统的时效性需求。计算引擎在做数据处理时,可能还需要从存储库中获取一些元数据,例如用户信息,情感词元数据信息等。除了实时的计算链路,对存量数据定期要做一些聚类,优化我们的情感词识别库,或者上游根据业务需要触发情感处理规则更新,根据新的情感打标库对存量数据做一次舆情计算。舆情的结果数据集有不同类的使用需求。对于重大舆情,需要做实时的预警。完整的舆情结果数据展示层需要支持全文检索,灵活的属性字段组合查询。业务上可能根据属性字段中的置信度,舆情时间,或者关键词组合进行分析。根据前面的介绍,舆情大数据分析系统需要两类计算,一类是实时计算包括海量网页内容实时抽取,情感词分析并进行网页舆情结果存储。另一类是离线计算,系统需要对历史数据进行回溯,结合人工标注等方式优化情感词库,对一些实时计算的结果进行矫正等。所以在系统设计上,需要选择一套既可以做实时计算又能做批量离线计算的系统。在开源大数据解决方案中,Lambda架构恰好可以满足这些需求,下面我们来介绍下Lambda的架构。 Lambda架构 (wiki) Lambda架构可以说是Hadoop,Spark体系下最火的大数据架构。这套架构的最大优势就是在支持海量数据批量计算处理(也就是离线处理)同时也支持流式的实时处理(即热数据处理)。具体是如何实现的呢,首先上游一般是一个队列服务例如kafka,实时存储数据的写入。kafka队列会有两个订阅者,一个是全量数据即图片中上半部分,全量数据会被存储在类似HDFS这样的存储介质上。当有离线计算任务到来,计算资源(例如Hadoop)会访问存储系统上的全量数据,进行全量批计算的处理逻辑。经过map/reduce环节后全量的结果会被写入一个结构化的存储引擎例如Hbase中,提供给业务方查询。队列的另一个消费订阅方是流计算引擎,流计算引擎往往会实时的消费队列中的数据进行计算处理,例如Spark Streaming实时订阅Kafka的数据,流计算结果也会写入一个结构化数据引擎。批量计算和流计算的结果写入的结构化存储引擎即上图标注3的"Serving Layer",这一层主要提供结果数据的展示和查询。在这套架构中,批量计算的特点是需要支持处理海量的数据,并根据业务的需求,关联一些其他业务指标进行计算。批量计算的好处是计算逻辑可以根据业务需求灵活调整,同时计算结果可以反复重算,同样的计算逻辑多次计算结果不会改变。批量计算的缺点是计算周期相对较长,很难满足实时出结果的需求,所以随着大数据计算的演进,提出了实时计算的需求。实时计算在Lambda架构中是通过实时数据流来实现,相比批处理,数据增量流的处理方式决定了数据往往是最近新产生的数据,也就是热数据。正因为热数据这一特点,流计算可以满足业务对计算的低延时需求,例如在舆情分析系统中,我们往往希望舆情信息可以在网页抓取下来后,分钟级别拿到计算结果,给业务方充足的时间进行舆情反馈。下面我们就来具体看一下,基于Lambda架构的思想如何实现一套完整的舆情大数据架构。 开源舆情大数据方案通过这个流程图,让我们了解了整个舆情系统的建设过程中,需要经过不同的存储和计算系统。对数据的组织和查询有不同的需求。在业界基于开源的大数据系统并结合Lambda架构,整套系统可以设计如下: 系统的最上游是分布式的爬虫引擎,根据抓取任务抓取订阅的网页原文内容。爬虫会把抓取到的网页内容实时写入Kafka队列,进入Kafka队列的数据根据前面描述的计算需求,会实时流入流计算引擎(例如Spark或者Flink),也会持久化存储在Hbase,进行全量数据的存储。全量网页的存储可以满足网页爬取去重,批量离线计算的需求。流计算会对原始网页进行结构化提取,将非结构化网页内容转化为结构数据并进行分词,例如提取出网页的标题,作者,摘要等,对正文和摘要内容进行分词。提取和分词结果会写回Hbase。结构化提取和分词后,流计算引擎会结合情感词库进行网页情感分析,判断是否有舆情产生。流计算引擎分析的舆情结果存储Mysql或者Hbase数据库中,为了方便结果集的搜索查看,需要把数据同步到一个搜索引擎例如Elasticsearch,方便进行属性字段的组合查询。如果是重大的舆情时间,需要写入Kafka队列触发舆情报警。全量的结构化数据会定期通过Spark系统进行离线计算,更新情感词库或者接受新的计算策略重新计算历史数据修正实时计算的结果。开源架构分析上面的舆情大数据架构,通过Kafka对接流计算,Hbase对接批计算来实现Lambda架构中的“batch view”和“real-time view”,整套架构还是比较清晰的,可以很好的满足在线和离线两类计算需求。但是把这一套系统应用在生产并不是一件容易的事情,主要有下面一些原因。 整套架构涉及到非常多的存储和计算系统包括:Kafka,Hbase,Spark,Flink,Elasticsearch。数据会在不同的存储和计算系统中流动,运维好整套架构中的每一个开源产品都是一个很大的挑战。任何一个产品或者是产品间的通道出现故障,对整个舆情分析结果的时效性都会产生影响。为了实现批计算和流计算,原始的网页需要分别存储在Kafka和Hbase中,离线计算是消费hbase中的数据,流计算消费Kafka的数据,这样会带来存储资源的冗余,同时也导致需要维护两套计算逻辑,计算代码开发和维护成本也会上升。舆情的计算结果存储在Mysql或者Hbase,为了丰富组合查询语句,需要把数据同步构建到Elasticsearch中。查询的时候可能需要组合Mysql和Elasticsearch的查询结果。这里没有跳过数据库,直接把结果数据写入Elasticsearch这类搜索系统,是因为搜索系统的数据实时写入能力和数据可靠性不如数据库,业界通常是把数据库和搜索系统整合,整合下的系统兼备了数据库和搜索系统的优势,但是两个引擎之间数据的同步和跨系统查询对运维和开发带来很多额外的成本。新的大数据架构Lambda plus通过前面的分析,相信大家都会有一个疑问,有没有简化的的大数据架构,在可以满足Lambda对计算需求的假设,又能减少存储计算以及模块的个数呢。Linkedin的Jay Kreps提出了Kappa架构,关于Lambda和Kappa的对比可以参考"云上大数据方案"这篇,这里不展开详细对比,简单说下,Kappa为了简化两份存储,取消了全量的数据存储库,通过在Kafka保留更长日志,当有回溯重新计算需求到来时,重新从队列的头部开始订阅数据,再一次用流的方式处理Kafka队列中保存的所有数据。这样设计的好处是解决了需要维护两份存储和两套计算逻辑的痛点,美中不足的地方是队列可以保留的历史数据毕竟有限,难以做到无时间限制的回溯。分析到这里,我们沿着Kappa针对Lambda的改进思路,向前多思考一些:假如有一个存储引擎,既满足数据库可以高效的写入和随机查询,又能像队列服务,满足先进先出,是不是就可以把Lambda和Kappa架构揉合在一起,打造一个Lambda plus架构呢?新架构在Lambda的基础上可以提升以下几点: 在支持流计算和批计算的同时,让计算逻辑可以复用,实现“一套代码两类需求”。统一历史数据全量和在线实时增量数据的存储,实现“一份存储两类计算”。为了方便舆情结果查询需求,“batch view”和“real-time view”存储在既可以支持高吞吐的实时写入,也可以支持多字段组合搜索和全文检索。总结起来就是整套新架构的核心是解决存储的问题,以及如何灵活的对接计算。我们希望整套方案是类似下面的架构: 数据流实时写入一个分布式的数据库,借助于数据库查询能力,全量数据可以轻松的对接批量计算系统进行离线处理。数据库通过数据库日志接口,支持增量读取,实现对接流计算引擎进行实时计算。批计算和流计算的结果写回分布式数据库,分布式数据库提供丰富的查询语意,实现计算结果的交互式查询。整套架构中,存储层面通过结合数据库主表数据和数据库日志来取代大数据架构中的队列服务,计算系统选取天然支持批和流的计算引擎例如Flink或者Spark。这样一来,我们既可以像Lambda进行无限制的历史数据回溯,又可以像Kappa架构一样一套逻辑,存储处理两类计算任务。这样的一套架构我们取名为“Lambda plus”,下面就详细展开如何在阿里云上打造这样的一套大数据架构。 云上舆情系统架构在阿里云众多存储和计算产品中,贴合上述大数据架构的需求,我们选用两款产品来实现整套舆情大数据系统。存储层面使用阿里云自研的分布式多模型数据库Tablestore,计算层选用Blink来实现流批一体计算。 这套架构在存储层面,全部基于Tablestore,一个数据库解决不同存储需求,根据之前舆情系统的介绍,网页爬虫数据在系统流动中会有四个阶段分别是原始网页内容,网页结构化数据,分析规则元数据和舆情结果,舆情结果索引。我们利用Tablestore宽行和schema free的特性,合并原始网页和网页结构化数据成一张网页数据。网页数据表和计算系统通过Tablestore新功能通道服务进行对接。通道服务基于数据库日志,数据的组织结构按照数据的写入顺序进行存储,正是这一特性,赋能数据库具备了队列流式消费能力。使得存储引擎既可以具备数据库的随机访问,也可以具备队列的按照写入顺序访问,这也就满足我们上面提到整合Lambda和kappa架构的需求。分析规则元数据表由分析规则,情感词库组层,对应实时计算中的维表。计算系统这里选用阿里云实时流计算产品Blink,Blink是一款支持流计算和批计算一体的实时计算产品。并且类似Tablestore可以很容易的做到分布式水平扩展,让计算资源随着业务数据增长弹性扩容。使用Tablestore + Blink的优势有以下几点: Tablestore已经深度和Blink进行整合,支持源表,维表和目的表,业务无需为数据流动开发代码。整套架构大幅降低组建个数,从开源产品的6~7个组建减少到2个,Tablestore和Blink都是全托管0运维的产品,并且都能做到很好的水平弹性,业务峰值扩展无压力,使得大数据架构的运维成本大幅降低。业务方只需要关注数据的处理部分逻辑,和Tablestore的交互逻辑都已经集成在Blink中。开源方案中,如果数据库源希望对接实时计算,还需要双写一个队列,让流计算引擎消费队列中的数据。我们的架构中数据库既作为数据表,又是队列通道可以实时增量数据消费。大大简化了架构的开发和使用成本。流批一体,在舆情系统中实时性是至关重要的,所以我们需要一个实时计算引擎,而Blink除了实时计算以外,也支持批处理Tablestore的数据, 在业务低峰期,往往也需要批量处理一些数据并作为反馈结果写回Tablestore,例如情感分析反馈等。那么一套架构既可以支持流处理又可以支持批处理是再好不过。这里我们可以参考之前的一篇文章《实时计算最佳实践:基于表格存储和Blink的大数据实时计算》。一套架构带来的优势是,一套分析代码既可以做实时流计算又可以离线批处理。整个计算流程会产生实时的舆情计算结果。重大舆情事件的预警,通过Tablestore和函数计算触发器对接来实现。Tablestore和函数计算做了增量数据的无缝对接,通过结果表写入事件,可以轻松的通过函数计算触发短信或者邮件通知。完整的舆情分析结果和展示搜索利用了Tablestore的新功能多元索引,彻底解决了开源Hbase+Solr多引擎的痛点: 运维复杂,需要有运维hbase和solr两套系统的能力,同时还需要维护数据同步的链路。Solr数据一致性不如Hbase,在Hbase和Solr数据语意并不是完全一致,加上Solr/Elasticsearch在数据一致性很难做到像数据库那么严格。在一些极端情况下会出现数据不一致的问题,开源方案也很难做到跨系统的一致性比对。查询接口需要维护两套API,需要同时使用Hbase client和Solr client,索引中没有的字段需要主动反查Hbase,易用性较差。参考文献Lambda大数据架构Kappa大数据架构Lambda和Kappa架构对比总结本文基于《百亿级全网舆情分析系统存储设计》并结合Tablestore的新功能做了现代大数据舆情系统的架构升级,实现了海量信息下的实时舆情分析存储系统。也介绍了开源方案,并和我们的方案做了详细的对比。 本文作者:宇珩原文链接 本文为云栖社区原创内容,未经允许不得转载。

June 5, 2019 · 1 min · jiezi

爱豆在北京开演唱会我在杭州要如何与他实时互动

如果你的爱豆在北京举办演唱会,并做4K高清直播(服务器在上海),演唱会上专门为粉丝设置了一些互动环节,例如抽奖送签名照、答题送爱豆周边等。那么遍布在全国各地的观众该如何与他实时互动? 很显然,因为网速、带宽等问题限制,各地观众的网络时延会存在明显差异。如果你在新疆、西藏等偏远地区,很有可能当你看到爱豆提问的时候,实际上现场已经完成了抽奖,因此错失和“爱豆”互动的良机。 再来看另一个场景,如今互动课堂已经成为教育均衡化的利器,在5G的助推下将进一步发展。而同样因为学生广泛分布全国各地,这一场景对于低延时、高稳定、高保真也提出了更大的挑战。画质差、音画不同步、交互不能实时反馈、长链路传输无法避免的网络抖动等问题,都无法让学生产生亲临课堂的感受,授课效果也必然会大打折扣。 随着5G的到来,全面爆发的超高清和创新视频业务使得数据量会越来越大,这些数据都在终端形成、积累,传送到云端,进行数据处理,再返回到终端指导业务。这一系列动作将对网络带宽产生数百Gbps每秒的超高需求,不仅会存在延迟,还需要面临弱网卡顿、连接成功率低等诸多问题,用户体验无法保障。同时,大带宽对回传网络、业务中心造成巨大传输压力,也会让企业面临着巨额的带宽成本。这意味着集中式的数据存储、处理模式将面临难解的瓶颈和压力。 而在引入边缘计算后,视频业务将大量业务在网络边缘终结,性能和带宽的瓶颈将得以突破。利用关键业务应用的下沉,边缘计算将大幅减少网络传输和多级转发带来的带宽与时延损耗,同时在边缘侧进行本地数据的初步分析和处理,可以承担部分“云“的工作,减轻云中心的压力和传输成本。 我们以开头的演唱会直播为例,来说明下它的逻辑。身在北京的主播媒体流会推到就近的边缘节点,在边缘节点直接进行转码,转码后的媒体流会分发到CDN边缘节点,当有用户访问时直接就近返回内容。基于边缘节点上的服务,直播流的上下行内容推送以及转码处理等都不用再回到位于上海的业务调度中心,大大降低了业务时延,身在杭州的粉丝的互动体验得到提升,同时边缘处理架构对带宽成本的节省也非常明显。 早在2016年,边缘计算开始被业界普遍提及,发展至今,已经有多家电信运营商、云计算厂商、CDN厂商和众多行业先行者开始布局与实践。这其中就包括虎牙直播和阿里云。 二者在直播领域进行了长期的技术合作,特别是在边缘计算节点上的合作取得了令人瞩目的效果,2018年10月英雄联盟总决赛期间,虎牙直播结合阿里云边缘节点(ENS)技术方案,保障了总决赛在线人气超过7000万超高流量的挑战,有效满足了用户对低延时、稳定性以及实时互动等方面的要求,在画面传输方面与同类型直播网站相比快将近10秒,用户能够第一时间看到最及时不卡顿的比赛画面。 正是因为坚定而深入的拥抱边缘,虎牙直播在获得网络低时延的同时,也减少了中心的压力,节省了30%以上的中心带宽成本,并且实现了边缘节点网络连接小于5毫秒延时,提升了主播上行质量和用户观看体验。 为什么不自建边缘数据中心?边缘计算对于实时性的优化已经十分明确,那么为什么虎牙直播要选择与云厂商合作,而非自建边缘数据中心呢? 据了解,在没有与云厂商合作之前,虎牙直播应对大型赛事活动,需自建边缘节点,而自建边缘节点交付效率和成本均不具备优势。为了更弹性地启用业务,选择拥抱云厂商不失为一条快速走向成功的捷径。 不止是弹性,自建节点还需要面临运维难度大、安全可靠性的考验以及高昂的启动成本。 首先,在运维方面,自建边缘节点的运维需要从建设、交付到运行的整个流程管理起来,其次要管理边缘节点内物理服务器层面、操作系统层面、以及软件应用层面的运维问题,出现问题时要有一组工具帮助远程查看日志和问题排查定位,这些对运维的自动化和白屏化提出了很高的要求。 其次,通常自建边缘节点基础环境的可靠性是依赖第三方运营商的服务,业务方需要及时对可能面临的软硬件故障进行及时的发现的调度,对业务架构的开发提出较高要求。同时,想要对网络流量安全、主机安全等问题进行提前防护,可能需要在每个边缘节点都部署一套软件加硬件的系统方案,开发成本非常高。 最后,自建基础设施意味着从商务采购、服务器采购、供应链管理、到节点建设都要企业自行解决,会带来资产投入过重与成本过高的问题。 由此可见,自建边缘节点的弊端十分明显。这也就是越来越多的企业选择第三方边缘计算服务提供商合作的原因。 云边端三体协同的网络架构会成为最终形态如今有了边缘计算,我们是否还需要云计算?答案必然是一定的。阿里云边缘计算技术负责人杨敬宇就曾表示过:这二者并不是此消彼长的关系,应是天然互补的关系,边缘计算正在拓展云计算的边界。在云和端的取舍要对两者的算力、电力以及传输多方成本做综合考量。 以文章开始讲述的互动直播场景为例,大量的交互使数据量激增,需要准确、快速的计算。如果在端上进行视频计算,会大量消耗端的算力,对端的性能要求很高且耗电量很大,但是拿到云上,又面临高昂的传输成本。 这时,云边端三体协同的架构将发挥重要作用。5G时代,终端算力上移、云端算力下沉,将在边缘形成算力融合,企业能够根据自己行业的特点和优势,在边缘计算领域建立一套新的生态系统。 在2018年12月,中国电子技术标准化研究院联合阿里云,共同编制并发布了一份《边缘云计算技术与标准化白皮书》,在业界首次定义了边缘云计算的概念和标准。边缘云计算是基于云计算技术的核心和边缘计算的能力,构筑在边缘基础设施之上的云计算平台。形成边缘位置的计算、网络、存储、安全等能力全面的弹性云平台,并与中心云和物联网终端形成“云边端三体协同”的端到端的技术架构,通过将网络转发、存储、计算,智能化数据分析等工作放在边缘处理,降低响应时延、减轻云端压力、降低带宽成本,并供全网调度、算力分发等云服务。 杨敬宇认为:原来的云如果只服务云端二体结构,没有边缘计算去做支撑的时候,就像三级跳一样没有一个支点,让终端直接上云,那么云很难支撑产业互联网的需求。云为了扩大自己的服务范围和服务能力,就一定要往边缘做。 一时之间,运营商、传统CDN厂商、云服务厂商、硬件和芯片厂商运营商纷纷加入阵营,基于各自行业背景和优势,推动产业良性发展。阿里云也率先在行业释放了云边端三体协同的产品红利,赋能产业应用。云自然不必说,其中“边”就是上文提到的边缘节点服务(ENS),以解决直播等行业“高带宽、高并发、计算密集”的业务需求。而“端”则是阿里云IoT边缘计算产品Link IoT Edge,用于解决万物的标准化接入问题,是连接最后1公里的物联网边缘计算平台,支持包括函数计算、流式计算、规则计算等计算引擎,还可以和超过10种以上云服务建立连接和协同。 未来可期:边缘计算会成为大视频领域发展的助推器回到大视频领域,边缘计算解决了低时延、大带宽的业务诉求,同时因为底层复杂的基础设施和网络环境已经被平台方封装,业务方不需关心底层设施和环境的各种差异,也不需关心底层运维问题。 阿里云在边缘计算领域具备先发优势,同时结合阿里集团丰富的生态场景,通过边缘计算的平台能力,边缘节点服务也陆续为各类垂直应用提供功能和解决方案,包括视频监控、AI能力、视频处理能力、实时计算、IoT接入等。 如此开放标准、可定义、可调度的边缘计算服务,定会在5G时代助推更丰富、更创新的视频形态到来。 当然,除了本文详述的互联网音视频场景,在线教育、游戏直播、视频监控也是大视频领域备受瞩目的业务场景之一。后续云栖公众号会持续带来边缘计算如何赋能各个产业,协同阿里云产品,打造完整行业解决方案,敬请期待。 本文作者:樰篱 原文链接 本文为云栖社区原创内容,未经允许不得转载。

June 5, 2019 · 1 min · jiezi

TableStore-海量结构化数据分层存储方案

前言表格存储是阿里云自研分布式存储系统,可以用来存储海量结构化、半结构化的数据。表格存储支持高性能和容量型两种实例类型。高性能使用SSD的存储介质,针对读多写多的场景都有较好的访问延时。容量型使用的是SSD和SATA混合的存储介质。对写多的场景,性能接近高性能,读方面,如果遇到冷数据产生读SATA盘的话,延时会比高性能上涨一个量级。在海量数据存储场景下,例如时序场景,我们会希望最新的数据可以支持高性能查询,较早的数据的读写频次都会低很多。这时候一个基于表格存储高性能和容量型存储分层的需求就产生了。 方案细节表格存储近期对外正式发布的全增量一体的通道服务(参考文档),通道服务基于表格存储数据接口之上的全增量一体化服务。通道服务为用户提供了增量、全量、增量加全量三种类型的分布式数据实时消费通道。有了通道服务,我们可以很方便的构建从高性能实例下的表到容量型表之间的实时数据同步,进而可以在高性能表上使用表格存储的特性数据生命周期(参考文档),根据业务需求设置一个合理的TTL。总体来说就可以构建一个如下图所示的架构: 整个数据的流动过程如下: 业务写入端直接写入高性能实例高性能实例中的数据通过通道服务同步至容量型高性能实例中的老数据自动过期,减少存储量占用用户查询请求根据时序查询条件,判断是否是近期数据 近期数据查询进入高性能,毫秒级别返回较早数据查询进入容量型,几十毫秒后返回代码和操作流程:在高性能实例上根据业务主键需求创建数据表,并设置合理的数据TTL,然后在容量型下创建相同的schema的表用来持久化存储所有数据。 然后在通道页面创建一个全增量类型的通道: 通过控制台可以简单清晰的查看到同步的状态,并发,进度等信息: 下面贴一下通过Tunnel进行复制同样schema表TableStore表的Sample代码: func main () { //高性能实例的信息 tunnelClient := tunnel.NewTunnelClient("", "", "", "") //容量型实例的信息 client := tablestore.NewClient("", "", "", "") //配置callback到SimpleProcessFactory,配置消费端TunnelWorkerConfig workConfig := &tunnel.TunnelWorkerConfig{ ProcessorFactory: &tunnel.SimpleProcessFactory{ ProcessFunc: replicateDataFunc, CustomValue: client, }, } //使用TunnelDaemon持续消费指定tunnel daemon := tunnel.NewTunnelDaemon(tunnelClient, "", workConfig) err := daemon.Run() if err != nil { fmt.Println("failed to start tunnel daemon with error:", err) }}func replicateDataFunc(ctx *tunnel.ChannelContext, records []*tunnel.Record) error { client := ctx.CustomValue.(*tablestore.TableStoreClient) fmt.Println(client) for _, rec := range records { fmt.Println("tunnel record detail:", rec.String()) updateRowRequest := new(tablestore.UpdateRowRequest) updateRowRequest.UpdateRowChange = new(tablestore.UpdateRowChange) updateRowRequest.UpdateRowChange.TableName = "coldtable" updateRowRequest.UpdateRowChange.PrimaryKey = new(tablestore.PrimaryKey) updateRowRequest.UpdateRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE) for _, pk := range rec.PrimaryKey.PrimaryKeys { updateRowRequest.UpdateRowChange.PrimaryKey.AddPrimaryKeyColumn(pk.ColumnName, pk.Value) } for _, col := range rec.Columns { if col.Type == tunnel.RCT_Put { updateRowRequest.UpdateRowChange.PutColumn(*col.Name, col.Value) } else if col.Type == tunnel.RCT_DeleteOneVersion { updateRowRequest.UpdateRowChange.DeleteColumnWithTimestamp(*col.Name, *col.Timestamp) } else { updateRowRequest.UpdateRowChange.DeleteColumn(*col.Name) } } _, err := client.UpdateRow(updateRowRequest) if err != nil { fmt.Println("hit error when put record to cold data", err) } } fmt.Println("a round of records consumption finished") return nil}总结通过通道服务,存储在表格存储中的结构化,半结构化数据可以实时流出,进行加工,萃取,计算或进行同步。如果是想进一步降低冷数据的存储成本,可以参考这篇文章把表格存储的数据备份到OSS归档存储。 ...

June 5, 2019 · 1 min · jiezi

势高则围广TiDB-的架构演进哲学

本文来源 | PingCAP微信公众号作者 | PingCAP CEO刘奇,本文根据他在第 100 期 Infra Meetup 上的演讲整理,预计阅读时间为 30 分钟,建议先收藏。 大家可能知道我是 PingCAP CEO,但是不知道的是,我也是 PingCAP 的产品经理,应该也是最大的产品经理,是对于产品重大特性具有一票否决权的人。中国有一类产品经理是这样的,别人有的功能我们统统都要有,别人没有的功能,我们也统统都要有,所以大家看到传统的国内好多产品就是一个超级巨无霸,功能巨多、巨难用。所以我在 PingCAP 的一个重要职责是排除掉“看起来应该需要但实际上不需要”的那些功能,保证我们的产品足够的专注、足够聚焦,同时又具有足够的弹性。 01最初的三个基本信念 本次分享题目是《TiDB 的架构演进哲学》,既然讲哲学那肯定有故事和教训,否则哲学从哪儿来呢?但从另外的角度来说,一般大家来讲哲学就先得有信念。有一个内容特别扯的美剧叫做《美国众神》,里面核心的一条思路是“你相信什么你就是什么”。其实人类这么多年来,基本上也是朝这条线路在走的,人类对于未知的东西很难做一个很精确的推导,这时信念就变得非常重要了。 图 1 最初的基本信念 实际上,我们开始做 TiDB 这个产品的时候,第一个信念就是相信云是未来。当年 K8s 还没火,我们就坚定的拥抱了 K8s。第二是不依赖特定硬件、特定的云厂商,也就是说 TiDB 的设计方向是希望可以 Run 在所有环境上面,包括公有云私有云等等。第三是能支持多种硬件,大家都知道我们支持 X86、AMD64、ARM 等等,可能大家不清楚的是 MIPS,MIPS 典型代表是龙芯,除此之外,TiDB 未来还可以在 GPU 上跑(TiFlash 的后续工作会支持 GPU)。 02早期用户故事 1、Make it work 有一句话大概是“眼睛里面写满了故事,脸上没有一点沧桑”,其实现实是残酷的,岁月一定会给你沧桑的。我们早期的时候,也有相对比较难的时候,这时候就有一些故事关于我们怎么去经历、怎么渡过的。 首先大家做产品之前肯定先做用户调研,这是通用的流程,我们当初也做过这个事,跟用户聊。我们通常会说:“我们要做一个分布式数据库,自动弹性伸缩,能解决分库分表的问题,你会用吗?”用户说“那肯定啊,现在的分库分表太痛苦了。”这是最初我们获取需求最普通的方式,也是我们最容易掉入陷阱的方式,就好像“我有一百万,你要不要?肯定要。”“我有一瓶水,喝了之后就健康无比,延年益寿你要不要?肯定要。”很容易就得到类似的结论。 所以这个一句话结论的代价是我们进行了长达两年的开发。在这两年的时间里,我们确定了很多的技术方向,比如最初 TiDB 就决定是分层的。很显然一个复杂的系统如果没有分层,基本上没有办法很好的控制规模和复杂度。TiDB 分两层,一层是 SQL 层,一层是 key-value 层,那么到底先从哪一个层开始写呢?其实从哪层开始都可以,但是总要有一个先后,如何选择? 这里就涉及到 TiDB 的第一条哲学。我们做一个产品的时候会不断面临选择,那每次选择的时候核心指导思想是什么?核心思想是能一直指导我们持续往前去迭代,所以我们第一条哲学就是:永远站在离用户更近的地方去考虑问题。 为什么我们会定义这样一条哲学?因为离用户越近越能更快的得到用户的反馈,更快的验证你的想法是不是可行的。显然 SQL 层离用户更近,所以我们选择从 SQL 层写起。其实一直到现在,绝大多数用户用 TiDB 的时候根本感受不到 KV 层的存在,用户写的都是 SQL,至于底层存储引擎换成了别的,或者底层的 RocksDB 做了很多优化和改进,这些变化对于用户关注的接口来说是不可见的。 ...

June 4, 2019 · 4 min · jiezi

不改代码也能全面-Serverless-化阿里中间件如何破解这一难题

阿里妹导读:Serverless 话题涉及范围极广,几乎包含了代码管理、测试、发布、运维和扩容等与应用生命周期关联的所有环节。在线应用如何不改代码也能迁移到 Serverless 架构?今天,我们来揭秘阿里巴巴成千上万在线应用的Serverless 演进过程。AWS Lambda 是 Serverless 领域的标志性产品,但如果将其应用于核心业务,可能会遇到以下难题:(仅代表作者个人观点) 要求用户以 Function 为单位进行开发,全新的开发框架,云厂商强绑定,社区主流技术栈迁移成本高;Function 启动速度要足够快,毫秒级或者秒级,这个限制对适用场景有很强的约束;Function 之间的调用通过 API Gateway,响应时间更长。Cloud Service Engine 云服务引擎(以下简称CSE),是阿里云中间件团队开发的面向通用 Serverless 计算的中间件产品,目的是具备 AWS Lambda 的各种优势,同时可以解决用户在使用 AWS Lambda 时遇到的难题。 什么是 Serverless?AWS 对 Serverless 定义是:(摘自 AWS 官网) AWS 无服务器平台提供的功能:(摘自 AWS 官网) AWS 的整套 Serverless 方案非常完善,但是没有解决存量应用如何迁移到 Serverless 架构的问题。仅仅是针对新开发的应用,建议用户使用 FaaS 方式开发,才有机会转向 Serverless 架构。笔者认为,要将 Serverless 架构大规模推广,必须要能有针对存量业务的解决方案。 Serverless 对云计算的价值云计算,归根结底是一种 IT 服务提供模式,不论是公共云还是专有云(以 IT 设备的归属不同分类),其本质都是帮助 IT 的最终使用者随时随地,并且简便快速地,获取 IT 服务,目前,IaaS、PaaS 都已经做到了按需付费,PaaS 甚至做到了按请求付费,如 DB,CACHE,MQ 等,但是 IaaS 的付费粒度仍然是时间维度,最快按照小时付费,以分钟来交付。 ...

June 4, 2019 · 2 min · jiezi

蚂蚁金服首席架构师何昌华开源SQLFlow是牛刀初试实时大数据系统才是未来基石

开源 SQLFlow,反哺业界,同时小小秀出 AI 肌肉。 这就是蚂蚁金服近日开源首个将 SQL 应用于 AI 引擎项目 SQLFlow 后,业界给出的反应。 SQLFlow,把艰深的 AI 与简单的 SQL 结合起来,大大简化了数据工程师使用 AI 技术的门槛。 而研发出 SQLFlow 的,正是蚂蚁金服计算存储首席架构师何昌华带领下的 AI Infra 团队。 何昌华斯坦福博士毕业,先在 Google 总部工作 7 年,赢得过公司最高技术奖项,其后又在独角兽 Airbnb 工作 2 年,负责后台系统的应用架构。 2017 年 5 月,他正式加盟蚂蚁金服,担任计算存储首席架构师,并在 2018 年入选了第 14 批国家“千人计划”专家。 在蚂蚁金服,何昌华的工作是开发新一代计算引擎,搭建金融型数据智能平台。 而 SQLFlow,就是计算引擎主线上的结晶之一。 不过对何昌华来说,世界正在巨变,他还要带队探索一些没人做成的事情。 比如全实时的大数据智能系统。 未来技术基石大数据的概念,最早来自于搜索引擎行业,因为搜索引擎面对的是人类在互联网上留下的爆炸性增长的庞大数据。 2010 年底,谷歌宣布新一代搜索引擎“咖啡因”正式上线,这项技术的革命性在于,任何时刻,世界上的任何网页发生了变化,都可以实时地添加到索引中,用户也可以实时地搜索到,解决了传统搜索引擎的延时问题。 何昌华当时正是咖啡因开发团队的核心技术负责人之一。 他解释,“咖啡因所实现的最核心的功能,就是实时。” 而现在何昌华在蚂蚁金服工作的目标,同样是搭建一个“完全实时”的大数据处理系统,或称之为大数据智能平台。由于线下生活场景的多样性和复杂性,这是个比构建实时搜索更有挑战性的任务。 他认为,这将成为未来技术的基石。 对于计算机来说,实时就是在发出请求到返回响应之间的延迟尽量小,对于大数据处理系统来说,这还意味着从数据生产到消费的延迟尽可能低,所有这些都意味着计算速度和能力的提升。 此前常用的大数据计算模型 MapReduce,对数据的处理是“分片式”的,数据的片与片之间有边界的概念,这种批处理的模式不可避免地会带来延时问题。 以搜索的场景为例,假如以天为时间单位对数据进行批处理,那就意味着今天更新的网页,用户明天才能搜索到,调高处理的频率可以部分解决问题,一天两次、一天四次、两小时一次…… 虽然能逐步接近“准实时”,但成本也会急剧上升。 要实现真正的实时,就必须打破这种批处理的边界,让数据处理的过程像水流一样,随来随算,随时反馈。 这也催生了后来流式计算引擎的蓬勃发展。 而在何昌华看来,除了快,“实时系统”还有两层重要含义。 第一是 OLTP(联机事务处理)和 OLAP(联机分析处理)的融合。 在以往的观念里,OLTP 对实时性的要求高,OLAP 对时效性的要求不那么高。 ...

June 4, 2019 · 1 min · jiezi

基于大数据的舆情分析系统架构-架构篇

前言互联网的飞速发展促进了很多新媒体的发展,不论是知名的大V,明星还是围观群众都可以通过手机在微博,朋友圈或者点评网站上发表状态,分享自己的所见所想,使得“人人都有了麦克风”。不论是热点新闻还是娱乐八卦,传播速度远超我们的想象。可以在短短数分钟内,有数万计转发,数百万的阅读。如此海量的信息可以得到爆炸式的传播,如何能够实时的把握民情并作出对应的处理对很多企业来说都是至关重要的。大数据时代,除了媒体信息以外,商品在各类电商平台的订单量,用户的购买评论也都对后续的消费者产生很大的影响。商家的产品设计者需要汇总统计和分析各类平台的数据做为依据,决定后续的产品发展,公司的公关和市场部门也需要根据舆情作出相应的及时处理,而这一切也意味着传统的舆情系统升级成为大数据舆情采集和分析系统。分析完舆情场景后,我们再来具体细化看下大数据舆情系统,对我们的数据存储和计算系统提出哪些需求: 海量原始数据的实时入库:为了实现一整套舆情系统,需要有上游原始输出的采集,也就是爬虫系统。爬虫需要采集各类门户,自媒体的网页内容。在抓取前需要去重,抓取后还需要分析提取,例如进行子网页的抓取。原始网页数据的处理:不论是主流门户还是自媒体的网页信息,抓取后我们需要做一定的数据提取,把原始的网页内容转化为结构化数据,例如文章的标题,摘要等,如果是商品点评类消息也需要提取有效的点评。结构化数据的舆情分析:当各类原始输出变成结构化的数据后,我们需要有一个实时的计算产品把各类输出做合理的分类,进一步对分类后的内容进行情感打标。根据业务的需求这里可能会产生不同的输出,例如品牌当下是否有热点话题,舆情影响力分析,转播路径分析,参与用户统计和画像,舆论情感分析或者是否有重大预警。舆情分析系统中间和结果数据的存储,交互分析查询:从网页原始数据清洗到最终的舆情报表这中间会产生很多类型的数据。这些数据有的会提供给数据分析同学进行舆情分析系统的调优,有的数据会提供给业务部门根据舆情结果进行决策。这些查询可能会很灵活,需要我们的存储系统具备全文检索,多字段组合灵活的交互分析能力。重大舆情事件的实时预警:对于舆情的结果除了正常的搜索和展示需求以外,当有重大事件出现我们需要能做到实时的预警。我们计划分两篇介绍完整的舆情新架构,第一篇主要是提供架构设计,会先介绍时下主流的大数据计算架构,并分析一些优缺点,然后引入舆情大数据架构。第二篇会有完整的数据库表设计和部分示例代码。大家敬请期待。 系统设计需求分析 结合文章开头对舆情系统的描述,海量大数据舆情分析系统流程图大体如下: 原始网页存储库,这个库需要能支持海量数据,低成本,低延时写入。网页数据写入后,要做实时结构化提取,提取出来的数据再进行降噪,分词,图片ocr处理等。对分词文本,图片进行情感识别产生舆情数据结果集。传统的离线全量计算很难满足舆情系统的时效性需求。计算引擎在做数据处理时,可能还需要从存储库中获取一些元数据,例如用户信息,情感词元数据信息等。除了实时的计算链路,对存量数据定期要做一些聚类,优化我们的情感词识别库,或者上游根据业务需要触发情感处理规则更新,根据新的情感打标库对存量数据做一次舆情计算。舆情的结果数据集有不同类的使用需求。对于重大舆情,需要做实时的预警。完整的舆情结果数据展示层需要支持全文检索,灵活的属性字段组合查询。业务上可能根据属性字段中的置信度,舆情时间,或者关键词组合进行分析。根据前面的介绍,舆情大数据分析系统需要两类计算,一类是实时计算包括海量网页内容实时抽取,情感词分析并进行网页舆情结果存储。另一类是离线计算,系统需要对历史数据进行回溯,结合人工标注等方式优化情感词库,对一些实时计算的结果进行矫正等。所以在系统设计上,需要选择一套既可以做实时计算又能做批量离线计算的系统。在开源大数据解决方案中,Lambda架构恰好可以满足这些需求,下面我们来介绍下Lambda的架构。 Lambda架构 (wiki) Lambda架构可以说是Hadoop,Spark体系下最火的大数据架构。这套架构的最大优势就是在支持海量数据批量计算处理(也就是离线处理)同时也支持流式的实时处理(即热数据处理)。具体是如何实现的呢,首先上游一般是一个队列服务例如kafka,实时存储数据的写入。kafka队列会有两个订阅者,一个是全量数据即图片中上半部分,全量数据会被存储在类似HDFS这样的存储介质上。当有离线计算任务到来,计算资源(例如Hadoop)会访问存储系统上的全量数据,进行全量批计算的处理逻辑。经过map/reduce环节后全量的结果会被写入一个结构化的存储引擎例如Hbase中,提供给业务方查询。队列的另一个消费订阅方是流计算引擎,流计算引擎往往会实时的消费队列中的数据进行计算处理,例如Spark Streaming实时订阅Kafka的数据,流计算结果也会写入一个结构化数据引擎。批量计算和流计算的结果写入的结构化存储引擎即上图标注3的"Serving Layer",这一层主要提供结果数据的展示和查询。在这套架构中,批量计算的特点是需要支持处理海量的数据,并根据业务的需求,关联一些其他业务指标进行计算。批量计算的好处是计算逻辑可以根据业务需求灵活调整,同时计算结果可以反复重算,同样的计算逻辑多次计算结果不会改变。批量计算的缺点是计算周期相对较长,很难满足实时出结果的需求,所以随着大数据计算的演进,提出了实时计算的需求。实时计算在Lambda架构中是通过实时数据流来实现,相比批处理,数据增量流的处理方式决定了数据往往是最近新产生的数据,也就是热数据。正因为热数据这一特点,流计算可以满足业务对计算的低延时需求,例如在舆情分析系统中,我们往往希望舆情信息可以在网页抓取下来后,分钟级别拿到计算结果,给业务方充足的时间进行舆情反馈。下面我们就来具体看一下,基于Lambda架构的思想如何实现一套完整的舆情大数据架构。 开源舆情大数据方案通过这个流程图,让我们了解了整个舆情系统的建设过程中,需要经过不同的存储和计算系统。对数据的组织和查询有不同的需求。在业界基于开源的大数据系统并结合Lambda架构,整套系统可以设计如下: 系统的最上游是分布式的爬虫引擎,根据抓取任务抓取订阅的网页原文内容。爬虫会把抓取到的网页内容实时写入Kafka队列,进入Kafka队列的数据根据前面描述的计算需求,会实时流入流计算引擎(例如Spark或者Flink),也会持久化存储在Hbase,进行全量数据的存储。全量网页的存储可以满足网页爬取去重,批量离线计算的需求。流计算会对原始网页进行结构化提取,将非结构化网页内容转化为结构数据并进行分词,例如提取出网页的标题,作者,摘要等,对正文和摘要内容进行分词。提取和分词结果会写回Hbase。结构化提取和分词后,流计算引擎会结合情感词库进行网页情感分析,判断是否有舆情产生。流计算引擎分析的舆情结果存储Mysql或者Hbase数据库中,为了方便结果集的搜索查看,需要把数据同步到一个搜索引擎例如Elasticsearch,方便进行属性字段的组合查询。如果是重大的舆情时间,需要写入Kafka队列触发舆情报警。全量的结构化数据会定期通过Spark系统进行离线计算,更新情感词库或者接受新的计算策略重新计算历史数据修正实时计算的结果。开源架构分析上面的舆情大数据架构,通过Kafka对接流计算,Hbase对接批计算来实现Lambda架构中的“batch view”和“real-time view”,整套架构还是比较清晰的,可以很好的满足在线和离线两类计算需求。但是把这一套系统应用在生产并不是一件容易的事情,主要有下面一些原因。 整套架构涉及到非常多的存储和计算系统包括:Kafka,Hbase,Spark,Flink,Elasticsearch。数据会在不同的存储和计算系统中流动,运维好整套架构中的每一个开源产品都是一个很大的挑战。任何一个产品或者是产品间的通道出现故障,对整个舆情分析结果的时效性都会产生影响。为了实现批计算和流计算,原始的网页需要分别存储在Kafka和Hbase中,离线计算是消费hbase中的数据,流计算消费Kafka的数据,这样会带来存储资源的冗余,同时也导致需要维护两套计算逻辑,计算代码开发和维护成本也会上升。舆情的计算结果存储在Mysql或者Hbase,为了丰富组合查询语句,需要把数据同步构建到Elasticsearch中。查询的时候可能需要组合Mysql和Elasticsearch的查询结果。这里没有跳过数据库,直接把结果数据写入Elasticsearch这类搜索系统,是因为搜索系统的数据实时写入能力和数据可靠性不如数据库,业界通常是把数据库和搜索系统整合,整合下的系统兼备了数据库和搜索系统的优势,但是两个引擎之间数据的同步和跨系统查询对运维和开发带来很多额外的成本。新的大数据架构Lambda plus通过前面的分析,相信大家都会有一个疑问,有没有简化的的大数据架构,在可以满足Lambda对计算需求的假设,又能减少存储计算以及模块的个数呢。Linkedin的Jay Kreps提出了Kappa架构,关于Lambda和Kappa的对比可以参考"云上大数据方案"这篇,这里不展开详细对比,简单说下,Kappa为了简化两份存储,取消了全量的数据存储库,通过在Kafka保留更长日志,当有回溯重新计算需求到来时,重新从队列的头部开始订阅数据,再一次用流的方式处理Kafka队列中保存的所有数据。这样设计的好处是解决了需要维护两份存储和两套计算逻辑的痛点,美中不足的地方是队列可以保留的历史数据毕竟有限,难以做到无时间限制的回溯。分析到这里,我们沿着Kappa针对Lambda的改进思路,向前多思考一些:假如有一个存储引擎,既满足数据库可以高效的写入和随机查询,又能像队列服务,满足先进先出,是不是就可以把Lambda和Kappa架构揉合在一起,打造一个Lambda plus架构呢?新架构在Lambda的基础上可以提升以下几点: 在支持流计算和批计算的同时,让计算逻辑可以复用,实现“一套代码两类需求”。统一历史数据全量和在线实时增量数据的存储,实现“一份存储两类计算”。为了方便舆情结果查询需求,“batch view”和“real-time view”存储在既可以支持高吞吐的实时写入,也可以支持多字段组合搜索和全文检索。总结起来就是整套新架构的核心是解决存储的问题,以及如何灵活的对接计算。我们希望整套方案是类似下面的架构: 数据流实时写入一个分布式的数据库,借助于数据库查询能力,全量数据可以轻松的对接批量计算系统进行离线处理。数据库通过数据库日志接口,支持增量读取,实现对接流计算引擎进行实时计算。批计算和流计算的结果写回分布式数据库,分布式数据库提供丰富的查询语意,实现计算结果的交互式查询。整套架构中,存储层面通过结合数据库主表数据和数据库日志来取代大数据架构中的队列服务,计算系统选取天然支持批和流的计算引擎例如Flink或者Spark。这样一来,我们既可以像Lambda进行无限制的历史数据回溯,又可以像Kappa架构一样一套逻辑,存储处理两类计算任务。这样的一套架构我们取名为“Lambda plus”,下面就详细展开如何在阿里云上打造这样的一套大数据架构。 云上舆情系统架构在阿里云众多存储和计算产品中,贴合上述大数据架构的需求,我们选用两款产品来实现整套舆情大数据系统。存储层面使用阿里云自研的分布式多模型数据库Tablestore,计算层选用Blink来实现流批一体计算。 这套架构在存储层面,全部基于Tablestore,一个数据库解决不同存储需求,根据之前舆情系统的介绍,网页爬虫数据在系统流动中会有四个阶段分别是原始网页内容,网页结构化数据,分析规则元数据和舆情结果,舆情结果索引。我们利用Tablestore宽行和schema free的特性,合并原始网页和网页结构化数据成一张网页数据。网页数据表和计算系统通过Tablestore新功能通道服务进行对接。通道服务基于数据库日志,数据的组织结构按照数据的写入顺序进行存储,正是这一特性,赋能数据库具备了队列流式消费能力。使得存储引擎既可以具备数据库的随机访问,也可以具备队列的按照写入顺序访问,这也就满足我们上面提到整合Lambda和kappa架构的需求。分析规则元数据表由分析规则,情感词库组层,对应实时计算中的维表。计算系统这里选用阿里云实时流计算产品Blink,Blink是一款支持流计算和批计算一体的实时计算产品。并且类似Tablestore可以很容易的做到分布式水平扩展,让计算资源随着业务数据增长弹性扩容。使用Tablestore + Blink的优势有以下几点: Tablestore已经深度和Blink进行整合,支持源表,维表和目的表,业务无需为数据流动开发代码。整套架构大幅降低组建个数,从开源产品的6~7个组建减少到2个,Tablestore和Blink都是全托管0运维的产品,并且都能做到很好的水平弹性,业务峰值扩展无压力,使得大数据架构的运维成本大幅降低。业务方只需要关注数据的处理部分逻辑,和Tablestore的交互逻辑都已经集成在Blink中。开源方案中,如果数据库源希望对接实时计算,还需要双写一个队列,让流计算引擎消费队列中的数据。我们的架构中数据库既作为数据表,又是队列通道可以实时增量数据消费。大大简化了架构的开发和使用成本。流批一体,在舆情系统中实时性是至关重要的,所以我们需要一个实时计算引擎,而Blink除了实时计算以外,也支持批处理Tablestore的数据, 在业务低峰期,往往也需要批量处理一些数据并作为反馈结果写回Tablestore,例如情感分析反馈等。那么一套架构既可以支持流处理又可以支持批处理是再好不过。这里我们可以参考之前的一篇文章《实时计算最佳实践:基于表格存储和Blink的大数据实时计算》。一套架构带来的优势是,一套分析代码既可以做实时流计算又可以离线批处理。整个计算流程会产生实时的舆情计算结果。重大舆情事件的预警,通过Tablestore和函数计算触发器对接来实现。Tablestore和函数计算做了增量数据的无缝对接,通过结果表写入事件,可以轻松的通过函数计算触发短信或者邮件通知。完整的舆情分析结果和展示搜索利用了Tablestore的新功能多元索引,彻底解决了开源Hbase+Solr多引擎的痛点: 运维复杂,需要有运维hbase和solr两套系统的能力,同时还需要维护数据同步的链路。Solr数据一致性不如Hbase,在Hbase和Solr数据语意并不是完全一致,加上Solr/Elasticsearch在数据一致性很难做到像数据库那么严格。在一些极端情况下会出现数据不一致的问题,开源方案也很难做到跨系统的一致性比对。查询接口需要维护两套API,需要同时使用Hbase client和Solr client,索引中没有的字段需要主动反查Hbase,易用性较差。参考文献Lambda大数据架构Kappa大数据架构Lambda和Kappa架构对比总结本文基于《百亿级全网舆情分析系统存储设计》并结合Tablestore的新功能做了现代大数据舆情系统的架构升级,实现了海量信息下的实时舆情分析存储系统。也介绍了开源方案,并和我们的方案做了详细的对比。 本文作者:宇珩阅读原文 本文为云栖社区原创内容,未经允许不得转载。

June 3, 2019 · 1 min · jiezi

大盘点-KubeCon-EU-2019-应用管理领域的新看点

摘要: KubeCon EU 2019 刚刚在巴塞罗那拉下帷幕,来自阿里巴巴经济体的讲师团,在大会上分享了互联网场景下规模化 Kubernetes 集群的各项落地经验和教训。所谓“独行速而众行远”,从不断发展壮大的社区中,我们看到越来越多的人拥抱开源,往标准演进,搭上了这趟开往云原生的高速列车。众所周知,云原生架构的中心项目是 Kubernetes,而 Kubernetes 则围绕着“应用”来展开。让应用部署得更好,让开发者更高效,才能给团队和组织带来切实的利益,才能让云原生技术变革发挥更大的作用。变革的势头既如洪水般吞没着老旧封闭的内部系统,又如春雨般孕育出更多的新开发者工具。在本次 KubeCon 中,就出现了许多有关应用管理与部署的新知识。这些知识中有哪些想法和思路值得借鉴,让我们少走弯路?在它们背后,又预示着什么样的技术演进方向? 在本文中,我们邀请到了阿里云容器平台技术专家、原 CoreOS 公司工程师、 K8s Operator 项目的核心作者之一邓洪超,为读者精选了此次会议“应用管理”领域的精华内容来一一进行分析与点评。 The Config ChangedKubernetes 上部署的应用一般会把配置存放到 ConfigMap 里,然后挂载到 Pod 文件系统中去。当 ConfigMap 发生更改时,只有 Pod 里挂载的文件会被自动更新。这种做法对某些会自动做热更新的应用(比如 nginx)来说是 OK 的。但是,对于大多数应用开发者来说,他们更倾向于认为更改配置要做一次新的灰度发布、跟 ConfigMap 相关联的容器应该做一次灰度升级。 灰度升级不仅简化了用户代码,增强了安全稳定性,更是体现了不可变基础架构的思想。应用一旦部署,就不再做变更。需要升级时,只要部署一个新版系统,验证 OK 后再摧毁旧版就好了;验证不通过时也容易回滚到旧版。正是基于这样的思路,来自 Pusher 的工程师们研发了 Wave,一款自动监听 Deployment 相关联的 ConfigMap/Secret 并随之改动而触发 Deployment 升级的工具。这款工具的独特之处在于它会自动搜索该 Deployment PodTemplate 里面的 ConfigMap/Secret,然后把里面所有数据计算一次 hash 放到 PodTemplate annotations 里面;当有变动时,会重新计算一次 hash 并更新 PodTemplate annotations,从而触发 Deployment 升级。无独有偶,开源社区里还有另一款工具 Reloader 也做了类似的功能——不同的是,Reloader 还能让用户自己选择填写监听哪几个 ConfigMap/Secret。 ...

June 3, 2019 · 2 min · jiezi

当我们在谈论高并发的时候究竟在谈什么

什么是高并发?按照现在现在google搜索出来的结果,大部分人给出的定义都大同小异。 高并发是互联网分布式系统架构的性能指标之一,它通常是指单位时间内系统能够同时处理的请求数,简单点说,就是QPS(Queries per second)。那么我们在谈论高并发的时候,究竟在谈些什么东西呢? 高并发究竟是什么?这里先给出结论: 高并发的基本表现为单位时间内系统能够同时处理的请求数,高并发的核心是对CPU资源的有效压榨。 举个例子,如果我们开发了一个叫做MD5穷举的应用,每个请求都会携带一个md5加密字符串,最终系统返回穷举出所有的结果,并返回原始字符串。这个时候我们的应用场景或者说应用业务是属于CPU密集型而不是IO密集型。这个时候CPU一直在做有效计算,甚至可以把CPU利用率跑满,这时我们谈论高并发并没有任何意义。(当然,我们可以通过加机器也就是加CPU来提高并发能力,这个是一个正常猿都知道废话方案,谈论加机器没有什么意义,没有任何高并发是加机器解决不了,如果有,那说明你加的机器还不够多!????) 对于大多数互联网应用来说,CPU不是也不应该是系统的瓶颈,系统的大部分时间的状况都是CPU在等I/O (硬盘/内存/网络) 的读/写操作完成。 这个时候就可能有人会说,我看系统监控的时候,内存和网络都很正常,但是CPU利用率却跑满了这是为什么? 这是一个好问题,后文我会给出实际的例子,再次强调上文说的 '有效压榨' 这4个字,这4个字会围绕本文的全部内容!控制变量法万事万物都是互相联系的,当我们在谈论高并发的时候,系统的每个环节应该都是需要与之相匹配的。我们先来回顾一下一个经典C/S的HTTP请求流程。 如图中的序号所示:1 我们会经过DNS服务器的解析,请求到达负载均衡集群2 负载均衡服务器会根据配置的规则,想请求分摊到服务层。服务层也是我们的业务核心层,这里可能也会有一些PRC、MQ的一些调用等等3 再经过缓存层4 最后持久化数据5 返回数据给客户端 要达到高并发,我们需要 负载均衡、服务层、缓存层、持久层 都是高可用、高性能的,甚至在第5步,我们也可以通过 压缩静态文件、HTTP2推送静态文件、CND来做优化,这里的每一层我们都可以写几本书来谈优化。 本文主要讨论服务层这一块,即图红线圈出来的那部分。不再考虑讲述数据库、缓存相关的影响。高中的知识告诉我们,这个叫 控制变量法。 再谈并发网络编程模型的演变历史 并发问题一直是服务端编程中的重点和难点问题,为了优系统的并发量,从最初的Fork进程开始,到进程池/线程池,再到epool事件驱动(Nginx、node.js反人类回调),再到协程。从上中可以很明显的看出,整个演变的过程,就是对CPU有效性能压榨的过程。什么?不明显? 那我们再谈谈上下文切换在谈论上下文切换之前,我们再明确两个名词的概念。并行:两个事件同一时刻完成。并发:两个事件在同一时间段内交替发生,从宏观上看,两个事件都发生了。 线程是操作系统调度的最小单位,进程是资源分配的最小单位。由于CPU是串行的,因此对于单核CPU来说,同一时刻一定是只有一个线程在占用CPU资源的。因此,Linux作为一个多任务(进程)系统,会频繁的发生进程/线程切换。 在每个任务运行前,CPU都需要知道从哪里加载,从哪里运行,这些信息保存在CPU寄存器和操作系统的程序计数器里面,这两样东西就叫做 CPU上下文。进程是由内核来管理和调度的,进程的切换只能发生在内核态,因此 虚拟内存、栈、全局变量等用户空间的资源,以及内核堆栈、寄存器等内核空间的状态,就叫做 进程上下文。前面说过,线程是操作系统调度的最小单位。同时线程会共享父进程的虚拟内存和全局变量等资源,因此 父进程的资源加上线上自己的私有数据就叫做线程的上下文。 对于线程的上下文切换来说,如果是同一进程的线程,因为有资源共享,所以会比多进程间的切换消耗更少的资源。 现在就更容易解释了,进程和线程的切换,会产生CPU上下文切换和进程/线程上下文的切换。而这些上下文切换,都是会消耗额外的CPU的资源的。 进一步谈谈协程的上下文切换那么协程就不需要上下文切换了吗?需要,但是不会产生 CPU上下文切换和进程/线程上下文的切换,因为这些切换都是在同一个线程中,即用户态中的切换,你甚至可以简单的理解为,协程上下文之间的切换,就是移动了一下你程序里面的指针,CPU资源依旧属于当前线程。需要深刻理解的,可以再深入看看Go的GMP模型。最终的效果就是协程进一步压榨了CPU的有效利用率。 回到开始的那个问题这个时候就可能有人会说,我看系统监控的时候,内存和网络都很正常,但是CPU利用率却跑满了这是为什么?注意本篇文章在谈到CPU利用率的时候,一定会加上有效两字作为定语,CPU利用率跑满,很多时候其实是做了很多低效的计算。以"世界上最好的语言"为例,典型PHP-FPM的CGI模式,每一个HTTP请求:都会读取框架的数百个php文件,都会重新建立/释放一遍MYSQL/REIDS/MQ连接,都会重新动态解释编译执行PHP文件,都会在不同的php-fpm进程直接不停的切换切换再切换。 php的这种CGI运行模式,根本上就决定了它在高并发上的灾难性表现。 找到问题,往往比解决问题更难。当我们理解了当我们在谈论高并发究竟在谈什么 之后,我们会发现高并发和高性能并不是编程语言限制了你,限制你的只是你的思想。 找到问题,解决问题!当我们能有效压榨CPU性能之后,能达到什么样的效果? 下面我们看看 php+swoole的HTTP服务 与 Java高性能的异步框架netty的HTTP服务之间的性能差异对比。 性能对比前的准备swoole是什么Swoole是一个为PHP用C和C++编写的基于事件的高性能异步&协程并行网络通信引擎Netty是什么Netty是由JBOSS提供的一个java开源框架。 Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。单机能够达到的最大HTTP连接数是多少?回忆一下计算机网络的相关知识,Htpp协议是应用层协议,在传输层,每个HTTP请求都会进行三次握手,并建立一个TCP连接。每个TCP连接由 本地ip,本地端口,远端ip,远端端口,四个属性标识。TCP协议报文头如下(图片来自维基百科): 本地端口由16位组成,因此本地端口的最多数量为 2^16 = 65535个。远端端口由16位组成,因此远端端口的最多数量为 2^16 = 65535个。同时,在linux底层的网络编程模型中,每个TCP连接,操作系统都会维护一个File descriptor(fd)文件来与之对应,而fd的数量限制,可以由ulimt -n 命令查看和修改,测试之前我们可以执行命令: ulimit -n 65536修改这个限制为65535。 因此,在不考虑硬件资源限制的情况下,本地的最大HTTP连接数为: 65535 * 本地ip数 = 65535 个。远端的最大HTTP连接数为: 65535 * 远端ip数 = 无限制~~ 。 ...

June 1, 2019 · 2 min · jiezi

一个优秀的可定制化Flutter相册组件看这一篇就够了

背景在做图片、视频相关功能的时候,相册是一个绕不开的话题,因为大家基本都有从相册获取图片或者视频的需求。最直接的方式是调用系统相册接口,基本功能是满足的,一些高级功能就不行了,例如自定义UI、多选图片等。 我们调研了官方的image_picker,它也是调用系统的相册接口来处理的,可定制程度不高,不能满足我们的要求。所以我们选择自己来开发Flutter相册组件。 我们的组件需要有如下的功能: 在app内完成图片、视频的选取,完全不用依赖系统相册组件可以多选图片,支持指定选定图片的总数目在多选的时候UI反应出选择的序号。可以控制视频、图片的选择。例如:只让用户选择视频,图片是灰色的。大图预览的时候可以放大缩小,也可直接加入到选取列表。设计思路API使用简单,功能丰富灵活,具有较高的订制性。业务方可以选择完全接入组件,也可以选择在组件上面进行UI定制。 Flutter做UI展现层,具体的数据由各Native平台提供。这种模式,天然从工程上把UI代码和数据代码进行了隔离。我们在开发一个native组件的时候常常会使用MVC架构。Flutter组件的开发的思路也基本类似。整体架构如下: 可以看出,在Flutter侧是一个典型的MVC架构,这里Widget就是View,View和Model绑定,在Model改变的时候View会重新build反映出Model的变化。View的事件会触发Controller去Native获取数据然后更新Model。Native和Flutter通过Method Channel进行通信,两层之间没有强依赖关系,只需要按约定的协议进行通信即可。 Native侧的组成部分,UIAdapter主要是负责机型的适配、刘海屏、全面屏之类的识别。Permission负责媒体读写权限的申请处理。Cache主要负责缓存GPU纹理,在大图预览的时候提高响应速度。Decoder负责解析Bitmap,OpenGL负责Bitmap转纹理。 需要说明的是:我们的这一套实现依赖于flutter外接纹理。在整个相册组件看到的大多数图片都是一个GPU纹理,这样给java堆内存的占用相对于以前的相册实现有大幅的降低。在低端机上面如果使用原生的系统相册,由于内存的原因,app有被系统杀掉的风险。现象就是,从系统相册返回,app重新启动了。使用Flutter相册组件,在低端机上面体验会有所改观。 一些细节1. 分页加载 相册列表需要加载大量图片,Flutter的GridView组件有好几个构造函数,比较容易犯的错误是使用了第一个函数,这需要在一开始就提供大量的widget。应该选择第二个构造函数,GridView在滑动的时候会回调IndexedWidgetBuilder来获取widget,相当于一种懒加载。 GridView.builder({ ... List<Widget> children = const <Widget>[], ... })GridView.builder({ ... @required IndexedWidgetBuilder itemBuilder, int itemCount, ... })滑动过程中,图片滑过后,也就是不可见的时候要进行资源的回收,我们这里这里对应的就是纹理的删除。不断的滑动GridView,内存在上升后会处于稳定,不会一直增长。如果快速的来回滑动纹理会反复的创建和删除,这样会有内存的抖动,体验不是很好。 于是,我们维护了一个图片的状态机,状态有None,Loading,Loaded,Wait_Dispose,Disposed。开始加载的时候,状态从None进入Loading,这个时候用户看到的是空白或者是占位图,当数据回调回来会把状态设置为Loaded的这时候会重新build widget树来显示图片icon,当用户滑走的时候状态进入 Wait_Dispose,这时候并不会马上Dispose,如果用户又滑回来则会从Wait_Dispose进入Loaded状态,不会继续Dispose。如果用户没有往回滑则会从Wait_Dispose进入Disposed状态。当进入Disposed状态后,再需要显示该图片的时候就需要重新走加载流程了。 2. 相册大图展示: 当点击GridView的某张图片的时候会进行这张图片的大图展示,方便用户查看的更清楚。我们知道相机拍摄的图片分辨率都是很高的,如果完全加载,内存会有很大的开销,所以我们在Decode Bitmap的时候进行了缩放,最高只到1080p。大图展示可以概括为三个步骤。 1 从文件Decode出Bitmap2 Bitmap转换成为纹理,并释放Bitmap3 纹理交给Flutter进行展示在步骤1中,Android原生的Bitmap Decode经验同样适用,先Decode出Bitmap的宽高,然后根据要展示的大小计算出缩放倍数, 然后Decode出需要的Bitmap。 Android相册的图片大多是有旋转角度的,如果不处理直接显示,会出现照片旋转90度的问题,所以需要对Bitmap进行旋转,采用Matrix旋转一张1080p的图片在我的测试机器上面大概需要200ms,如果使用OpenGL的纹理坐标进行旋转,大于只需要10ms左右,所以采用OpenGl进行纹理的旋转是一个较好的选择。 在进行大图预览的时候会进入一个水平滑动的PageView,Flutter的PageView一般来说是不会去主动加载相邻的page的。举个例子,在显示index是5的page的时候index为4,6的page也不会提前创建的。这里有一个取巧的办法,对于PageController的viewportFraction参数我们可以设置成为0.9999。对于前面这个例子,就是在显示index是5的page的时候,index为4,6的page也需要显示0.0001。这样index为4,6的page显示不到1个像素,基本上看不出来: PageController(viewportFraction=0.9999)还有另外一种办法,就是在Native侧做预加载。例如:在加载第5张图片的时候,相邻的4,6的图片纹理提前进行加载,当滑动到4,6的时候直接使用缓存的纹理。 纹理缓存后,一个直接的问题:什么时候释放纹理?等到预览页面退出的时候释放所有的纹理显示不是很合适,如果用户一直浏览内存则会无限增长。所以,我们维护了一个5个纹理的LRU缓存,在滑动过程中,最老的纹理会被释放掉。在页面退出的时候整个LRU的缓存会进行销毁。 3. 关于内存 相册图片使用GPU纹理,会大幅减少Java堆内存的占用,对整个app的性能有一定的提升。需要注意的是,GPU的内存是有限的需要在使用完毕后及时删除,不然会有内存的泄漏的风险。另外,在Android平台删除纹理的时候需要保证在GPU线程进行,不然删除是没有效果的。 在华为P8,Android5.0上面进行了对比测试,Flutter相册和原native相册总内存占用基本一致,在GridView列表页面,新增最大内存13M左右。它们的区别在于原native相册使用的是Java堆内存,Flutter相册使用的是Native内存。 总结相册组件API简单、易用,高度可定制。Flutter侧层次分明,有UI订制需求的可以重写Widget来达到目的。另外这是一个不依赖于系统相册的相册组件,自身是完备的,能够和现有的app保持UI、交互的一致性。同时为后面支持更多和相册相关的玩法打好基础。 后续计划由于我们使用的是GPU纹理,可以考虑支持显示高清4K图片,而且客户端内存不会有太大的压力。但是4k图片的Bitmap转纹理需消耗更多的时间,UI交互上面需要做些loading状态的支持。 组件功能丰富,稳定后,进行开源,回馈给社区。 本文作者:闲鱼技术-邻云阅读原文 本文为云栖社区原创内容,未经允许不得转载。

May 31, 2019 · 1 min · jiezi

自动化日志收集及分析在支付宝-App-内的演进

背景结合《蚂蚁金服面对亿级并发场景的组件体系设计》,我们能够通盘了解支付宝移动端基础组件体系的构建之路和背后的思考,本文基于服务端组建体系的大背景下,着重探讨“自动化日志手机与分析”在支付宝 App 内的演进之路。 支付宝移动端技术服务框架 这是整个支付宝移动端无线基础团队的技术架构图,同时蚂蚁金服体系内的其他业务 口碑、网商银行、香港支付宝、天弘基金等) 通过移动开发平台 mPaaS进行代码开发、打包、灰度发布、上线、问题修复、运营、分析。因此,mPaaS 源自于支付宝移动端的核心技术架构,并在 App 全生命周期的每个环节提供特定的能力支持。接下来,我们将着重分享“日志诊断”和“移动分析”两个能力背后的架构演进和选型思考。 支付宝移动端技术服务框架:数据分析框架 如图所示,即数据分析能力的技术架构图,其中“数据同步”、“埋点SDK”、“日志网关”是移动端专属的能力,其余部分是所有的数据分析平台都必须具备的数据结构。 1. 日志采集 接下来我们重点分析支付宝移动端的日志采集框架,首先第一部分是“日志 SDK”,日志 SDK 会向业务层提供一个埋点接口,使用起来就和 Java 里面的 logger.info 的感觉一样:业务层只需要把想记录的信息传递给日志 SDK。日志 SDK 会在拿到业务日志后,去系统内部获取相关的系统级别的上下文信息,比如机型、操作系统版本、App 版本、手机分辨率、用户ID (如果用户登录了)、设备ID、上一个页面、当前页面等,接着把这些信息与业务日志内容整合成一个埋点,然后记录到设备的硬盘上。对,只是记录到硬盘上,并没有上报到服务端。 日志 SDK 会在合适的时机,去和日志网关交互,判断获取什么样的日志、什么级别的日志可以上报。如果可以上报,是以什么频率上报、在什么网络条件下上报。因此通过日志 SDK 与日志网关的交付,我们可以来实现日志的策略式降级。日志的策略式降级这点对于支付宝特别重要,因为目前支付宝的体量,日常的日志上报量为约 30W 条日志/s;而在大促的时候,日志量会是日常的几十倍! 所以,如果大促期间不采用任何的日志降级策略的话,我们的带宽会被日志打包,支付宝的正常业务功能就不可用了。 由此,我们可以总结,在大促高并发场景下,我们需要只保留关键日志的上传,其余日志统统降级。即使是日常业务处理,我们也只允许日志在 WIFI 条件下上报,防止发生流量相关的投诉。 埋点网关除了提供日志上报的策略开关能力之外,就是接收客户端的日志。它在接受到客户端日志之后,会对日志内容进行校验,发现无效的日志会丢弃掉。而对有效合法的埋点,会根据客户端上报的公网 IP 地址,反解出城市级别的地址位置信息并添加到埋点中,然后将埋点存放在它自己的硬盘上。 2. 埋点分类 经过多年的实践,支付宝把日志埋点分为了四类。 (1)行为埋点:用于监控业务行为,即业务层传递的日志埋点属于行为埋点,行为埋点属于“手动埋点”,需要业务层开发同学自己开发。不过也不是全部的业务行为都需要业务方手动开发,有一些具备非常通用性的业务事件,支付宝把它们的埋点记录放到了框架层,如报活事件、登录事件。因此,行为埋点也可以叫做 "半自动埋点"。 (2)自动化埋点:属于“全自动化埋点”,用于记录一些通用的页面级别、组件级别的行为,比如页面打开、页面关闭、页面耗时、组件点击等。 (3)性能埋点:属于“全自动化埋点”,用于记录 App 的电量使用情况、流量使用、内存使用、启动速度等。 (4)异常埋点:属于“全自动化埋点”,严格上讲,也算是性能埋点的一种。但是它记录的是最关键的最直接影响用户的性能指标,比如 App 的闪退情况、卡死、卡顿情况等。这类埋点,就属于即时大促期间也不能降级的埋点! 图中的代码示例即为一条行为埋点样例,大家可以看到,埋点实际上就是一条 CSV 文本。我们可以看到里面有日志网关添加进行的地址位置信息内容,也有日志 SDK 给添加的客户端设备信息。 3. 日志处理模型 下面我们来整体了解支付宝内部日志处理的通用流程: (1)日志切分 我们已经了解到,埋点实际上即为一段 CSV 文本。而所谓日志切分呢,即将 CSV 格式的文本转成 KV,通俗点说就是内存里面的 HASHMAP。这个切分的过程,可以直接根据逗号进行切换,当然也还有很多其他的办法。 ...

May 30, 2019 · 2 min · jiezi

技术三板斧关于技术规划管理架构的思考

阿里妹导读:实践需要理论的指导,理论从实践中来。作为技术工程师,要不断地从事件中反思经验、总结规律,才能避免踏入同一个坑,才能更高效地完成 KPI ,甚至是晋升。今天的文章来自阿里巴巴高级技术专家毕啸,从五个方面总结工程技术的核心要点,相信对你能有所启发。大约半年前,开始总结自己关于工程技术的一些核心要点,关于规划、技术管理以及架构,三个方面的一些心得。结合自己团队的现状、自己对于周边做得比较好的同学的观察,于是有了文中的这几张图。 一、关于技术规划三板斧技术规划规划做得好,能起到比较好的正向引导作用,个人及团队的整体目标感会好很多,分为三个部分的内容: 第一部分是全局分析,这需要溯源历史,思考未来,要对未来有一定的预判。能够基于数据,基于专业,基于客户价值,同时结合顶层的战略、公司的战役情况和组织的现状做分析。 第二部分是定目标。这一部分非常关键,定义好目标以及非目标,哪些事情是不要做的也要讲明白,并且确认目标的实现路径,做好拆解。 最后一部分是以终为始,从最终结果的角度,来溯源开始。从技术支撑业务发展、平台能力输出或者赋能、平台研发效能以及技术数据驱动业务等不同的角度审视结果。 另外,关于创新,可以有几个不同维度的方法,例如通过上下左右的比较,用比较思维法来获取信息;例如移花接木,通过不同行业的分析来完成方案的嫁接;例如第一性思考,深度分析业务以及技术的场景,产出最后的方案。 二、关于技术管理三板斧这里的管理,不是团队管理,是指技术本身的管理。其实最近一年多,一直在倡导一件事情,就是技术的微观化管理,技术和其他的事务不太一样,一旦宏观化管理,不能 Deep Dive 细节,就非常容易引发各种各样的问题。例如,在研发质量中体现为研发效率降低,架构孵化。总体提供三个方面的建议: 首先,把控核心细节。软件工程这些年,本质是没变的。不管是偏互联网的部分还是偏企业级的部分,关键细节是需要严格把关的。 另外,就是数据化度量。通过数据驱动研发体系的重建,通过质量风险文化的宣导以及核心指标的跟进,起到督导的作用。 最后,就是清单革命。清单革命是一本书的名字,这里借用过来,合适是 checklist,不管是代码规约、应用规范还是稳定性治理等,都容易由于不重视或者不 check 而逐渐孵化。这时候,一个好的 checklist 非常关键重要。 三、关于技术架构三板斧关于架构,其实讲架构模式、TOGAF 架构、互联网架构等的书不少。架构本身有一些通用的方法的,但是方法一旦通用,就会偏虚无缥缈。这里总结了三个部分: 第一,是多元多维。这个概念来自穷查理宝典,因为架构需要良好的上下文输入,需要思考时间和空间维度,需要思考组织人才和 KPI ,需要思考目标过程和结果,这些和架构本身关系不大,但是关联到架构是否能够良好地落地。 第二和第三是相辅相成的,核心是分而治之,各个击破。架构本身是解决问题的过程,问题太复杂了,只能采用分而治之的办法。怎么分?利用金字塔原理,不遗漏、不重复,重点在业务架构和技术架构,同时在数据化上做思考,之后按照架构主题做拆分。怎么击破?分层架构和模块化架构,是比较通用的两个方法,业界有架构模式的参照,也可以用一些移花接木的方法。另外,关键架构主题和架构模式,也可以有checklist,方便在做架构的时候,通过清单对照不会漏掉重要内容。 四、关于赛车、赛道、赛手三段论去年六七月份,针对市面上已有的物流机器人公司,做了一个全局的分析。在分析公司上,是有一些方法论的,正当尝试总结的时候,正好看到“得到”的一个专栏,一名证券公司的分析师分析如何快速搞懂一家公司。于是,做了总结:一个前提,就是分析宏观背景,例如经济形势。接下来是三部分:赛道很容易理解,就是这个行业发展的情况,赛道够不够宽,赛道够不够长;第二个就是赛车,公司有没有核心的商业模式以及核心竞争力;第三个就是赛手,公司的人和文化,这个也非常重要。 五、关于点线面体的思考曾鸣老师的智能商业,是比较有深度的讲解互联网的一本书,中间有一篇文章是讲点线面体的,内容很不错。公司战略和个人发展战略,都可以从点、线、面、体的角度来思考。这里做一个引用: 点线面体,是一种全新的战略定位思考方法。这些年,很多人来找我讨论,公司的下一步应该怎么做。讨论多了我慢慢发现,传统的战略理论框架很多已经不适应现在新的环境了。战略的最核心是定位,很多人都耳熟能详。定位最传统的理论框架是波特提出来的成本领先、差异化和利基市场的竞争战略。虽然在未来这种定位还是大家需要去思考的,但实际上在网络时代有更重要的问题要先回答。曾鸣《智能商业》 本文作者:毕啸阅读原文 本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

May 30, 2019 · 1 min · jiezi

阿里云高级技术专家张毅萍我眼中的边缘计算

导读:边缘计算是目前公认的大方向,越来越多的边缘计算应用将随着5G建设的步伐而兴起。阿里云边缘计算团队的目标是在行业爆发来临之前,完成基础计算资源平台的构建,为产业提供基于体验的计算调度能力,进而助推整个产业快速应用发展。那么在目标背后为之奋斗的工程师是怎样的?他们们是如何一步步助推阿里云边缘计算实现从零到一的启动?这样的团队又需要怎样的人才呢?阿里云高级技术专家张毅萍在本文中给出答案。阿里云高级技术专家张毅萍,在学生时代就属于比较喜欢“折腾”的人,本硕都是计算机专业,也就让他更早踏入IT这个行当。在学校期间,相比日常的课程,他将更多的时间花在课外折腾上,比同龄人更早有了一些技术上的积累。在大三时参加科技创新方面的竞赛获奖并保研,之后因为时间上比较宽裕,大四就踏上了创业这条更“折腾”的路。 在创业期间,他更是把“折腾”特质发挥到极致,利用自身在分布式网络与音视频传输方面的技术经验,做过VoIP、P2P视频,赶上过移动互联网手机APP的第一波浪潮,也经历过从浪尖拍死到沙滩的全过程。一晃神,竟已经在创业这条赛道跑了13年。 在一年多以前,他选择加入阿里云,聚焦在边缘网络的整体架构设计、基于边缘网络的各种业务应用的设计和研发。他经常说,自己非常幸运能搭上边缘计算这班起步并飞速发展的快车,也非常期待为这个新方向的爆发付出自己的努力。每次朋友问起他的创业梦怎么办,他则笑着回答:自己并没有换赛道,边缘计算仍然属于创业,需要每一个看好的人为之付出200%的努力。 张毅萍来到阿里云边缘计算团队的一年多时间内,这个团队从0到1完成了边缘节点服务(ENS)产品的商业化,为客户实现边缘计算业务规模化提供了坚实的基础,引领了产业良性发展。同时,团队也积极推进行业标准化,去年12月份联合中国电子技术标准化研究院发布《边缘云计算技术及标准化白皮书》,在业界首次对边缘云计算下了定义。 边缘云计算提供的基础能力,主要包括网络和资源覆盖,以及匹配场景需求的计算、存储、安全、网络、稳定性、性能、成本优化等能力。其中很多方案是基于中心云的虚拟化方案进行改造的,比如计算虚拟化、块存储、VPC网络等,当然方案改造也有非常大的挑战,因为飞天系统的很多方案是基于规模化设计。有些则是新场景下的新方案,比如边缘回云的链路优化,资源调度等。 张毅萍所在团队的脚步不止于此,在边缘云计算的基础能力之上,他们要考虑的是服务形态问题,即用什么样的方式提供边缘计算的能力,新的挑战随之而来。 ENS产品1.0版本是一个IaaS的服务形态,依托独立的小规模边缘节点服务时,面对更广泛的客户需求,服务在资源弹性和稳定性等方面需要所有突破。同时,用户拿到一批边缘虚机实例后,需要考虑如何部署/升级应用,如何运维主机,如何监控等问题。另外,随着当前互联网架构的快速迭代,针对边缘计算场景,是否可以有一个先进的业务架构可以参考,是否有一组标准的API和基础中间件让用户快速构建自己的边缘业务架构呢? 张毅萍团队认为不能让这些问题变成用户享受边缘计算红利的门槛,所以,在年初ENS推出2.0版本,基于全局边缘资源的调度支持更好的资源弹性,应用镜像快速分发/升级能力以及配套的DevOps能力,并与阿里云容器团队合作,在边缘节点实现容器K8S+Docker生态的DevOps能力,通过云-边多区域统一的容器托管服务,赋能用户快速将业务下沉至边缘,缩短业务响应时间。 在未来,团队也会做持续的技术投入,勇作行业探路者。同时,张毅萍所在的阿里云边缘计算团队也期待更多有志之士加入,一起迎接更多未知和挑战。 谈到技术型公司的人才要求,张毅萍说:在互联网加速发展的阶段,我认为对于任何一个技术和非技术同学来说,最重要的是不要怕做错事情,很多事情技术上没有前人的经验做参考、商业上没有可复制的模式、现实情况下也没有太多的确定因素作为判断依据,那么就需要大胆假设,并为这个假设付出努力去证明它,哪怕证明假设的结果是错误的。过于担心自己付出的努力得不到好的回报,除了给自己制造心理失衡和焦虑,没有其它任何作用。 赶拼的小伙伴们,快加入我们吧,这里永远不会缺少挑战! 本文作者:山哥在这里阅读原文 本文为云栖社区原创内容,未经允许不得转载。

May 30, 2019 · 1 min · jiezi

ZooKeeper-学习笔记

ZooKeeper 介绍ZooKeeper(wiki,home,github) 是用于分布式应用的开源的分布式协调服务。通过暴露简单的原语,分布式应用能在之上构建更高层的服务,如同步、配置管理和组成员管理等。在设计上易于编程开发,并且数据模型使用了熟知的文件系统目录树结构 [doc ]。 共识与 Paxos在介绍 ZooKeeper 之前,有必要了解下 Paxos 和 Chubby。2006 年 Google 在 OSDI 发表关于 Bigtable 和 Chubby 的两篇会议论文,之后再在 2007 年 PODC 会议上发表了论文“Paxos Made Live”,介绍 Chubby 底层实现的共识(consensus)协议 Multi-Paxos,该协议对 Lamport 的原始 Paxos 算法做了改进,提高了运行效率 [ref ]。Chubby 作为锁服务被 Google 应用在 GFS 和 Bigtable 中。受 Chubby 的影响,来自 Yahoo 研究院的 Benjamin Reed 和 Flavio Junqueira 等人开发了被业界称为开源版的 Chubby 的 ZooKeeper(内部实现事实上稍有不同 [ref ]),底层的共识协议为 ZAB。Lamport 的 Paxos 算法出了名的难懂,如何让算法更加可理解(understandable),便成了 Stanford 博士生 Diego Ongaro 的研究课题。Diego Ongaro 在 2014 年发表了介绍 Raft 算法的论文,“In search of an understandable consensus algorithm”。Raft 是可理解版的 Paxos,很快就成为解决共识问题的流行协议之一。这些类 Paxos 协议和 Paxos 系统之间的关系,如下 [Ailijiang2016 ]: ...

May 30, 2019 · 6 min · jiezi

把握数据库发展趋势-DBA应如何避免踩坑

摘要:在DTCC 2019大会上,阿里云智能数据库产品事业部高级产品专家萧少聪做了题为《如何构建云时代DBA的知识体系》的演讲,进行云时代以后,IT行业各工种的职责都在发生变化,云数据库使得日常DBA管理实现更多的自动化,大大提高日常管理效率,同时也对于企业整体投资产出可以更快获得成效。面对云数据库的发展趋势,DBA应如何避免“踩坑”呢?本文就为大家揭晓答案。 专家简介:萧少聪(花名:铁庵),阿里云智能数据库产品事业部高级产品专家,PostgreSQL中国社区常委。 直播回放链接:https://yq.aliyun.com/live/1046 议题PPT下载,戳这里!https://yq.aliyun.com/download/3562 本文将主要围绕以下四个方面进行分享: 管理模式的变化云数据库VS.自建数据库云DBA知识体系构成如何成为优秀的云DBA一、管理模式的变化对于数据库技术而言,“云”已经成为大家无法忽视的技术趋势。在Gartner 2018年的数据库魔力四象限里面,云计算数据库厂商已经占LEADERS及VISIONARIES领域的绝对比例,这也代表了业界对于云的认可。 那么,云和传统架构有什么不同呢?对于传统数据库系统而言,需要搭建很多的硬件,连接很多的网线,在自己搭建的私有云里面可能会有一些虚拟化或者容器化的架构,再往上对于DBA而言其实需要的就是一个数据库,需要能够连接进去进行操作。当然了,在传统架构下,DBA能够对数据库有更多的操作和配置,但是在云上可能只会提供一部分数据库配置文件的修改权限,并不会允许修改全部配置,这是因为云为DBA提供的是SLA,也就是说云数据库提供的是服务。针对于服务而言,不太可能允许DBA去对操作系统进行改变,因为这样可能会破坏HA,因此会有一些限制,但是对于数据库操作而言,依旧是通过一个端口就连接进去的。 除了数据库架构设计之外,传统架构和云架构在做安装配置的时候也会有所不同。在传统架构下,DBA需要去规划数据库所有的一切,包括操作系统、硬件以及各种安装准备以及验收、切换等一系列演练。在云架构之下,整体的配置、安装以及部署是不需要DBA敲各种命令或者安装各种业务系统的,操作系统、参数优化以及整体的HA只需要在云控制台上点击几下就可以配置完成,无论使用阿里的公共云还是私有云都是这样的状态。这些就是在管理模式方面或者在系统创建过程中已经能够看到的变化。 二、云数据库VS.自建数据库有很多人存在这样一个疑问。那就是“云数据库和自建数据库有哪些区别?”。这里首先澄清一个概念,在阿里巴巴看来,真正云托管的数据库才是云数据库,而如果只是使用ECS云服务器来自行搭建的数据库并不算是真正的云数据库。 实际上,云数据库最终提供的是一个服务,其包括了系统的可靠性、可用性、安全、备份等一系列的东西,当建立完云数据库这些都是配置完成的,无需DBA进行二次配置。当然,如果DBA有自己配置的需求,阿里云所提供的云数据库服务也会提供API接口进行调配,或者也可以通过阿里云的管理平台进行操作,而不像传统情况下需要非常高的数据库初始建设费用。 成本模式的变迁 对于成本而言,传统情况下自己建设数据中心需要规划好未来3到5年到底需要多少资源,所以成本是一次性提供的。此外,对于DBA而言,一般将其分为业务DBA和运维DBA,前者为数据库业务解决问题,发挥功用,后者纯粹地负责运维工作,比如安装、部署、定期进行各种类型的巡检。未来,运维DBA会因为云架构的体现慢慢地减少,而业务DBA却不会消亡,因此DBA应该更加关注于企业在做什么业务,数据架构应该如何优化,帮助企业改变本身的运营状态。 以往成本的开支,一下子就是一台服务器,但是如今在云上或者互联网上有很多的创业公司,所谓的“独角兽”就是从很小规模开始起步,突然之间变成很大。当这些创业公司小的时候或许并不需要购买一台服务器,通过云架构,就可以从很小开始,逐渐弹性上去,这样的弹性能力使得IT实现资源的释放。如果今天还在使用传统的数据库服务器购买方式,而竞争对手或许就能够将节省下来的资金用于技术人员或者业务上去,因为没有了固定资产初期的开销,对于创业公司而言,其运行的资金链也会更加健康,发展的速度也会更快。 三、云DBA知识体系构成随着数据库技术的发展,企业对于DBA的需求也不断提高。从对于OLTP这样的SQL数据库和NoSQL数据的掌握,进一步演进,为了解决性能问题可能需要Key-Value缓存数据库,之后建立OLAP数据仓库,再之后实现大数据离线分析。 而对于初创公司而言,就会发现在最开始可能三两台机器就搞定了,只需要一个兼职的DBA。 进一步当开始使用Key-Value缓存数据库之后,业务越来越重,单台服务器无法搞定,需要实现HA。此时就比较困难了,因此需要一个比较神奇的DBA,需要DBA什么都懂。 当企业进一步发展到更大的时候,可能不仅仅需要解决一套系统的问题,可能需要解决多套系统的问题。此时可能需要一个DBA团队,分工会变得更为细致,不仅有专业的DBA,还应该有顶尖的架构级别DBA来解决整体问题。 更进一步,可能需要做数据仓库和大数据,那么整个DBA团队的分工就会更加明细。 在企业的实际运行过程中,DBA需要做大量的工作,有的时候甚至是操作系统的各种细节都需要了解清楚才能将数据库调优好。 云数据库的理论基础 而当进入云数据库时代,需要看到的是另外一种景象。这里有一些云计算的新名词,比如Region地域、AZ可用区、VPC以及VSwith等,这些都是云DBA需要了解和掌握的。从数据库的角度来看,云数据库的确出现了很多新名词,但是数据库基础理论依然是不变的,依然会有实例、高可用、分布式、SQL、ACID和CAP等理论。 运维简化:自动化部署 以往都会说需要部署一个主备集群,而今天如果想要部署主备集群也会在一个IDC中心进行部署。如果想要部署跨IDC的主备集群,在传统架构下往往需要购买光纤、光缆,并且需要确定光纤、光缆的延迟情况,判断其所造成的延迟是否能够接受。而在云数据库架构之下,这些信息都不需要进行管理,所需要管理的就是在购买云数据库时进行选择,比如选择跨中心的主备就可以直接建立起来,因此这种复杂架构的构建并不需要自己来规划,可以节省DBA去做传统底层业务处理的时间。 运维简化:跨地域部署及切换 除了对于传统架构比较容易的同一个城市跨AZ之外,其实如果想要实现跨省就会变得非常复杂了。然而,在云上就会变得非常容易,如果想要实现跨Region的搭建就可以利用阿里云上的DTS工具将数据拉过去,需要进行数据复制的时候才会收费,平时不用的时候甚至可以直接将其关闭掉。 当搭建了跨Region的数据中心之后,后面就会有更多的事情。比如到底敢不敢进行主备切换,以往做主备切换的时候都需要配置一大堆的DNS,自己写很多脚本做确认,而在云架构底下,只需要通过一个按钮就可以实现。因此,大家一定要清楚,作为云DBA应该去学习哪些东西,同时需要放弃哪些东西的学习。因此当有云架构之后,DBA可以将重心放到学习如何优化SQL以及各种不同的数据库特性以及它们之间的组合架构如何解决业务上的问题,而底层的业务架构可以交给云去做。 运维简化:定期全/增量备份 在云上面,如果需要做定期增量备份也仅仅需要点击几个按钮进行构建即可。 运维简化:恢复到时间点 无论针对于哪个数据库,阿里云的服务都可以做到任意时间点的秒级恢复。这一功能并不只是为了帮助用户找回数据,很多用户的DBA和开发的互动越来越频繁,如果开发收到某个时间段系统运行较慢的反馈,就可以直接克隆一个那个时间段的新实例出来,并且只需要按需购买即可,克隆出来实例调试完程序之后直接将其关闭掉即可,一切的成本都在DBA的掌握之中。 运维简化:按需横向扩展 DBA对于数据库的横向扩展也会做很多动作,传统的方式通过只读实例可以做相应的扩展,同时还有像阿里云的DRDS分布式数据库分片的运行方案,也能够比较容易地搭建出来,进一步地还可以走向PolarDB,通过分布式的一写多读来简化业务规则。未来,DBA需要重点关注的点在于什么时候使用什么样的架构。举例而言,如果需要解决某个大促时间段大量的读请求问题,应该通过只读实例来实现。而如果老旧业务完全可以基于互联网改写,就可以选择直接通过DRDS做整个系统的分库分表操作。如果需要非常强的与关系型数据库一致性的业务,并且与此同时数据量非常大,可能需要选择PolarDB的架构,因此DBA需要对于不同的数据库架构以及其背后原理有自己的理解。 运维简化:自动读写分离阿里云数据库帮助用户实现了读写分离,DBA不需要再进行应用程序上的业务改写,比如对于读写分离的设置都可以实现自动化。通过对于请求的分析来判断应该分发到读实例还是写实例。 以上这些都是云数据库能够提供的能力,大家会发现以往的管理模型已经都覆盖到了。未来运维方面的DBA工作可能减轻,因此DBA应该跳到业务方向上进行发展。 四、如何成为优秀的云DBA在云数据库的背景下,DBA是否还需要学习每一部分的数据库管理知识呢?因为人的时间是有限的,未来除非真的要做类似于阿里云的整体管控系统时需要深入底层进行分析,而如果不是,那么这些数据库管理就可以交给云管控平台来实现。但是数据库优化却需要DBA知道和掌握,这里并不是指修改哪些参数能够优化成什么样子,因为这些在云平台上就已经配置好了,但是DBA需要知道的是针对于某个数据库,什么样的索引对它更加有效,表与表之间的关系应该如何建立才能使得数据库性能更好。 云数据库提供了很多的集群架构,也并不一定需要全部学习。无论是单节点、双节点还是三节点,通过阿里云都可以实现一键式部署。因此作为DBA更加需要了解不同的数据库实例之间应该如何进行互动,从而产生对业务有效的架构方案和规划方案,这正是DBA需要深入思考的,而不是每天都在备份服务器,部署数据库,检修各种硬件。 云服务支持边界 基于云的运行环境,云数据库服务和DBA的边界会发生改变。资源调度、基础优化、平台能力以及准确输出都是由云来提供的,而企业的DBA需要做这样几件事情:对于表结构需要花费更多的时间来规划,定义自己企业的SQL标准来规范开发模型,对于SQL以及结构进行优化来提升业务性能。此外,DBA不仅应该关注于数据库,实际上也应该做企业成本的控制,通过不同的数据模型组合来解决不同的业务问题,也需要了解云数据库日志的不同,并通过故障检测自查或者发起服务需求。 性能问题甄别 对于云DBA而言,如果出现了数据库性能问题应该怎么做呢?其实任何的云厂商都会有自己成熟的一整套监控以及性能分析方案,比如阿里云的方案就源自于阿里巴巴内部的经验,能够帮助DBA发现故障并提供解决方案,使用起来非常方便。 云服务支持边界 此外,阿里云也提供了一种能力,就是阿里云后端的DBA会帮助用户解决数据库相关的问题。以往情况下,如果数据库出现了问题,需要打电话给服务商来约时间解决,存在一定的延迟。而今天在阿里云上面,DBA随时可以进入。并且阿里云还提供了安全保障,具有完善的授权机制,只有用户授权阿里云的DBA访问用户数据库或者进行服务的时候,阿里云的DBA才有权限为用户提供服务,而如果没有得到授权,阿里云的DBA是不能够进入的。 高危SQL预防 阿里巴巴具有自己的一整套数据库开发规范,而用户的DBA也可以自己定义一套数据库开发规范,比如可以定义某一个字段是否可以以某种方式编写,这样就从系统设计和规范的层面避免烂SQL进入系统,进而造成系统故障。 跨云管理 今天,阿里云本身在运营云,而其实阿里云也会提供跨云的管理工具。无论用户使用的是哪里的云,只要管理的是MySQL、MongoDB、Redis数据库都会提供HDM工具来协助用户管理跨云数据库。 总结一下,云数据库带来了标准化部署、自动化运维、按需扩容以及工具化调优等优势。对于企业而言,不要再让DBA为部署和备份等琐碎的运维工作所缠绕了,他们应该将精力投入到优化架构、写好SQL以及做好数据库的整体构造上,进而为企业输出核心技术生产力。 本文作者:七幕 阅读原文 ...

May 29, 2019 · 1 min · jiezi

阿里云CDN技术掌舵人文景相爱相杀一路狂奔的这十年

导读:提到阿里云CDN,不得不提技术掌舵人姚伟斌(文景),虽然他不是团队中最“老”的同学,但他却历经了淘宝业务发展最为飞速的几年,见证了从最初服务淘宝和集团内部的CDN,到如今国内服务客户最多的云CDN的每一步技术蜕变。在他看来是业务在推动着技术的发展,技术带动了人的成长,过程中不乏迷茫和低谷,但最终确实是一次次的业务洪峰把CDN技术推向了顶端。 缘起开源 怀着赤子之心加入阿里读书时期的文景是个非常“爱折腾“的学生,经常去女生宿舍帮忙调通网络,也接了很多系统开发的私活项目。在研究生阶段接触到了嵌入式开发、无线传感网络、Linux,底层网络,向服务端开发转型。 当时比较火的是金融和通信专业,但是文景对开发就是如痴如醉的喜爱,虽然他的学习成绩不算拔尖,但是因为项目的实操历练经验丰富,他在毕业时候顺利的进入了一家互联网大厂。也就是在这份工作中,他接触到了很多服务端开源软件,如Nginx、Squid、Varnish、Lighthttpd等,也为后续进入阿里奠定了基础。始终认为开源对拓宽程序员的视野和提升代码水平非常重要,所以他开发了很多Nginx开源模块,因为不断的打磨,有一些项目在Github上有上千的星了。回忆当初,技术人员需要一定的价值认同,要么在业务上厉害,有上千万的用户,要么就是技术价值的认可,你做的东西不仅自己在用,成千上万的开发者也在用,甚至有国外的开发者会给你写感谢信,这是非常好的技术认可。 “后来当时的公司业务发展比较慢,遇到了发展瓶颈,而因为自己在开源领域的一些成就,被阿里看中。当时阿里属于业务早期,我心里怀疑这公司到底行不行,没想到面试官竟然是开源领域非常有号召力的“大神”,我当时立刻就决定加入阿里了。有时候程序员选择一份工作不是看业务多强大,而是身为程序员的梦想使然。“文景说。 来到阿里后,文景负责Tengine的研发,从一个人单干,逐渐发展到小团队,Tengine也成为集团95%以上业务的入口。在阿里节奏很快,业务每年的增长几倍甚至几十倍,这十年来有三千倍的增长,这过程中也深刻体会到人和公司的成长是同步的。Tengine业务复杂度非常高,支持整个阿里集团的业务。作为一个支撑性的部门,更需要自驱力,主动做好,主动邀请别人来使用,并且在期间主动解决问题让业务变得更好。 在阿里这么快节奏的工作环境之下,文景还坚持付出额外的时间来做开源,有一段时间Tengine曾跻身全球前十的WebServer,这也是团队成员至今都非常自豪的事情。 这十年,双11和这些程序员“相爱相杀”文景很幸运,加入阿里的第一年他就赶上了双11。对于当时的淘宝技术人来说,双11是每年最最重要的事情。“对我们来说,最关键的就是在零点那一刻,系统要扛住,降级的措施越少越好“。文景回忆到,当时的技术原则:第一是要对业务有预估,几千万人同时并发的QPS是多少,系统能不能支持;第二,要做技术预案,所有依赖系统的容量是多少,一旦出了问题后的应对方案。”经过头几年双11考验后,系统逐渐具备了在极限的情况下也能正常运行的能力,在高性能、稳定方面有很大提升。到后来,我们技术能力和资源储备,已经远超当年秒杀的规模,当前的技术架构已经足以支撑,所有的技术人这才安心了。“ 当然,技术的积淀并不是一蹴而就。在这种高强度的业务压力下,基本上所有的瓶颈都会被文景团队遇到,内存、CPU、IO、网络,来来回回做了很多轮软件优化和节点架构升级。为了应对峰值压力,团队也提前准备业务锁量、节点压测、降级预案、采购临时带宽等多种措施。在我们的监控和数据还不完善的那个年代,双11就靠每个人打开多个终端,盯着一批节点,一旦发现机器负载过高,立马进行人工干预。 转眼来到了2012年,文景认为这一年对CDN非常关键:“第一,我们决定不再采用外部的商用CDN,因为我们发现淘宝的流量,商用CDN是不足以支撑的。原因是淘宝是中国第一个图片这么多的网站,当时的SSD机器还没有这么流行,大部分的CDN厂商还在用SATA的机器,遇到数据量激增的时候,它的IOPS跑不起来,节点立刻会挂掉。第二,当大部分CDN厂商都在用千兆机器,淘宝CDN已经在用万兆机器,我们是中国第一个使用全SSD机器的厂商,并且完成了40G能力的节点上线。当时的技术架构是非常领先的。” 随后的几年,随着CDN能力的增强,双11扛住了数十倍的业务峰值流量,而且很多业务已经开始使用CDN,比如秒杀、红包、详情页等。后来CDN不仅支持集团内部双11,也开始服务外部客户。那几年的发展可以用一路狂奔来形容,每年都有新的业务产生,比如HTTPS、直播、短视频等,文景带领着团队不仅要做产品商业化、要贴身服务客户,还要去快速适应并调整面向新业务的技术方案、优化用户体验、技术攻坚、节点建设,同时也要对集团和客户的双11做全链路的保障方案,双11每年带宽增速在50%-100%,文景的脚步从未停歇。 跌倒了,爬起来继续上路狂奔这一路,文景经历过高峰,当然也有跌落低谷,他认为2015年对团队来说意义非凡,因为那一年他们险些背了3.25。当时淘宝上了全站HTTPS,而由于前期压测、对新业务的评估没有做到位,全站HTTPS带来的计算开销导致CPU、内存都开始成为瓶颈。“当双11开始后,别人都在为数据再创新高而欢呼,我们团队的工程师却眼睁睁的看着线上一些节点内存被打爆,不停重启,当时我在客户现场驻场,真的连死的心都有了。”文景回忆到。 当时的CDN团队已经到了阿里云,经常全中国到处跑,深入客户现场,贴身服务,整个团队的工作重心不再仅仅是为双11做方案和保障。“我们从纯碎的技术人,变成了需要有商业思维的架构师,用CDN这个产品帮助客户去解决问题。也正是因为如此,这次的经历给我们敲响了警钟,后面每当新业务诞生的时候,我们都做足了充分的预案,坚决避免再次重现,更绝不容许这种情况出现在客户身上。” 在此之前,文景带领的CDN团队已经进入阿里云,完成了从“甲方”到“乙方”的转型。“我们还是很偏技术思维的,我们认为只要把自己这块的技术做好做透,一切就顺理成章了。最开始我们在Tengine团队才不到10个人,是纯技术团队,负责软件开发。在转做CDN后,我们要去owner整个系统,考虑的东西更多,系统稳定性是第一优先级。如今,到了阿里云,我们需要吃透业务,所有技术人员都要去跑客户,去了解客户的需求,研究如何更好的服务他。这对我们来说其实是一个角色的转变,技术与商业结合的思维转变。”文景说到。 转型所带来的彷徨并不是所有人都能顺利度过,一度有很多技术人员抱怨业务做太多了,甚至有人离开。文景做为团队负责人,责无旁贷要帮助大家去适应。他当时鼓励工程师们“荤素搭配”自己的工作,要肩负起偏业务性的工作,当然也留出精力去做系统性的纯粹开发,这对工程师的发展是非常有好处的。他也不断地用自己的亲身经历告诉大家,业务,能让技术人员更好地了解产品的设计、提升去场景的理解。阿里全员一直崇尚着“客户第一”,在文景看来,客户第一就是真正地了解客户的需求,再把它变成产品,解决更多客户的问题,而不是你觉得这个产品牛,硬塞给客户去用。总之,技术牛不牛,要拿商业来证明。 到如今,文景所在的阿里云CDN团队已经拥有遍布全球的2500+节点和120T带宽能力储备,同时凭借全球服务能力和产品技术优势被评为全球级(Global)服务商,即面向全球五大洲提供围绕密集商业和消费城市的接入服务。 给年轻技术人一些建议最后,对于想了解或者想踏入CDN这一领域的技术人员,文景也给出了一些建议。 了解行业 CDN这个产品的历史,比云计算还要久,因为互联网的发展而应运而生的产品。现在,这行业是充分竞争的行业,它已经有成熟的解决方案和开源的软件,最终决定性产品的核心竞争力就是:稳定性、成本和质量,厂商们都在寻求更好地突破。阿里云CDN通过历年双11沉淀下来的技术和快速响应能力,已经在四年时间内,从零做到了中国最大的云CDN。未来的CDN行业,会更注重客户价值,面对客户关于低成本、服务质量、安全性、高清视频等不同价值需求点,需要不同场景和技术来满足。 研究开源,专注,不断学习 首先,文景认为去选择优秀的开源软件是一种好的方式,Github是程序员非常好的名片,开源软件写的好的人,代码、沟通能力、落地能力都不会差。第二,一定要专注,决定了方向后,至少要沉淀3年左右的时间,当你成为这个行业的专家,去任何公司都会发挥很大的价值。第三,要不断学习,计算机行业日新月异,对于技术人最大的挑战就是不能停止,要不停去接触新的东西。每年的业务都是两三倍的增长,你会发现你原来的技能已经跟不上业务增长的步伐,在互联网这么快速发展的环境和阿里发展这么迅速的公司,不学习就会被淘汰,绝对不能固步自封。 最后,欢迎加入我们! 阿里云CDN团队诚招技术人才啦!点此查看最新职位! 本文作者:山哥在这里阅读原文 本文为云栖社区原创内容,未经允许不得转载。

May 29, 2019 · 1 min · jiezi

达摩院首席数据库科学家李飞飞云原生新战场我们如何把握先机

阿里妹导读:云计算大潮来袭,传统数据库市场正面临重新洗牌的情境,包括云数据库在内的一批新生力量崛起,动摇了传统数据库的垄断地位,而由云厂商主导的云原生数据库则将这种“改变”推向了高潮。云时代的数据库将面临怎样的变革?云原生数据库有哪些独特优势?在 DTCC 2019大会上,阿里巴巴副总裁 李飞飞博士就《下一代云原生数据库技术与趋势》进行了精彩分享。 李飞飞(花名:飞刀),阿里巴巴集团副总裁,高级研究员,达摩院首席数据库科学家,阿里云智能事业群数据库产品事业部负责人,ACM 杰出科学家。 大势所趋:云数据库市场份额增速迅猛如下图所示的是 Gartner 关于全球数据库市场份额的报告,该报告指出目前全球数据库市场份额大约为400亿美金,其中,中国数据库市场份额占比为3.7%,大约为14亿美金。 具体到数据库市场分布,传统五大数据库厂商 Oracle、Microsoft、IBM、SAP、Teradata 占比达到了80%,云数据库的份额占比接近10%,并且云数据库市场份额占比每年也在快速增长,因此, Oracle、MongoDB 等也在大力布局其在云数据库市场的竞争态势。 根据 DB-Engines 数据库市场分析显示,数据库系统正朝着多样化、多元化的方向发展,从传统的 TP 关系型数据库发展到今天的多源异构的数据库形态。目前,处于主流位置的还是大家耳熟能详的数据库系统,比如商业数据库 Oracle、SQL Server以及开源的 MySQL、PostgreSQL 等。而一些比较新的数据库系统,比如MongoDB、Redis 则开辟了一个新的赛道。数据库 License 的传统销售方式在逐渐走下坡路,而开源以及云上数据库 License 的流行程度却在不断提升。 数据库:云上应用关键的一环正如 AWS 创始人 Jeff Bezos 所说:“The real battle will be in databases”。因为云最早是从 IaaS 做起来的,从虚拟机、存储、网络,到现在如火如荼的语音识别、计算机视觉以及机器人等智能化应用,都是基于 IaaS 的,而数据库就是连接 IaaS 与智能化应用 SaaS 最为关键的一环。从数据产生、存储到消费的各个环节,数据库都至关重要。 数据库主要包括四大板块,即 OLTP、OLAP、NoSQL 以及数据库服务和管理类工具,也是云数据库厂商发力的四个方向。对于 OLTP 而言,技术发展已经历经了40年,而如今大家还在做的一件事情就是“加10元和减10元”,也就是所谓的事务处理。当数据量变得越来越大和读写冲突的原因,对数据进行在线实时分析的需求衍生出了 OLAP。由于需要 Scale out,而数据强一致性不能够得到保证,就有了NoSQL 。而最近又出现了一个新名词—— NewSQL,这是因为 NoSQL 也有所不足,故将传统 OLTP 的 ACID 保证与 NoSQL 的 Scale out 能力进行了整合,变成了NewSQL。 ...

May 29, 2019 · 2 min · jiezi

阿里技术专家努力成为一名‘‘值得跟的Leader

图片描述(最多50字)本文来源 | 土豆他爸爸 作者 | 老穆,阿里技术专家,持续关注移动端技术架构、大前端全栈技术领域。 有时会听到小伙伴,吐槽自己的现任或前任直接主管。 随着工作时间和经验的增长,每每看到这种吐槽,我就会反思,假设有一天我是那位被吐槽的主管,我就一定能做的更好吗?如果自己不敢SAY YES,那反倒说明自己的火候不到,一定还有哪部分欠缺,但它具体是什么呢? 刚好最近在学习“宁向东的管理学课”,今天我也试着通过四象限图表,来结构化的展示下我对Leader类型分类的理解,什么样才是一个好Leader。 我认为,在一般的下属眼中,Leader可分为以下4种(1234四个象限): “值得跟”的Leader(1象限) 1、这是对一个Leader,最高的评价。 2、大部分下属(排除是个别狗腿子下属),从心里愿意跟着这位老板,认为“跟着他有肉吃”:事情能做成,能力能成长,物质能回报。 3、这个象限的Leader,其本身也一定会散发着某些特殊人格特点,且他们往往具备较强的专业能力。 4、不打嘴炮,能以身作则;情商不会差,能笼络好人心;能够平衡好业务KPI及关注下属职业成长;有独立的业务和技术见解;能为团队谋到正确的出路;不一味的打鸡血鼓励加班,Smart Work not Hard Work。 “靠得住”的Leader(4象限) 1、这种是常见的,较好的老板,一个字,“稳”! 2、毕竟人到中年,以及某些客观原因,不可能所有的Leader都是上图第1象限的那种,都是人中龙凤。普通主管是大多数,工作勤勤恳恳,不打鸡血,不吹牛逼,有职业素养,具备自己一套工程、业务、管理方法论的Leader,已经是很“稳”的主管了。 3、这样的老板,会踏踏实实带着大家做事。在团队齐心协力的努力下,结果往往不会太糟,所以物质回报也还ok。 4、不过这种Leader身上的个人魅力或职场魅力,相对会弱一些,所以他对下面的人的未来成长的正向影响因子也相对有限。 “画大饼”的Leader(2象限) 1、这种老板,理论能力强,且有独立认知,但下属不一定买他的账。 2、他常能把3年后的业务蓝图都规划好了,也不能说他说的不对,毕竟有些说的也挺有道理,且无法证伪,但是说的那些东西,总是不怎么容易落地。所以下面的人干活也比较懵逼,缺乏方向感和KPI量化指导。 3、他常低估,一线干活的员工所遇到问题的复杂性及解决时间。而且喜欢拔高业务价值,导致“上面”对这个团队预期偏高,所以稍有不顺利,反倒是促成了“画大饼”的现象。 4、跟着爱“画大饼”的Leader,下面的人往往身体比较累,因为需要通过肉体的加班,去弥补老板向上汇报,画出来的那张“大饼”。但是也有例外,因为能超出预期的结果,往往也都是难啃的骨头,不能一棒子拍死这类“梦想型”主管。 “被吐槽” 的Leader(3象限) 1、这种老板既不得民心,业务往往也拿不到好结果,而且通常情商都不高。 2、作为Leader,如果得不到下属的内心认可,往往说明他在组织管理、业务管理、情商管理、下属职业晋升培养管理、团队发展规划管理等“多个方面”做的不好,所以才引得下属在工作之外对其吐槽。 3、跟着“被吐槽”的Leader,下面的人往往心比较累,因为所有被安排的事情,做起来都是那么不痛快,但是谁让自己要汇报给他,还得违心的“跪舔”,所以有机会还是趁早换坑。 “值得跟”绝对是对一个 Leader 最高的赞扬 上面4种Leader类型,是从对“个人未来发展”和对“社会性投入回报”两个层面来拆解的。现在职场人,大家都想有良好的职业发展,但也请领导别总打嘴炮,该有的物质落地还是要有的,聪明的领导,会配合着短期和长期回报组合着来。 另外,能躬行实践,肚子里有货,有认知深度,且在有了家庭后还能平衡好工作与生活的Leader,真的不多见。 Leader也是人,大多数更是普通人,如果工作投入的多了,自然家里照顾少,如果家里照顾的多了,自然会借用公司的职能杠杆,让下面人去多干一些,这些都需要主管智慧的平衡。 所以通常情况下,Leader也确实不好做,所以如果自己能遇到好领导,请珍惜,多向他学习,不管是工作方式、还是生活平衡、还是情商处事。 对于想寻找值得“跟随”的好老板的小伙伴,我建议是,第1象限最优,其次是第4象限,再次是第2象限,最后是第三象限。如果跟着一个第三象限的领导,请努力尝试更换到第2或第3象限的领导,第1象限的则可遇不可求,没遇到之前请努力提高自身,没有好坑,那就先让自己成为一个好萝卜。 组织发展的必然性 记得前些年看到帖子,“在基础薪资一样的情况下,毕业生应该进大公司还是小公司或创业公司”,记得那时候两种观点都有自己的一些理由,无非就是大公司去了是拧螺丝,小公司则可以学习更多知识,让自己快速成长。当时我的观点是,各有各的好,核心重点是应该注重提高自身,不要纠结,都可以水到渠成。 但是时至今日,我对这个问题,越来越有了更明确的答案,因为想清楚了,我现在的建议是:“在条件允许的情况下,请选择进大公司”。 对于出入职场的人,如果能进入大公司,岗位职责和从属领导关系一般会比较明确,虽然不能让你像创业公司一样十八般武艺样样熟悉。 但是由于公司具备完整的通识培训,且会在特定领域,让你重复性的锻炼某些必须的技能,重复事情做的多了,复利作用就会出现,自然会产生一些衍生能力的提高,大厂沉淀的那些在各种社会光圈背后的道理,慢慢的就会被自己悟出来。 而且在整体的工作方式和业务理解上,大厂也会提供一个良好且稳定的成长环境,这对青壮年的新人来说,这样的阳光和土壤,远比如何能在短时间拿到什么果实(工资、晋升、名头)更重要。虽然大厂现在越来越不好进,但机会还是有的。 努力成为一名"值得跟"的Leader 组织业务考核主管的,是KPI,而员工心里考核主管的,则是口碑。口碑里会流露出心底是否服他。所以好口碑的主管具备哪些特点呢?这些特质自己是否可以提前提高?不妨拿镜子对比自己现在的水平: 1、下面的人服你: 在业务能力水平、管理水平上,“服”这个主管2、上面的人器重你: 更上级的领导,认可该主管的工作结果,所以跟着他的人自然“有肉吃”如果跟着他的人,持续有肉吃,那么离“值得跟”就更进一步了3、在同级Leader中,有独立的人格特质: 个人自律(身体力行),情商高(办事漂亮,能合理的分配KPI)能有效引领团队拿到业务结果(不靠无脑加班提高团队绩效)4、具备独立的思考认知能力: 有自己的认知方法论,生活方法论,被团队认可的价值观明确的人生规划,能给为年轻人解惑职业问题并帮助下属晋升成长工作这些年,我在阿里的历任直接主管已经不下10位了,打过交道的主管就更多了。他们每个人的处事方式和行为水平,就像一面面镜子和对照表,在校正和指导我,帮助我对职场系统进一步定位理解和完善。 未雨绸缪,提前丰富自己的能力矩阵,早晚有一天,大家都会被组织,赋予管理某一块业务的职责,那时,各位就都会增加一个新的职业头衔 - “Leader”。 少些吐槽,多些精进,始终并持续关注自身的不断成长,选择性忽视那些“即使吐槽但也没用”的精力浪费。理解好一个Leader对组织的意义,对业务的意义,对下属的意义,努力成为一名有好口碑的Leader,并最终成为一名“值得跟”的Leader。 不知大家看完这篇文章,对管理、个人成长是否有了更加深刻的认识?是否想多学习一些关于管理的知识? GIAC全球互联网架构大会深圳站将于2019年6月举行,届时有更多关于团队管理、个人成长、微服务、软件工程的相关演讲。参加2019年GIAC深圳站不仅可以了解业界动态,同时可以和多位业界大咖近距离接触。 参加GIAC,盘点2019最新技术,8折活动倒计时 3天,多人购买更有优惠哦!快识别图中二维码抢购吧! ...

May 28, 2019 · 1 min · jiezi

论程序员的自我修养我在阿里干了十年开发

究竟是努力重要,还是选择重要?资深阿里技术人毕玄师兄有着自己的见解。 毕玄,阿里巴巴基础设施事业群负责人,资深技术专家。打造了阿里目前使用最为广泛的核心中间件之一的服务框架;设计并带领团队实现了阿里技术发展史上具有里程碑意义的异地多活。 文章不长,但值得品味。师兄的文风就和他的代码一样,简洁洗练。 2007年年底,我入职阿里。工作十年,我看到了各种各样的程序员,也看到了各种各样的成长路线,说说自己的一些观点吧。 第一阶段:拓展视野,择一深入 作为技术人员,在刚起步阶段时,首先需要拓宽自己的技术宽度,对自己所做的项目/产品所涉及的方方面面的技术都应该有所了解。 另外就是学习工程化,让自己真正具备开发商业软件的能力。 在工程化和知识宽度达到一定阶段后,根据自己的兴趣和工作内容有所选择,主要是加强在某一领域的技术深度。 第二阶段:自我评估,选择方向在技术深度达到了一定阶段后,需要对自己做出一个判断,就是更适合偏业务方向,还是偏基础技术方向发展。 偏业务方向的技术人员,我认为做的好的表现是: 1、对业务发展的未来有一定的预判,有商业敏感意识; 2、能对复杂的业务进行合理的抽象; 3、在系统的设计上能对未来业务的变化有一定的预留处理。 偏基础方向的技术人员,我认为做的好的表现是: 1、能结合业务的发展趋势对基础技术的方向有一定的预判,避免业务发展受到基础技术的拖累; 2、对业界的技术发展方向有自己的认知和判断; 3、在对应的基础技术领域有不错的技术深度。 同学们可以结合自身特质以及当前情况,做出一个选择,重点发展。 第三阶段:再进一步,你需要的是… 再往更高阶走的同学,通常就会出现一种新的角色,就是成为团队leader。
做为一个技术团队的leader,无论是业务的还是基础技术的,在技术能力上还是不能差的,尤其是判断力。 另外,作为一个团队leader,就意味着承担了团队方向的判断的职责。一个团队的方向基本会直接影响到团队所有成员的未来,以及所支持的业务的发展状况。 对于团队leader,我觉得最重要的能力就在方向的判断上,然后是根据方向的判断的组织建设(团队搭建,人才识别、培养、招募等)能力。
如果不是往leader方向,那基本就是往架构师方向为多。 作为架构师,除了至少一两个领域的深度外,对广度的要求非常高。无论是业务架构师,还是基础方向的架构师,领域的知识宽度是非常重要的,意味着能做多大范围的事。 还有同样就是判断能力,判断能力会体现在架构师在做设计时如何判断重点,在有限的资源和时间情况下如何做取舍,对未来如何让铺垫,以及对事情的技术控制能力。 一个好的架构师在技术风险的控制能力上必须是非常强的,例如一个强大的基础领域的架构师,应该是可以很好的控制跨多个专业技术领域的技术演进。 除了以上两类,还有一种是往专业技术深度领域方向走,例如内核、JVM等,这些领域是真正的需要非常深的技术功底才能hold住。还会有其他例如转型往业务产品方向等发展的就不在此展开了。 总结:兴趣是最强的自驱 总而言之,我觉得在整个成长过程中,兴趣是最为关键的。 “Follow your heart”非常重要,只有在足够的兴趣或梦想的情况下才能产生很强的自驱,没有足够的自驱我觉得在技术领域基本上是不可能走到高阶的。 除兴趣外,自身的优势也要判断清楚,每个不同的方向,我自己认为还是需要一定的天分的,而所谓的天分我觉得就是对个人优势的判断。 师兄说,兴趣和梦想是他成长中最强的自驱力 阿里巴巴的故事, 也是从一群年轻人长城上的梦想开始 在很难的时候, 是什么支撑着你逆风飞翔? 本文作者: 橙子阅读原文 本文来自云栖社区合作伙伴“阿里味儿”,如需转载请联系原作者。

May 28, 2019 · 1 min · jiezi

阿里开发者招聘节-2019阿里巴巴技术面试题分享20位专家28道题

摘要: 阿里巴巴资深技术专家们结合多年的工作、面试经验总结提炼而成的笔试真题这一次将陆续放出(面试题答案将在专辑分享结束后统一汇总分享)。并通过这些笔试真题开放阿里巴巴工作机会,让更多的开发者加入到阿里这个大平台。为帮助开发者们提升面试技能、有机会入职阿里,云栖社区特别制作了这个专辑——阿里巴巴资深技术专家们结合多年的工作、面试经验总结提炼而成的面试真题这一次将陆续放出(面试题官方参考答案将在专辑结束后统一汇总分享,点此进入答题并围观他人答案)。并通过这些笔试真题开放阿里巴巴工作机会,让更多的开发者加入到阿里这个大平台。 这一次,不仅是知识的收获,还将间接地与技术大牛们做了直观的沟通,了解他们的出题思路与考察要点,并加以消化吸收,这对自己技术能力本身就是一种极大的提升。走上编程之路,不断丰富自己方能与世接轨,努力做最优秀的自己。5月21日,我们给开发者的第28道面试题。 28.请评估一下程序的执行结果?public class SynchronousQueueQuiz { public static void main(String[] args) throws Exception { BlockingQueue<Integer> queue = new SynchronousQueue<>(); System.out.print(queue.offer(1) + " "); System.out.print(queue.offer(2) + " "); System.out.print(queue.offer(3) + " "); System.out.print(queue.take() + " "); System.out.println(queue.size()); }}• A. true true true 1 3• B. true true true (阻塞)• C. false false false null 0• D. false false false (阻塞) 阿里巴巴出题专家:桃谷 阿里云中间件技术专家, Apache Dubbo PMC ,Spring Cloud Alibaba Architect,具有多年分布式以及中间件架构设计及研发经验,目前负责Apache Dubbo的研发及社区生态。  ...

May 27, 2019 · 1 min · jiezi

首次揭秘阿里巴巴中间件在-Serverless-技术领域的探索

Serverless 话题涉及范围极广,几乎包含了代码管理、测试、发布、运维和扩容等与应用生命周期关联的所有环节。AWS Lambda 是 Serverless 领域的标志性产品,但如果将其应用于核心业务,可能会遇到以下难题:(仅代表作者个人观点)首度揭秘:  要求用户以 Function 为单位进行开发,全新的开发框架,云厂商强绑定,社区主流技术栈迁移成本高;Function 启动速度要足够快,毫秒级或者秒级,这个限制对适用场景有很强的约束;Function 之间的调用通过 API Gateway,响应时间更长。本文将介绍阿里云中间件团队在探索 Serverless 过程中的思考以及正在做的事,目的是尽可能让开发者少改代码,甚至不改代码,就能具备 AWS Lambda 的技术优势。 Cloud Service Engine 云服务引擎(以下简称CSE),是阿里云中间件团队开发的面向通用 Serverless 计算的中间件产品,目的是具备 AWS Lambda 的各种优势,同时可以解决用户在使用 AWS Lambda 时遇到的难题。 什么是 ServerlessAWS 对 Serverless 定义是:(摘自 AWS 官网) AWS 无服务器平台提供的功能:(摘自 AWS 官网) AWS 的整套 Serverless 方案非常完善,但是没有解决存量应用如何迁移到 Serverless 架构的问题。仅仅是针对新开发的应用,建议用户使用 FaaS 方式开发,才有机会转向 Serverless 架构。笔者认为,要将 Serverless 架构大规模推广,必须要能有针对存量业务的解决方案。 Serverless 对云计算的价值云计算,归根结底是一种 IT 服务提供模式,不论是公共云还是专有云(以IT设备的归属不同分类),其本质都是帮助 IT 的最终使用者随时随地,并且简便快速地,获取 IT 服务,目前,IaaS、PaaS都已经做到了按需付费,PaaS 甚至做到了按请求付费,如DB,CACHE,MQ等,但是 IaaS 的付费粒度仍然是时间维度,最快按照小时付费,以分钟来交付。 因此,当下的云计算场景,应用的开发维护方式相比传统 IDC 时代的开发维护,差别还不是很大。但 AWS Lambda 提供了一种全新的开发维护方式,用户只需要写好业务代码,提交到云上,所有和机器容量、可用性、机器为单位的运维工作可以全部交给了云平台,这种模式极大的释放了云的弹性价值,真正做到了按需付费。 ...

May 24, 2019 · 2 min · jiezi