千万级到10亿+的疯涨,搜狗商业平台服务化体系实践之路

【编者按】互联网从诞生到现在,网站的规模不断扩大,存储和处理的数据量也远远超出了人们的想象,又随着对信息实时性、多媒体需求大幅增长的现象,互联网架构面临越来越大的挑战。CSDN致力于解决这一问题,在刚刚结束的 SDCC 2015中国软件开发者大会上,特举办了架构专场( 上午报报道、 下午报道),以及《程序员》电子刊10月B开设了 架构专题。在接下来也将继续深耕架构师、服务于开发者,推出更多的大牛访谈、知名互联网公司架构实践、技术公开课等,敬请期待。 

本文是搜狗商业平台服务化体系实践之路,作者是搜狗商业平台架构师么刚、搜狗高级开发工程师王宇,给你细细道来,以下为正文:

声明:本文为《程序员》电子刊11月B技术板块文章,未经允许禁止转载。 

挑战

搜狗商业平台为打造搜狗一站式营销服务平台提供基础架构支撑,支持跨平台的广告主及代理商的接入、广告投放、效果评估、策略优化以及资金管理等。近年来搜狗业务飞速发展,在线广告物料实现了千万级到10亿+的增长,天级报文量完成了百万级到亿级的跨越,而一年一度的6.18、11.11互联网狂欢也更是对搜狗商业平台的基础架构提出了严峻的考验。

从技术层面,搜狗商业平台涵盖了前端/后端框架、大数据分析、流式计算、移动研发等多个领域、不一而足。本文聚焦服务化,介绍搜狗商业平台服务化体系如何在业务规模几何级数增长的情况之下,保证系统的高性能,高可靠性和高可扩展性。

搜狗商业平台根据自身的业务特点,在力求节约成本的前提下,打造了一套完整的服务化体系,如图1所示。

图1. 搜狗商业平台服务化体系

  1. 源数据层:服务化数据来源,由不同的存储介质组成,实现基础性数据的持久化存储;
  2. 数据采集传输层:负责数据采集,并把数据由源数据层同步至缓存层。商业数据的特点决定了数据采集传输必须保证数据的可靠性和实时性;
  3. 分布式缓存层:完成对基础数据的加工,计算和分布式存储,为服务层提供高效健壮的查询服务;
  4. 服务层:通过微服务的方式,快速迭代,满足业务需求。

一、源数据层

商业平台的数据,按类型划分为:结构化数据和半结构化数据,而存储介质包括数据库(MySQL,Oracle),文件和web service接口等。由于数据源的异构性,给我们上层的服务带来三个问题:

  1. 不易维护:针对每一个异构数据源,都必须开发一套相应的访问组件,造成服务依赖关系复杂;
  2. 运维困难:运维需要维护多种存储介质,同时准备不同的扩容/缩容以及灾备预案;
  3. 性能不稳定:异构数据源的访问接口性能存在一定的差异,在某些应用场景下,会导致服务的性能表现不稳定。

为此对源数据层做了两方面的优化:

  1. 数据源统一:针对关系型数据库,我们采用MySQL作为基础数据库,逐步替代Oracle。针对半结构数据源文件和Web Service,我们从中提取出结构化数据,准实时同步到MySQL;
  2. 数据库组件统一:数据库层面统一开发一套基于mysql的高性能嵌入式分库分表框架。

二、数据采集传输层

“时间就是金钱”这句话在商业平台中体现得淋漓尽致,一个稳定可靠、低延迟的数据采集传输系统是整个服务化体系正常运转的重要保证 (数据采集传输系统在内部也称之为报文交换系统,在后文中也会用报文交换系统来统一标示)。

  • 系统介绍:

数据采集实现常用方式有两种:

  1. 应用驱动双写:应用程序同时向数据库和消息系统发起写操作,这种实现比较灵活,但是不能保证两个系统同时锁定操作,带来不一致风险;
  2. 数据库日志挖掘:从数据库日志(如MySQL的Binlog日志)解析获取数据库变更事务,这个也可以解决一致性问题,同时有较高的同步性能。但是由于现有主流数据库的日志私有性,版本升级差异较大,难以保证系统升级可用性。

在评估这两种方式优劣之后,我们采用了第二种(数据库日志挖掘)的方式,稳定可靠、低延迟是我们的首要目标(概要架构如图2所示)。

  1. 客户端从系统获取消息数据有两种方式:全量和增量。客户端第一次获取数据时,可以从hdfs上拉取全量数据加载,完成之后再切换到增量服务通道获取增量日志,刷新数据。
  2. 为了节约存储空间,只存储数据,不存储数据描述(元数据)。

千万级到10亿+的疯涨,搜狗商业平台服务化体系实践之路_第1张图片

图2. 报文交换系统概要

  • 稳定可靠:

主要从三个方面保证报文交换系统的稳定可靠:

  1. 序列号机制:报文交换系统并不需要强一致性,而是最终一致性。在日常的报文交换系统中,会产生上亿条实时数据流,一旦出现数据乱序的情况,就破坏了系统的最终一致性要求。所以我们引入了序列号机制,为采集的每一条数据都分发一个有序的全局唯一ID,保证实时数据流的有序传输;
  2. 数据重放机制:除了乱序,生产环境也可能出现数据丢失的情况。我们通过引入实时数据偏移量来解决这个问题。一旦数据出现丢失,可以通过指定任何时间点和一个偏移量,让系统自动从这个时间点+偏移量开始重放数据;
  3. 读写分离,跨机房多机部署:读写分离降低系统IO,跨机房、跨网段部署避免因网络或者机器故障导致系统不可用。
  • 低延迟:

随着广告物料快速增长,系统容量也越来越大,瞬间产生的大流量往往会造成报文交换系统的同步延迟,而一个分钟级以上的延迟都会对线上系统带来较大的收益损失。所以我们采取以下三点优化来保证系统的低延迟:

  1. 数据库采取分库分表策略存储,按用户ID水平拆分,数据并行采集;
  2. 按照报文重要级,划分为多个物理通道,通道之间不会互相干扰。一些对延迟容忍度低的可以走高速通道,一些对延迟容忍度高的可以走低速通道;
  3. 异步处理:在报文交换系统中,存在不同类型的报文,有些也需要额外二次加工处理,如果使用同步式处理的话,那这种block式的功能会非常影响系统性能。为了提高系统的吞吐量,我们把这些同步式优化成异步式,不会堵塞其他重要报文,保证重要报文的通过性,降低延迟。具体应用如图3。

 

三、分布式缓存

相对于K-V查询以及正排倒排检索系统而言,商业平台的查询逻辑要复杂的多,经常涉及到多表联合查询,全表扫描等复杂查询,传统的RDBMS方案无法满足查询的性能要求,另外,底层数据源的异构也是RDBMS难以克服的问题。为此搜狗商业平台搭建了分布式缓存系统,作用有三:1. 降低物理数据库压力,提高查询性能;2. 向上屏蔽底层数据的异构存储;3. 向上提供类sql的查询接口,支持微服务架构的快速迭代。随着业务规模的飞速发展,分布式缓存系统也遇到了性能下降,内存膨胀过快,运维困难等问题。

  1. 性能下降:主要出现在一些查询在线物料量比较大的全属性交叉运算上,运算涉及到过滤、联表、业务逻辑计算、排序等步骤。即使是内存+索引,在非常大的数据量下,也会出现秒级别的超时;
  2. 内存膨胀过快:分布式缓存是作为底层源数据的全镜像,所以随着在线物料量的快速增长,内存资源非常紧张;
  3. 运维困难:由于架构涉及组件多,相互之间依赖复杂,耦合性高,给运维人员管理运维也带来一定困难。
  • 高性能

相对于数据库,分布式缓存的查询性能已经有了非常明显的提升,但对于百万量级的复杂查询,性能仍不能满足业务需求。为此在标准SQL查询接口的基础上,对于海量数据的复杂查询,采取了预处理的方式,把结果预先计算出来并存储在分布式缓存中。这样查询时可以节省SQL语句的执行时间,从而大大提升查询性能。但是预处理方式也带来了SQL结果状态延迟的问题,为了保证基础数据的变化能够实时反映到SQL结果中,我们借鉴了流式计算的思想,当基础数据发生变化时,触发SQL语句的执行。示意图4所示。

千万级到10亿+的疯涨,搜狗商业平台服务化体系实践之路_第2张图片

  • 内存置换

数据冷热不均的现象在商业平台也表现得十分明显。通过监控我们发现90% 

左右的查询请求集中于10%的热数据。从节约硬件成本的角度出发,我们在分布式缓存系统中增加了内存置换的设计。通过极小的查询性能的损耗,节约50%以上硬件成本。

  1. 内存置换算法:系统默认的内存置换算法是标准的LRU算法,可以很好的支持目前绝大多数的业务场景。为扩展性考虑,也可以通过配置选项,方便的支持LRU+LFU,LRU+对象大小等复杂置换算法
  2. 置换策略:通过监测内存使用的上下水位线,采用异步置换的策略,将内存使用率始终维持在安全水平。
  3. 数据预加载:对于节点冷启动的情况,为了防止初始化时大量访问未命中,穿透缓存到底层系统,可以采用预加载机制,提前把指定客户数据加载到缓存。

内存置换示意图如下图5 所示。

  • failover和可扩展性
  1. 主从双集群架构:分布式缓存采用主从双集群架构,集群中采用多分片方式存储。提供多路访问通道,降低单机故障的影响范围;
  2. Failover访问中间件:分布式访问中间件引入自动探测机制,当一次访问调用探测到某路访问通道存在异常时,会自动切换到备选通道中。
  3. 自动sharding:在水平扩展存储容量时,通过热缓存更新机制,将新分配的请求路由新节点上,就可以做到在不停服务下数据自动迁移。

四、服务层:

在搭建分布式缓存的同时,我们也注意到服务层存在较复杂的耦合关系,这也给服务化体系正常运转带来一些潜在风险。我们更需要一个松耦合的服务层。所以我们提出了微服务化。

微服务化:主要对分布式缓存上游服务进行解耦。目的是将一些功能模块单独做成一个个服务。我们可以为每个服务选择一个新的适合业务逻辑的,业内比较成熟的存储方案,比如Redis、MongoDB等,最终形成一个松耦合服务生态系统。这样做的好处是显而易见的:

  • 耦合性低:首先我们可以根据业务类型(读多还是写多等)、数据量来决定使用哪种类型的存储方案,这样可以减小内存缓存和单个数据库的负载,同时也可以避免升级单个服务而影响全局的问题。
  • 存储和计算隔离:计算和存储服务化隔离,避免存储节点嵌入过多的业务逻辑计算,提高存储节点的存储能力和吞吐量。同时避免了计算节点有状态,有利于提高计算节点的计算能力和高可用性。
  • 快速迭代:优化核心功能,迁移边缘功能,降低整个系统的复杂度和开发成本。实现方案是将每个大任务/系统拆解成一个个的较小任务/系统,使每个任务/系统做到足够轻量级和友好,每个任务/系统之间松耦合,能够快速迭代。

总结

搜狗商业平台服务化体系承担了物料存储、广告展现、数据分析到效果反馈等重要功能。在业务快速发展背景下,如何保证系统的高性能、高可靠、高可运维、高灵活性成为我们面临的挑战。

通过源数据层统一,搭建稳定可靠、低延迟的报文交换系统和高性能的分布式内存,以及微服务化的打造,初步完成商业平台服务化体系的建设,并成功支撑了在线物料量日增长上千万级的业务发展规模。经历了整个搜狗商业平台服务化体系实践过程后,有以下几个经验心得:

  • 敢于做减法:大道至简,在一个臃肿的系统上继续加功能只会加重这个系统的负担,更不利于系统的升级维护。要敢于做减法,提取出每个系统的核心功能,减掉旁枝末节的功能。比如我们会实时监控每个系统功能的运行状况,包括响应时间,调用次数等。并定期去清理一些低pv或者重要性偏低的系统功能,保持系统轻量级;
  • 微服务化:传统服务架构上面搭建了非常多的应用,就像是一块铁板,笨重且不可拆分,系统中任何程序的改变都需要整个应用重新构建和部署新版本。另外传统的整体风格的架构在进行水平扩展时也只能整个系统扩展,而不能针对某一个功能模块进行扩展。而微服务架构可以完美的解决统一风格架构所遇到的种种问题。微服务架构将系统以组件化的方式分解为多个服务,服务之间相对独立且松耦合,单一功能的改变只需要重新构建部署相应的服务即可;
  • 不放过每一个细节:细节决定成败。在对系统进行优化时,要仔细评估任何一个微小的细节。比如细粒度锁的选取,数据结构的选型,内存池、连接池设计等,这些细节处理的好,会带来意想不到的收获。另外,在升级过程中,时时刻刻保留有计划B,确保系统最终结果在可控的范围。

你可能感兴趣的:(千万级到10亿+的疯涨,搜狗商业平台服务化体系实践之路)