[.com原稿]从单体程序到微服务,再到现在流行的服务网格概念,Spring连接了这两个时代。它曾经是单体程序的代名词,但在微服务时代重生,给我们带来了SpringCloud。借助SpringCloud,苏宁大数据中心完成了微服务架构的改造。在实践中,这并非一帆风顺。解决问题有思考,有困惑,更有乐趣。为什么微服务?为什么是春云?苏宁数据中心的后台是传统的开发架构,VIP负载均衡+Nginx+SpringMVC,代码以单体程序为主。一般情况下,一个项目使用统一的域名。在苏宁现有的开发架构下,统一域名导致后端只有一个war包,程序成为单体程序在所难免。下图是一个典型的老式项目代码目录:项目名-web:外部war包模块项目名-接口:统一定义的接口项目名-service:统一定义的接口,实现整个项目的管理和开发思路,开发围绕单个程序模型设计的弊端很明显:代码职责不明确,大家在同一个模块下提交代码,违背了高内聚和低耦合。业务拓展不便。第一,微服务的思想并不高大上。我们为什么选择微服务?主要原因是管理问题。结合苏宁已有的开发架构,整个微服务架构如图:域名解析+VIP负载均衡+Nginx+服务网关+各种服务。下图是一个项目采用微服务后的工程代码目录:项目名称-模块1项目名称-模块2整个代码目录更加清晰,有利于模块拆分和人员职责安排。数据中心项目背景介绍苏宁数据中心是一个大型项目群:OLAP是底层加速和查询引擎,底层支持Druid、ES、PGCitus集群。它与Presto类似,但与Presto不同的是,OLAP会主动对数据进行预立方。加速。百川是指标平台层,允许用户对指标进行建模和定义,对外提供指标查询服务。百川支持的主要建模方式是:星型。数据建模自然离不开维表维度。UDMS系统用于定义和管理所有维度和维度表。目前已收录全集团近200个维度,对外提供维度及维度表信息服务。天宫是一个类似Tableau、Superset的可视化报表设计平台。与这些BI软件最大的区别在于,天工基于百川的指标和UDMS的维度做报表,数据来源已经高度标准化和规范化。目前的商业报表分析工具:Cognos、AliQuickBI等,结合了数据建模和可视化设计能力,这是天工和他们最大的不同。慧眼是一个统一的报表入口,所有的报表发布到慧眼进行业务。慧眼最大的挑战在于报表权限的控制和自动匹配。总共有4000多个报告,有20000多个用户。一份报告对8,000多人开放是很常见的。这些都依赖人工维护,容易出错,不利于数据安全,不能及时响应用户需求。这些都是慧眼系统需要解决的问题。微服务框架选择Dubbo架构介绍Dubbo主要有四个模块:Monitor(监控)Regsitry(注册中心)Provider(服务器)Consumer(消费者)Provider向Regsitry注册服务,Consumer向Regsitry订阅服务信息,Monitor服务监控服务调用。整个服务调用流程如下:消费者在本地发起服务调用。动态代理将调用发送到Loadbalance模块。Loadbalance从Registry中获取服务实例信息,向服务实例发送请求,记录监控日志等信息。SpringCloud架构介绍SpringCloud的整个架构和Dubbo非常相似:Eureka(注册中心)Gateway(服务网关)Provider(服务端)Consumer(消费者端)Zipkin(监控)区别如下:SpringCloud是一个HttpRest接口,但Dubbo没有。SpringCloud注册中心没有使用Zookeeper,而是使用自研的Eureka。关于Zookeeper是否适合作为注册中心,可以参考文章:《Eureka! Why You Shouldn’t Use ZooKeeper for Service Discovery》,《阿里巴巴为什么不用 ZooKeeper 做服务发现》SpringCloud提供了Gateway网关组件。兼容Spring生态,丰富的生态链,自定义过滤器和拦截器增强功能,如:权限验证,日志打印等;SpringCloudNetflix提供了熔断器、限流等组件。基于以上几点,考虑到统一的架构和未来的发展趋势,我们选择了SpringCloud。SpringCloud主要帮我们做系统内部的服务,REST接口形式不会破坏已有的服务,前端服务调用不需要调整。选择SpringCloud的另一个重要原因是Dubbo和苏宁RSF服务框架高度重叠。在对外服务接口方面,我们还是以RSF接口为主。基于SpringCloud的服务实践整体架构介绍整体有几个组件:注册中心、服务网关、服务监控、负载均衡器。注册中心使用SpringCloud提供的Eureka,服务网关使用SpringCloud提供的Zuul组件,负载均衡器使用Ribbon组件。服务网关的负载均衡策略为:WeightedResponseTimeRule,根据服务器响应时间路由到哪个节点。服务监控组件用于监控服务性能和调用状态。最重要的一点是将整个服务链路串联起来。服务监控设计监控是一个系统的眼睛,是绝对不可或缺的一部分。Zipkin提供了很好的服务链路监控。结合自己的使用场景,最终没有选择Zipkin。为什么?首先了解Zipkin的整体架构:数据采集(Brave、Sleuth)Tranport数据传输(支持Kafka,直接发送到Collector)Collector(数据采集)Storage(存储:ES)Search+Webui(监控展示)整体架构如图在下图中。Zipkin监控数据格式如下:Zipkin有以下缺点:我们不仅仅监控SpringCloud服务调用,比如:苏宁RSF服务调用,SQL执行时间,本地方法执行时间等,监控数据格式不符合业务需求。Collector节点容易出现性能瓶颈,ES聚合查询性能差。跨线程,不能连接链接。基于以上几点,我们决定开发自主研发的服务链路监控系统。整个系统架构如下。我们原则上使用Kafka和Druid来提供最大的可扩展性。Druid对应Zipkin中的角色:Collector(数据收集)+Storage(存储:ES)。我们根据业务需要设计了监控日志格式,如下图所示:一个调用链接具有相同的根ID,服务名由三部分组成:系统名、一级名、二级名、一级名称。有7个值:url:http接口url-call:调用http接口rs:rsf接口rsf-call:调用rsf接口sql:executesqlcache:operatecachemethod:localmethod你可能会问,如何在不存储的情况下判断一个链接父ID中的父子关系?这里我们设计了一个特殊的事务ID生成规则,可以通过事务ID本身来判断父子关系,如下图:下图中监控系统的链接展示页面:基于Hystrix的熔断设计Hystrix对应的中文名字是“虎猪”,豪猪全身长满刺,可以抵御天敌,代表一种防御机制,这与Hystrix本身的功能不谋而合。因此,Netflix团队将框架命名为Hystrix,并使用了相应的卡通形象作为Logo。在分布式系统中,很多依赖必然会失败,比如超时、异常等,如何保证在出现依赖问题的情况下,整体服务不会失败,这就是Hystrix需要做的事情。Hystrix提供了熔断、隔离、Fallback、Cache、监控等功能,可以在一个或多个依赖同时出现问题时保证系统仍然可用。使用Hystrix非常简单,只需要添加相应的依赖即可,最方便的方式是使用注解HystrixCommand:fallbackMethod:指定Fallback方法threadPoolKey:线程池名称threadPoolProperties:指定线程池参数(线程池大小,***queuequeuenumber)commandProperties:CIRCUIT_BREAKER开头的参数配置断路器相关参数,METRICS_ROLLING开头的参数设置与索引计算相关的参数定义,参考类:HystrixPropertiesManager@RestControllerpublicclassHystrixTest{@RequestMapping(value="/query/user/name",method=RequestMethod.GET)@HystrixCommand(fallbackMethod="getDefaultUserName",threadPoolKey="query_user",threadPoolProperties={@HystrixProperty(name=CORE_SIZE,value="10"),@HystrixProperty(name=MAX_QUEUE_SIZE,value="10")},commandProperties={@HystrixProperty(name=CIRCUIT_BREAKER_ENABLED,value="true"),@HystrixProperty(name=CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value="1000"),@HystrixProperty(name=CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value="25")})pstaticStringID{UserNamesExThread.sleep(-1);returnuserID;}publicStringgetDefaultUserName(StringuserID){return"";}}基于服务网关Zuul实现的广播功能,有时我们希望url请求被所有服务实例执行。这里我们对Zuul进行了修改,增加了一个BroadCastFilter,在url请求头中将gate_broadcast设置为true,那么这个请求就会被转发到所有的服务实例。实例封装了所有实例返回的结果,以及返回微服务带来的问题。服务拆分的粒度不容易把握。SpringCloud的微服务有一个ServiceId的概念。通常一个war包对应一个ServiceId。这个ServiceId下可以有多个服务。粒度拆分方式主要有:水平拆分和垂直拆分。垂直细分主要有以下几种方式:按功能划分,如用户管理、指标管理、模型管理等。按角色划分,如管理员、商户、用户。水平切分一般用于提取公共基础服务,如:用户名密码验证服务、用户基本信息查询。运维和开发的复杂度增加。在单一程序时代,只有一个战争包。微服务鼓励服务拆分,战争和部署节点的数量大大增加。另外,一个流程往往由多个分布式服务完成,这带来了很多棘手的问题:需要通过分布式事务来保证数据的最终一致性,防止单个服务出现问题造成雪崩。要求。调试难度增加。微服务方式鼓励服务拆分,通过服务间依赖完成功能,给开发和测试带来挑战。合理选择两种方案:微服务和代码复用。后续的架构演进服务版本控制没有版本控制,也就是说我们不能做灰度发布。破坏性版本发布后,无法兼容旧版本。下图是服务A、B、C、D的版本依赖关系:我们的实现思路是改造Zuul:标记版本标签,在Zuul中判断访问来源(比如查询接口版本对应App版本5.1为2.1),标记版本标签,根据版本信息基于Gateway服务路由到对应的版本服务实例熔断和限流机制目前有一些开源框架如ratelimit,通过以下方式实现限流熔断向Ruul添加过滤器。但是有几个问题:不支持动态配置不能满足业务变化,比如有版本控制综上所述,我们开始了一些自研工作,可以更贴合我们的业务场景。总结从2016年到现在,两年时间,苏宁大数据中心从传统的单例开发模式转向基于SpringCloud的微服务开发模式,找到了一条适合自己的路子。这不仅仅是技术框架的切换,更是开发思维的升级。令人欣喜的是,SpringCloud这两年发展迅速,并在2018年发布了革命性的2.0版本,这离不开社区的支持。许多像Netflix这样的公司正在努力为SpringCloud生态系统做出贡献。基于SpringCloud,我们开发了一些服务于自己业务的组件,让我们意识到自己也有能力和责任回馈社区。任重而道远,好的架构一定是适应业务发展的架构。这不是Spring的结束,也不适合我们。作者:王福平简介:苏宁易购大数据中心数据中台技术负责人,曾任百度大数据部高级工程师,1号店搜索与精准部架构师。多年来一直从事大数据的研发,对大数据工具和机器学习有深刻理解,有丰富的实时计算经验,对Storm和SparkStreaming有深刻理解。热爱分享和技术传播,目前关注数据分析平台建设,旨在连接数据建模和数据分析,基于Druid、Kylin等OLAP技术,提供平台级数据索引服务,打造“数据即服务”一站式解决方案。【原创稿件,合作网站转载请注明原作者和出处为.com】
