奶奶从路边捡来一只小鸡。它总是喳喳的叫,但是周末我坐在那里的时候,它就会蹲在我脚上,很安详的样子。然后小鲜肉就过来说:麻麻,我好想吓唬它。小鸡被吓的到处乱串。我说了挺多话没法让小鲜肉停下来。我就叹了口气在那里看着。一个5岁的孩子本来就不具备换位思考的能力。还有一个问题,我其实根本不知道小鸡是怎样想的。只是觉得它趴在我脚上的时候很安心很安静。晚上下班我会把手伸到笼子里陪它待一会儿,因为我想它是很想自己的妈妈的。

  本文首发于静儿1986的博客,原文地址是http://www.cnblogs.com/xiexj/p/6874654.html

  先说说我们部门的业务。我们部门掌管乐视网所有的视频音频等最核心数据的信息。所有子业务都围绕着这个核心数据。最笼统的分可以分为两块:读和写。

  读数据除了直接依赖DB的内部操作之外,就是直接通过http请求的RPC调用。因为调用这个接口的业务方非常多,他们用的语言和技术非常杂,http有更好的通用性和便于运营人员等不懂技术的人排查问题,只能内网访问,也很安全。这是部门并发量最大的服务。单台机器QPS一般在2k多,低谷时在1k多,高峰时在3k多。线上11台接口服务器同时工作。但是读数据为了提高并发量,将全量的视频和专辑数据存在了memcached缓存里。所以一旦其他业务方更新了数据会直接发送MQ消息给读数据服务,读数据服务更新了缓存后要给业务方回复消息。

  读数据还有一种被叫做离线数据推送。这是由于像搜索部门这样的,需要所有视频相关的全量数据,不合适通过接口访问。之前用的是他们直接依赖我们的数据库镜像。但是这样我们这边要进行数据库改造,分库分表或者其他的表结构修改,就要通知各个依赖业务方。所以我们就改用定时全量数据推送给他们和MQ实时数据发消息的方式进行解耦。

  还有一个面向所有部门同事的服务,就是统一异常平台。部门的所有子业务的异常都会异步发送到统一的Redis中。可以在一个公共的平台统一查看。对于特定业务的,会给特定的同事发出告警邮件。

  写数据的业务方非常多,我们部门也有。其他部门也有。写数据就是创建,修改和删除。写数据QPS很低。

  创建时不仅要走我们这边,还要调用云存储,云转码等其他部门的接口。具体流程可参考之前的一篇文章:《一个请求过来都经过了什么》

  修改是走我们部门内部系统或者调用我们的API。

  删除只能走我们部门内部系统,删除接口目前不向其他业务部门开放。

  我自己目前主要做的就是读数据的部分。离线数据算是我开发的,其他人是拷贝的我的。目前正在进行RPC接口的改造。写我也做过。PGC项目是专业用户进行视频上传的,当年是我做的。这是一个平台。我做过数据接入。就是我们购买一些版权的公司将他们的视频的介质和媒体信息直接ftp放到我们服务器上,或者给我们一种调用方式我们自己去取,这种属于后台服务。我也维护过我们的视频后台系统。是我去美国做数据接入的时候,美国运营同事总是过来找我说我们系统的问题,由于时差,我只能自己动手改了。

  后台服务可以自己想怎么写怎么写。其他的,不管是读接口,PGC还是后台系统都是采用的SOA架构将业务垂直分解为前端(对于平台来说就是和界面打交道的,对于读接口来说就是业务方调用的),使用Dubbo来调用数据服务。基于这种设计,一个子业务的代码基本模块都分为API模块,WEB模块(读接口无此模块),common模块(一些公用工具或者公用POJO), client模块(dubbo服务的接口),service服务(dubbo服务的实现,即服务提供者)。

  简单介绍一下Dubbo:Dubbo是一种透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。实现了软负载均衡及容错机制,服务自动注册与发现,能够平滑添加或删除服务提供者。

 

  下面是今天的重点,吐槽一下我们目前读接口的架构不合理(当然不合理是很正常的,这是一个为期三年的古董),我们新方案已经设计好了。

  读接口业务简单,并发支持需求大。如果说采用Dubbo层是为了与业务分离,提高服务的复用率,提高数据的统一性。目前一个子业务就自己弄一套Dubbo。有API和WEB两个对前端业务的也将就起到作用了。读接口就是一个api调服务,有啥复用的啊。Dubbo的读接口采用默认的阻塞模式,高并发的情况下Dubbo就会成为性能瓶颈。

  业务方可以进行数据的更新,他们更新DB后还要维护我们的缓存。我们的缓存采用的乐视统一的CouchBase集群。CouchBase是Memcached的升级版。既然是走Memcached协议,那么就可以使用Moxi代理来提高性能。

  简单介绍一下Moxi:它基于memcached开发,对于并发的gets请求,做合并来减少和memcahed server的交互。对热点访问的cache会在本地缓存,减少network hops。network hops就是网络路由跳数,距离目的网络所经过的路由器数目。对于某种类型的key,可以异步set。可配置超时时间,也有错误重试机制。

  各个业务线反馈说Memcached不好用,有性能问题。好多业务线自己换成了Redis,解决了好多神奇问题。撇开这些数据不谈,给你一个用Redis而不用Memcached理由:Memcached的各种强化和代理Memcached自己都可以做,但是没有做。Redis却在不断的更新和优化。

  还有一个专门维护这个缓存数据一致性的服务。我个人觉得我们系统过分的强调了一致性,却牺牲了性能。下面是一些基本的理论:

  分布式领域CAP理论:

  • Consistency(一致性),数据一致更新,所有数据变动都是同步的。
  • Availability(可用性),好的响应性能  
  • Partition tolerance(分区容错性)可靠性。

  定理:任何分布式系统只可同时满足两点,没法三者兼容。

  忠告:架构师不要将精力浪费在如何设计能满足三者的完美分布式系统,而是应该进行取舍。

  一致性模型:

  • 强一致性
  • 单调一致性
  • 会话一致性
  • 弱一致性
  • 最终一致性

  BASE理论(CAP理论的延伸):

  • 基本可用(Basically Available):允许损失部分可用性,保证核心可用
  • 软状态(Soft State):分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的提现。mysql replication的异步赋值也是一种体现。
  • 最终一致性(Eventual Consistency):

  核心思想:即使无法做到强一致性,但是应用可以采用合适的方式达到最终一致性。

  像我们常用的分布式存储:mysql的主从读写分离,redis缓存的master-slave形式的主从复制都是基于操作记录的,都会有时延,也就是保证最终一致性而已。

   

  题外话:基本的理论和名词概念是很实用的。比如在之前公司做搜索引擎的时候,搜索引擎需要分词,分词的分词组件叫Tokenizer。这个不是搜索引擎特有的概念。Java的rt.jar这个最基础类库里有StringTokenizer和StreamTokenizer。如果你了解了这个,就很容易理解理解搜索引擎的分词是干什么用的。

  

  再说我们项目中过分强调数据一致性而损失性能和高可用的事情。完全可以不对一致性不那么精益求精。这并不是说不追求完美。追求完美可以提现在哪些方面呢?

  之前做的一个信用名片的项目,有的用户在某星手机的某些版本中上传头像,上传之后头是倒着的。经调查发现我们拍的照片在手机上可以各个角度拍摄,凭借着EXIF信息,这是一种专门为数码相机设置的格式。里面有拍摄时翻转手机的信息,可以有8种角度。很多操作系统和图片查看软件都会自动按照信息里的翻转角度,将图片翻转回来。但是某星的某些版本没有这个功能。针对这个问题,开始的时候,我用了一个国外的元数据萃取的工具包将这个EXIF信息的翻转信息提取出来。效果已经达到了。但是作为代码手艺人,觉得只是这么个小需要就添加了一个1MB多的jar包,而且实际上它的实现是解析构建DOM树的方式,意味着为了提取翻转信息,要解析构造整个文件对象。所以我自己又采用了直接读取图片二进制流的方式,取图片前面如果以0xFFD8开头的就是包含EXIF信息的,否则不予处理,读取文件结束。以0xFFD8开头的要判断是否包含旋转信息,包含旋转信息的判断是Intel标准还是Motorola标准,因为这两个标准高字节和低字节代表的含义正好相反。就这样一直到读到旋转信息或者判断出不存在旋转信息,文件关闭。所以最后读入的文件数据很少,效率大大提高。

  在之前公司用Solr搜索引擎的时候,有个需求是过滤输入的html标签。但是在Solr中对索引读入后的第一个操作就是分词,使用Solr自带的或者外部的分词器。然后再对分好的词进行更细节的过滤或者近义词之类的。但是这第一步就直接破坏了文档的结构,变成了一个个单词,而不是html文档形式。再去除,可以去除,一个个过滤符号和单词是否是html标签,判断前后都是啥。能做,第一,麻烦,最重要的是效率低。所以我当时的做法是直接修改了自己用IK分词器的源码,读入数据第一个操作先过滤标签。这就很好办了,apache有现成的工具类。这样避免了读入读出带来的性能损耗。

  

  说了这么多,架构到底是一个什么概念。我个人理解,在一个组织和系统内可以有很多维度的架构。

  比如业务架构是我们老大要考虑的事情。他心目中有一个自己的业务架构定位,外面提了一个需求,他有自己的规划,这个是不是应该纳入我们的业务体系。

  比如系统架构是管理者和架构师一起进行考虑的事情。业务定好了,那么用怎样的模块去划分这个业务更利于维护,更高效。

  比如技术架构是架构师的最重要责任。真正从技术角度去展示一个系统,包括硬件的,软件的,抽象的,具体的。它包括网络,服务器,第三方产品使用和调用,软件架构和数据架构。

  比如软件架构是开发人员可以接触到的软件开始的部分。比如一个web系统从nginx反向代理开始到一个SOA架构的系统:包括resin服务,resin服务上有一个mvc架构的程序,调用另一个服务的系统,系统又和缓存,数据库,消息队列,第三方调用打交道。

  比如数据架构,这个之所以单提出来是因为数据是服务的核心。比如对一个WEB应用来说,有一些数据是直接可以放到客户端的,如JS,静态页面。还有一些数据是要放到服务端的。服务端的数据又要考虑是放在缓存还是数据库还是文件等等。放在什么地方要综合考虑效率,带宽,安全,数据有效性和可靠性。

  

posted on 2017-05-23 21:04  编程一生  阅读(6185)  评论(27编辑  收藏  举报