从 LAMP 到框架式开发的 SOA:土巴兔 8 年架构之道

lyf2254 7年前
   <p>关于架构,我认为:架构没有好坏之分,只有合适的才是好的。架构不是设计出来的,而是摔打出来的。“ <strong>物有本末,事有终始,知所先后,则近道矣</strong> ”,这里跟大家谈谈土巴兔网站架构之道。</p>    <p>今天跟大家交流的架构之道,这个“道”其实包含两个含义:一是土巴兔网站架构的衍变历程;二是在这个历程中我们悟出的一些思想。</p>    <p>我把土巴兔网站架构演变分成三个阶段:</p>    <p><img src="https://simg.open-open.com/show/0b5fe9037821c18e1800443704449c40.jpg"></p>    <p><strong>第一阶段</strong></p>    <p>2008 年 ~ 2014 年,关键词:LAMP、裸奔</p>    <p>土巴兔 2008 年成立,刚开始的时候是一个非常简单的基于 LAMP 网站 (Linux + Apache + MySQL + PHP)。 LAMP 是开源的技术,建站速度快,开发成本低。土巴兔做的是装修 O2O,业务特点是线下业务复杂、流程长、变化快,业务和产品都需要不断试错,技术要快速支撑。</p>    <p>到 2014 年,网站也逐渐变成了下图的架构:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/9513fa11f9c98ff88b1e2c38bd2dff9b.jpg"></p>    <p>简单去看,架构主要分成三层:代理层、 Web 层和数据层。 代理层主要做的是负载均衡, Web 层负责对请求进行处理交给 PHP 进行页面渲染, PHP 做了数据访问、业务逻辑和页面展现三件事。数据层我们也做了一些数据库高可用。比如 MySQL 的双 master 多 slave 的架构,运维成本非常高。当时就一个运维,二十几个工程师。</p>    <p>随着业务的发展, C 轮融资,团队快速扩张,各种各样的业务代码(不管是网站还是 CRM)都往主站里塞,这样的架构存在非常明显的问题:</p>    <p><strong>第一,性能问题。</strong>整个网站每个请求直接穿透到 DB,没有系统化的缓存体系。 比如当时 CRM 后台一个项目查询页面耗时一分多钟是很常见的事,严重影响工作效率。</p>    <p><strong>第二,可用性问题。</strong>由于代码和数据的紧耦合,任何一个数据库慢查询,都会导致 PHP 进程堵塞, PHP 进程快速堆积,最终往上层蔓延导致整个网站打不开,造成雪崩。</p>    <p><strong>第三,安全性问题。</strong>我们网站对于安全防御几乎等于裸奔,事实也证明了问题的严重性,随着之后 2015 年土巴兔在行业内逐渐崭露头角,行业内竞争对手的恶意攻击 ( 例如 DDoS、 CC 攻击 )、乌云等第三方网站都暴露的安全漏洞尽出(例如 SQL 注入、 XSS 跨站脚本)。这些都对网站安全提出了极大的挑战。</p>    <p>当时我们的机房在广州,时不时被攻击一下,导致网站打不开。IDC 机房的服务质量也比较差,更为严重的问题,不只是我们被攻击,同机房的其他网站被攻击我们也会受到牵连。俗话说,人怕出名猪怕壮,当时技术现状堪称是内忧外患。</p>    <p>最后,可维护性差,开发低效。代码和数据的重度耦合,业务上但凡需要有一个流程或规则的变动,需要从头到尾整个链条式、大规模地改代码。维护成本随着业务数量的增长呈指数级增长。即使到今天,整个 Web 层的代码依然耦合性非常高。</p>    <p>2014 年下半年,我刚加入土巴兔,面临这种粗放式的裸奔,我们意识到要有两手准备:首先是穿上内裤保护关键部位,其次是穿上外衣抵御寒冬。</p>    <p><strong>第二阶段</strong></p>    <p>2014 年 ~ 2016 年上半年,关键词:SOA、加固。</p>    <p>具体来说,我们主要做了这几件事情:</p>    <p>首先是组建 Java 后台团队,搭建 SOA 架构体系,搭建新版 CRM 系统,把核心数据保护起来。</p>    <p>CRM 是土巴兔背后的生产系统,其重要性就好比客服、订单系统对于京东的重要性一样,它直接影响着业务链的生产效率。刚开始 SOA 接管的就是 CRM 最核心业务,把 CRM 数据查询性能进行全面优化。</p>    <p><strong>首先要把 DB 释放出来,我们引入了搜索引擎 Elasticsearch,把复杂的联表查询全部转移到业务逻辑层和 Elasticsearch 上去做。</strong>这样的改造很基础也很重要,因为只有 DB 稳定了,上层的业务才不会挂。</p>    <p>经过 SOA 化之后,无论多复杂的查询,新版 CRM 页面的响应时间都控制在 200 毫秒之内。事情并不像大家想象地那么简单,如果从零开始架构一个系统,我相信并不会很困难,但是如果去升级一个已经在运行了好几年的业务系统,事情就不简单了。</p>    <p>当时组建的 Java 团队花了将近 2 个月才真正对业务逻辑、表结构梳理清楚(当时数据库 database 就是一个,而且有 1000 多张表,核心业务表的字段都是上百个)。尽管表结构众多不合理,也不敢冒然激进地对数据库结构进行大规模改造,只是在服务层做了封装,底层数据库基本没变,数据库根本不敢动,你不知道动的一个字段会对哪个 PHP 代码造成影响。遗憾的是,至今还没有机会和精力去对底层的数据进行分离和重构,很多业务还是 PHP 直接访问数据库。</p>    <p>其次,对网站高可用进行加固,代码部署分离,接入公有云防护和云缓存,建立多级缓存体系。</p>    <p>经历了 CRM 改版之后,我们深刻地相信,重构一个业务快速发展的网站后台难度是巨大的,尤其是当你每天还承载着 400 万 UV 以及你带的队友大多是一群刚毕业没多久的生瓜蛋的时候。因此,对网站的加固,主要还是从运维的角度出发去做。大家写过 PHP 的应该都知道, PHP 处理一个 Web 请求是同步调用的,处理完就释放一切资源(例如 DB 连接、缓存连接等)。同步的方式编码很快,但是问题也很明显,但凡后台一个服务阻塞,那么这个请求也就阻塞直到超时。</p>    <p>在这种情况下, 一种方法是把业务处理异步化,减少系统之间的依赖阻塞。 但是异步化对技术的变革太大,我们只对部分关键业务做了异步化。</p>    <p><strong>我们选择了另外一个种方法,那就是进行分离。</strong>分离有几个维度:读写分离、动静分离、业务分离。网站的代码和 CRM 代码分开部署。网站浏览类页面和用户发招标域名分。隔离的好处很明显,一个业务挂了不影响全局。网站大多数是读请求,只有很少部分用户会注册登录和进行操作。</p>    <p>基于读写分离和动静分离,我们使用了第三方云防护,结合自身的缓存体系, 建立了一套从云缓存、 CDN,到代理层缓存,再到 PHP 静态化缓存,再到服务层的 Redis, es 的多级缓存体系 。简单地说,从用户出发,对流量进行层层过滤,最终到达数据库的只是非常小的一部分(不到 1k 次请求/分钟)。同时,云端页面缓存是分布在全国很多节点上的,可以有效地抵抗 DDoS 类攻击。经过了这一轮的加固,即使网站内部全部挂了,网站经常被访问的热点页面还是能打开,并且用户还是可以在土巴兔登记手机号码。使用云缓存还有一个好处就是,网站的首屏时间已经降到 100 毫秒一下,跟淘宝和京东达到了同一水平。</p>    <p>除此之外, <strong>建立了一套线上全网层次化的监控体系</strong> ,从前端的页面的性能、可达性监控、到后端服务层的波测监控,配合脚本自动故障转移,自动化告警(短信、微信、语音呼叫)。同时,针对乌云等网站暴露的漏洞,我们自研和运营了一套应用防火墙 (WAF) 系统、代码检测系统。 WAF 是通过部署在代理层 Nginx 服务器上的 Lua 脚本实现,每天防御恶意攻击数据: 20 万次左右,并且防御规则持续运营。对于机房建设,我们也进行了大规模的升级,核心机房从广州迁移到北京,南方机房作为备份机房。</p>    <p>因此,第二阶段的网站架构如下图:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/cbc36e12d2da120b2ceb48c9ca189ff7.jpg"></p>    <p style="text-align: center;">从这个图大家也可以看到,最上面第一层是公有云层,包括网宿 WSA 页面缓存、腾讯云页面缓存和 CDN。第一层基本上挡掉了大多数的流量。再往下,当页面缓存失效时,云端会往下回源到代理层。代理层部署了 WAF 和页面缓存。代理层的页面缓存也会多虑掉一部分流量。再往下就是 Web 层,再往下是 SOA 服务层。当然目前 SOA 做得还不是很完善。从这个图中大家也可以看到有块空白地方, PHP 穿透服务层直达数据库,这是架构设计不允许的。同时服务层也非常乱,服务治理做得还不够,这也是后面要努力去优化的方面。</p>    <p>这里提一下负载均衡,为什么用 7 层负载均衡,代替了原来了 4 层 LVS,其实也很容易理解。 7 层 lb 是属于应用层的控制,我们要实现 WAF,必须在应用层做,网络层只能实现很简单的防护。</p>    <p>另外,之所以没有先从内部一层一层去优化升级我们的网站性能,而直接用第三方的云端页面缓存这种简单却非常有效的手段,是因为内部优化需要经历的时间会很久,耗费人力成本很高,不可能一撮而就。何为重何为轻,这是重要的技术之道。因此,我们允许短时间的服务化不彻底,因为网站高可用了,我们有足够的时间去优化内部系统。</p>    <p>事实上,业务的高速发展,也不允许在网站高可用还没做好的情况下去全面升级 SOA。</p>    <p>经过了第二阶段的不断摔打和加固,网站的可用性和安全性基本达到要求:现在土巴兔即使核心机房的服务都挂了,网站还能打开,而且首屏时间不差于淘宝京东。用户还能在我们的网站登记手机号码。但是,架构进化之路还很长,接下来我们要解决这些问题:</p>    <p>首先,人员新手多,开发效率低,技术框架如何应对人才压力?随着业务的扩张,团队快速扩张和壮大的需求跟优秀工程师比较难招的矛盾日益凸显。尤其是,我们总部落在腾讯大厦旁边,招人更加难上加难。作为一个创业团队来讲,我们做不到像 BAT 和 Google 一样,一届一届 985、 211 的优秀毕业生进来,我们必须走出一条自己的路。也就是说:我们团队要做出还不错的东西,但是我们又不能过于依赖人的优秀,我们只能依赖傻瓜化的框架。</p>    <p>其次,代码交付频繁、交付质量差。业务的变更频繁,根据统计,我们经常一周发生 200 多次线上变更。当时我们运维团队就 3 个人。在 2015 年的时候我们的压力是非常大的。交付多了也直接导致质量就变差。我们的程序员在写一个 PHP 页面的时候,经常一个异常没有处理,页面就打不开了,导致缓存回源失败。</p>    <p>另外,SOA 并没有彻底,服务也会越来越多,如何治理?虽然在第二阶段通过一些云缓存从外部做了保护,但是我们网站内部的结构还是比较脆弱。如何由内而外地对我们后端系统进行治理和加固,是下一阶段的重点。</p>    <p><strong>第三阶段</strong></p>    <p><strong>2016 年下半年以后,我们关于架构的关键词是:傻瓜化、全面服务化、流程化、标准化。</strong></p>    <p>其实在去年年底我们就已经开始思考,傻瓜化框架应该是怎么样的?土巴兔的技术 3.0 该怎么去做?</p>    <p>我们认为, 傻瓜化的框架就是让新挂蛋能很快上手做业务开发,不用学习太多,就像我们使用 iPhone 拍照,就算不是专业的摄影师,也能拍出比较好的照片。</p>    <p>傻瓜化的框架也能保证 PHP 在渲染了一个异常页面的时候,不让这个页面吐出去给用户访问到,而是自动地吐出一个哪怕历史的正常页面。</p>    <p>傻瓜化的框架可以让开发不需要关注数据存在哪里,数据是否要从数据库到搜索引擎进行同步,如何同步,如何缓存等问题,只要根据 SDK 调用就行。</p>    <p>知己知彼,方能百战不怡,我们的团队跟 BAT 的团队比,不足在于:我们的开发人员能力没那么强,团队也没那么多人;但这也恰恰也是我们优势:小的团队,可以动物脱兔,容易统一标准,统一框架。因此我们把一组能力最强的人抽出来专门开发工具和框架。用工具去武装我们的新兵。</p>    <p>企业经过了粗放式地奔跑,到了一定的阶段,就必须停下来修炼内功迎接下一阶段的挑战,就必须要去建设标准化平台。高效治理服务也是一个比较大的话题,今天的分享我并不想说太多。我只说说关于技术 3.0 之路,我们做的一些尝试和规划。</p>    <p>首先是 SOA,我们规划的 SOA 是层次化的,如下图:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/ed5fbf900ae1859cacdf4dd3fb05539b.jpg"></p>    <p>纵向来看,我们将 SOA 架构划分成 5 个层次: <strong>展示层、流程服务层、应用服务层、数据服务层、基础服务层。</strong> 横向来看,各个业务对应的服务相互独立(基础服务除外)。一般来说,每个服务都属于某个业务,一个业务定义了一组相关的流程、服务及数据。业务内部的相关流程服务具有相对的紧耦合特性,跨业务之间的服务和流程相对独立。</p>    <p><strong>展示层:</strong>展示层主要是 Web 层,主要是 PHP 这一层。</p>    <p><strong>流程服务层:</strong>流程服务层包含了跟业务流程相关的服务。</p>    <p><strong>应用服务层:</strong>定义了相对独立的业务逻辑,供 PHP、其他应用服务、或者流程节点服务调用。应用服务可以调用属于自己(一一对应)的数据服务,以及其他应用服务。应用服务提供对业务数据对外暴露的接口,对业务数据进行有效保护。换句话说,如果某个应用要访问某个业务的某个数据,必须通过这个数据对应的应用服务接口来实现,不能直接调用这个数据服务。应用服务是对我们底层数据的有效隔离和保护。</p>    <p><strong>数据服务层:</strong>数据服务是最底层的服务,它封装了跟数据交互的基本 CRUD 接口,对于上层的应用服务来说数据服务屏蔽了访问存储设施的细节,只提供抽象的访问接口。数据服务内部定义看了业务领域的数据对象,这些对象是通过业务编号 + 服务编号 + 对象名来全局唯一标识。一个数据服务只允许对应一个应用服务来访问,对数据进行了有效控制和隔离。我们可以简单地理解成数据服务层就是解决数据访问的问题,但是又是傻瓜式地访问。</p>    <p><strong>基础服务层:</strong>基础服务不属于任何业务,包含了一些公共的服务组件,例如日志服务、消息服务等。应用服务之间可以相互调用,为了简洁,图上没画箭头。</p>    <p>大家理解一下,对于 O2O 公司来讲,每天变化的其实就是业务,业务的什么东西在变?其实就是流程和规则的变来变去。我们希望下面应用服务层和数据层变得没有那么多,相对固定,而流程是可以经常变的,这就是要分层治理的原因。我们也引入了一些流程引擎、规则引擎,以技术之不变应业务之万变。在这种分层治理的架构之下,业务需要开发新的流程,只需要部署一套新的流程图,同时配合流程节点的对应的业务服务插拔到这个流程中去,流程服务聚合应用服务来快速实现我们的业务,这是我们未来希望达到的目标。</p>    <p><strong>SOA 是个很大的范畴,我重点讲讲我们如何做傻瓜化的数据服务:</strong></p>    <p>基于之前利用 Elasticsearch 来做复杂数据查询的经验,后来很多业务系统凡是有一些复杂的联表查询都开始使用 MySQL + es 的存储模式, MySQL 存原始数据,做一些简单的 KV 查询, es 做复杂的联表查询和数据聚合统计。后来业务开发的同学都要去学习 MySQL 和 es,并且还要学习如何从 DB 同步数据到 es 等重复性的事情。因此我们希望把这些建表、查询、数据同步等复杂的事情抽象出来,让框架去做,开发只管负责描述业务逻辑的数据 schema:数据结构和关系。这就是为什么我们提出傻瓜化的数据服务的思想,如下图:</p>    <p><img src="https://simg.open-open.com/show/782e64c2ca73df515412af7c3131e813.jpg"></p>    <p>与其说这是一个服务,不如说这是一个数据开发平台,通过这个平台,开发只需要定义数据 schema,我们用 JSON 去描述这种数据的 schema,这种 schema 跟 SQL 的建表语句类似,但是表达能力更强。这种数据描述是一种中间语言,可以同时转化成 SQL 的建表语句和 Elasticsearch 的 mapping 定义。从上图可以看出,其实 schema 就是类似于 ER 图,描述了对象和对象之间的关系。我们的框架会根据 schema 定义自动生成数据访问 SDK,开发只需要拿 SDK 来访问数据就行,使用例子见上图右上角代码段。其实 SDK 只是一个 HTTP 的客户端,对于数据的真正访问时在我们的数据服务中完成,所有关于数据的持久化、查询路由、缓存、权限控制的逻辑都在数据服务层做,客户端是非常轻的。 DB 和缓存、 ES 之间的同步也由数据服务平台自动完成。</p>    <p>这里重点说一下,我们如何去解决联表查询的问题呢?我们在定义 schema 的时候,会把需要联表查询的多元关系描述成一个冗余对象,例如我们有一个 Book(ID,name) 对象和一个 Author(ID,name) 对象。同时我们有一个关系表来描述两者的关系,因此我们在 schema 里定义了一个 AuthorBook 对象,里面包含 author_id 和 book_id 两个原始字段。我们的业务可能需要根据 author 的名字查找 Book。这时,我们的做法就是在 DB 的 AuthorBook 表里只存储 author_id 和 book_id 这两个 ID 字段,而在 es 的 AuthorBook 这个关系表里除了存储两个 ID 之外,还有两个冗余字段: author_name 和 book_name,同时平台保证了这两个字段跟 DB 里面 Author 表和 Book 表里面的 name 保持实时同步。为了做到这样的效果,我们在 schema 中这样描述 AuthorBook 对象:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/48ef6ae3d9e0191669eab62cbe37d916.jpg"></p>    <p>我们对字段的同步关系进行了描述,就像 DB 的外键一样,描述了 author_name 同步自 Author 表的 name 字段,利用 author_id 作为外键跟 Author 表的 ID 关联。通过这种方式,理论上能解决联表查询的复杂度,一切都变成 ES 的单表查询。</p>    <p>当然,这个数据服务平台的推广还没有大面积展开,目前还在单个业务的试用跟测试阶段,而且一个比较大的挑战就是数据同步,我们还没有做得非常强大,之后在推广过程中一定会遇到很多问题需要完善,敬请期待。当然,我们也希望等我们的平台完善之后争取能开源出来,帮助更多企业提高效率。相信使用我们的数据服务之后,后台服务的开发将会变得非常容易。</p>    <p><strong>最后再说说网页容错问题,</strong>后台数据库挂掉或者后台服务异常都会导致页面展现异常,甚至整个页面就挂了。针对这种问题我们也作了总结反思,我们有必要搭建一个能监测错误的舞台。如果说我们的网站是一个舞台,那么页面上展示的内容就是舞台上的演员和表演,我们要保证这个舞台的表演不会出错,因此我们建立了一种异常页面的检测机制。如果说这个内容不太正常,那这个舞台是不允许你上台的。当我们上线一个新的页面的时候,根据历史的页面我们做一些相似度的检测,如果发现这个相似度差异非常大,就要告警,框架就不给你上,换而去找出最近的一个正常的历史页面吐出来。我们做任何技术框架都坚持一个假设:开发会犯错,而且会持续犯错。</p>    <p>在土巴兔,关于技术架构方面的事情可以谈很多,由于篇幅关系今天主要跟大家介绍上面这三个阶段的重点,欢迎大家留言中批评指正。</p>    <p>最后我稍微总结一下,个人对技术或架构的一些感悟:</p>    <p><img src="https://simg.open-open.com/show/106459f21513185a609220dfc3406361.jpg"></p>    <p>Q&A</p>    <p><strong>提问:想了解下这种按业务划分各系统,系统间交互怎么定义?比如我们目前的问题是各业务系统协作效率不高,环境老出问题,不是版本不对就是依赖的系统不支持。</strong></p>    <p>张华杰:关于系统之间的交互,我们定义了一套标准的协议,系统之间都是通过总线进行调用,有了标准协议,只需要各团队负责维护自己服务的稳定就行了。关于版本升级,系统之间通过 RPC 调用,系统之间的兼容性问题更多的是服务 api 接口的升级,我们通过平台保证了升级的向下兼容性,另外,需要大家统一一套错误码规范。关于系统之间接口的参数合法性验证也是很重要的工作,我们利用开源自己定义了一套参数自动检验规范。</p>    <p>监控告警也是重要的一环,新系统上线必须有压测和自动拨测,以及标准的监控数据上报,否则运维是不给上线的。</p>    <p><strong>提问:土巴兔目测有 20+ 多个城市的站点,400W UV 是打到一个机房还是每个城市均衡? 方便透露一二线城市跟三四线城市的流量占比是怎样的吗?</strong></p>    <p>张华杰:我们的流量主要是分布到网宿全国 60 - 70 多个缓存节点上的,对用户都是就近访问。当然,当缓存失效的时候需要回源,回源的流量主要回到我们北京核心机房,我看了一下,峰值每秒一千多请求量。流量的话一线城市占据了 50% 以上,剩余的城市占了一半。多亏网宿和腾讯云才保证了我们核心机房的无压力。其实,对于我们这样重度依赖线下的家装 O2O 公司来说,内部 CRM 系统的流量跟 C 端用户的回源流量是相当的,因为我们每天有上千人同时在全国各地访问我们内部的 CRM 系统,以后会更多,而且会接入各种移动终端,这对于我们内部 IT 系统的优化和升级提出了更大的挑战。所以,网站的流量反而不是我们当前最棘手的问题。</p>    <p><strong>提问:如果现在回过头去看,并且你知道后续会是这个现状,会把当时的 LAMP 架构用怎么样的架构替代,来一定程度的保证后续的扩展更具灵活性?</strong></p>    <p>张华杰:如果从头来过,我们一定还是从 LAMP 开始建站。 这么做的原因很简单,创业公司一定要快, LAMP 建站成本非常低,招人门槛也低。另外,如果可以的话,建议创业公司尽量把自己的服务部署到公有云。原因很简单,也是快速有效。你不需要拥有一支很强的研发和运维班子就可以把事完成了。用别人的云平台可以大大降低试错的成本。另外,如果有可能,我还是建议尽可能把数据层和逻辑层沉到 SOA 层去做。数据这一层的规划需要非常懂业务和懂技术的人去做,至少数据从一开始就要垂直化。数据对于技术架构是很重要的环节,如果事后再去优化架构,就会发现其实架构并不难设计,但是现有数据拆离和优化才是最难的。我们当前业务有 1000 多张表,全部塞在一个数据库里,即使再牛逼得架构师,要去重构它们都是非常难的,因为我们要保证业务的持续稳定。这就是为什么我们要做傻瓜化数据服务,我们想去从数据层改造,但是将会非常艰难。这就是历史的债。</p>    <p><strong>提问:上文提到一种数据库 schema 描述的方法,这个目的是什么?</strong></p>    <p>张华杰:我们做了整个 CRM 的改造升级,在改造升级的时候我们遇到了很多的问题,例如我们 CRM 很多后台的页面,有一些复杂的联表查询很慢,把 DB 累得半死。我们把这种复杂查询都转到搜索引擎中去做,让 MySQL 只做一些简单的健值查询,因为 MySQL 并不擅长做复杂的计算。怎么把复杂查询转到 Elasticsearch 中去呢?那就需要把很多表的信息冗余到 ES 的一张表中去。并且,我们通过这种数据的映射关系,维护了 es 数据跟 MySQL 的实时同步。事实也证明了,用 ES 加数据冗余,确实可以提高实时查询的效率。这种方法逐渐被更多业务所采用,但是这样做会增加很多额外成本,例如 ES 跟 MySQL 的数据同步就比较麻烦。因此我们把 MySQL 跟 ES 的数据映射关系进行抽象描述,用一种通用的数据定义语言( DDL)去描述,也就是我们所说的 schema。具体来讲, schema 描述了两个东西:一个就是对象(包括对象的属性),第二个就是对象之间的关系。一旦定义了 schema,它可以自动转换成 MySQL 和 ES 的建表语句。并且,数据同步服务可以识别其中的数据冗余关系进行自动同步,而不需要开发自己写代码维护数据同步。我们做这个事情的目的,就是希望业务开发程序员不需要去关注数据存哪里、怎么访问、怎么建表、怎么索引等事情。他只需要把业务数据描述成 schema,我们的平台就能自动生成数据访问的 SDK。开发只需要引入 SDK 直接调用就行了。 SDK 的实现是通过 RPC 调用数据服务,一切数据访问都被收拢和隔离到数据服务中去。这么做有很多好处:</p>    <p>首先,对数据的访问进行了统一的控制和隔离。我们可以控制谁能访问什么数据,谁不能访问。</p>    <p>其次,数据服务本身是对数据访问的一种代理,我们可以在存储层做各种性能和可用性优化。服务会去判断查询应该是走搜索引擎的还是 MySQL。我们不让开发直接写 SQL 访问数据库或者 ES,这样可以减少开发犯错的机会,因为开发经常不注意写一些慢 SQL 把 DB 卡半死。如果将来 MySQL 不再适合我们的应用场景,我们也可以在数据服务层替换成其他的存储引擎而不需要改动上层代码。</p>    <p>最后,数据服务通过对数据访问的收敛和控制,提供了对数据层的运营能力。例如,之前我们开发对数据库表加了一些字段,很多年之后可能这些字段都弃用了,但是 DBA 也不知道,数据库始终保留着这些垃圾字段和数据。我们希望数据平台统计出这些信息,帮助 DBA 发现这些垃圾字段,并提示 DBA 去清理。</p>    <p><strong>提问:这个平台现在已经在用了吗?</strong></p>    <p>张华杰:其实我们已经内测了,接下来会把我们核心业务的核心数据进行升级到这种数据服务上去。但是目前数据同步模块还存在一些问题,因为数据同步服务需要根据 schema 定义的数据依赖关系来进行 DB 到 ES 的数据实时同步和冗余。这个模块比较复杂,还在改进阶段。而且,根据我们目前数据库的复杂程度,我相信数据平台的真正全面推广,并保证现有业务的平顺迁移,可能需要花半年以上的时间。</p>    <p><strong>提问:我还是不太确定可不可以达到你的期望?理论上是把这个数据搬过去,自动帮你建立索引,他什么都不用做,关键是这一点我不太确定。</strong></p>    <p>张华杰:确实这个听上去非常理想。但是你真正去了解业务的过程中,你会发现其实大多数的情况,大多数的业务都是简单的查询,没有那么多复杂的,当然复杂的也可以做。我觉得我们这个框架的目的是为了解决 80% 的问题。这个东西不是万能的,但是我们希望它能解决大多数的问题。这就是二八的原则。当然,要做建哪些索引,这些其实在 schema 里面已经描述清楚了,数据字段的类型,长度约束,来源等,甚至哪些数据只需要查 DB,不需要做 es 冗余都能在 schema 里描述,那么自动建索引理论上也是可以实现的。当然,数据同步是一个比较复杂的问题,尤其是涉及到跨业务的数据同步,同步程序必须写得很健壮很通用,这里有难度,但是这种复杂是值得的,因为开发就简单了。</p>    <p><strong>提问:复杂查询也是提供给线上访问的吗?有一个很快的响应时间?</strong></p>    <p>张华杰:对。你可以想象我复杂查询如果在 DB 里面可能要跑到秒级别,我把这些数据冗余到 ES 集群里,响应时间基本能到百毫秒以内。其实也不是什么很高深的技术,就是用空间换来了时间。</p>    <p><strong>提问:你做索引的数据膨胀有多大?举个例子,原来一台 MySQL 或者是两台 MySQL,你把它搬到 ES 里面,你是用两台还是多少台可以盛得下?有没有放大?</strong></p>    <p>张华杰:一定会放大,如果冗余得多,数据的大小可能翻好几倍,例如我们的一个核心业务数据,有大概 10 张表组成,在 es 里面除了这 10 张表自身的数据之外,还有一张集成的大表,把 10 张表的数据冗余在一起。对于我们而言,数据量并没有达到海量,历史项目加起来就是几千万级别的。我们的服务是各业务垂直拆分相互隔离的,各个数据可以平行扩展。你可以理解成,每个业务放在自己的独立的桶里,每个桶分担的量并没有那么大。之前我们访问压力大的原因是所有数据都在一个桶里。拆分之后就不会有这种问题。另外,Elasticsearch 天生就是分布式的,节点可以配置分片和复制,集群可以动态伸缩,对于数据规模的调整也是比较灵活,它不像 MySQL 那样伸缩性比较差,这也是为什么我们选择 Elasticsearch 的原因。</p>    <p><strong>提问:你刚才说的要把它变成配置化,其实对于开发人员来说是需要去了解这个配置的。以前我们做的这个事情,做实时指标的计算,实际上是把配置化变成 schema 化的。我们认为在数据统计里面是最好理解的一个语言,以前的配置化在我们自己的系统内是自己定义的一套规则,让别人花更多成本去了解这套规则,我不知道这方面的成本你是怎么去权衡的?</strong></p>    <p>张华杰:开发会花一些额外的成本去了解这种数据描述语言,但是也不完全是这样,我们通过开发一些 GUI 工具来帮助用户更快地建立 DDL,这需要一整套平台的支持 ,把规则和约束做到 Web 交互中去 ,目前这个平台已经做得七七八八了。 当你的企业使用的数据库种类很多的时候,统一的数据描述语言是很有必要的,这更多是一种思想,你学会这种思想比你学会一种标准更重要。对于开发来说,这种 schema 跟 SQL 建表语句类似,对懂 SQL 的人来说是比较容易掌握的。甚至,我们可以专门让领域专家集中去做数据的描述,这样开发就更加解放了。</p>    <p><strong>提问:我有一个问题。我现在是在一个创业公司,我们公司也遇到了被别人攻击的事情,我们公司的技术参差也是不齐,每个人都写一个后台代码,你前台的数据可能是不合法的,现在的创业公司很多都没有安全意识,你们是怎么解决这些问题的?</strong></p>    <p>张华杰:我们用了一些共有云,比如说腾讯云、阿里云,他们都有安全方面的服务,你刚才说的是应用的防火墙 (WAF),另外还有 DDoS 攻击,我觉得一些互联网巨头已经做了,只需要拿来主义。另外,我们内部自己做了一个 WAF,如果当时我早知道腾讯有的话,我们可能会先拿过来用,自己一开始不会花那么大精力去做。我们自己还做了一些代码漏洞的检测小工具。我还是建议创业公司可以考虑一下公有云,直接用就行了,先顶住,再优化。</p>    <p> </p>    <p> </p>    <p> </p>    <p>来自:http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653547771&idx=1&sn=6443b856bbed74c30aeb7d9afba17c4d&scene=0</p>    <p> </p>