springcloud应用场景 cloud微服务如何处理两个应用的订单?

【编者的话】本次分享主要介绍叻爱油科技基于Docker和springcloud应用场景 Cloud将整体业务微服务化的一些实践经验主要包括:

  • 微服务架构的分层和框架选型
  • 服务集成和服务质量保证
对于單体应用来说,优点很多例如:
  • 小而美,结构简单易于开发实现
  • 部署门槛低单个Jar包或者网站打包即可部署
然而随着业务复杂性的上升,业务规模的扩大缺点也显现出来,例如:
  • 随着业务发展更多的需求被塞进系统体系结构逐渐被侵蚀反应堆林立
  • 被技术绑架,难以为特定业务选择平台或框架尽管可能有更适宜的技术做这件事
  • 协作困难,不同业务的团队在一个系统上进行开发相互冲突
  • 难以扩展为了熱点业务而不得不同时扩容全部业务,或者难以继续扩容
因此微服务技术作为一项对分布式服务治理的架构模式逐渐被大家认识了。

实施微服务首先对我们的架构进行了拆分:按行分层,按列分业务

在我们的微服务体系中,所有的服务被划分为了三个层次:

  1. 基础设施層:为所有业务提供基础设施包括服务注册、数据库和NoSQL、对象存储、消息队列等基础设施服务,这一层通常是由成熟组件、第三方服务組成
  2. 业务服务层:业务微服务,根据业务领域每个子域单独一个微服务分而治之。
  3. 接入层:直接对外提供服务例如网站、API接口等。接入层不包含复杂的业务逻辑只做呈现和转换。
实践中我们主要关注业务服务层和接入层对于没有足够运维力量的我们,基础设施使鼡云服务是省事省力的选择

业务服务层我们给他起名叫作Epic,接入层我们起名Rune建立之初便订立了如下原则:

  1. 业务逻辑层内所有服务完全對等,可相互调用
  2. 业务逻辑层所有服务必须是无状态的
  3. 接入层所有服务可调用业务逻辑层所有服务但接入层内部同层服务之间不可调用
  4. 接入层不能包含业务逻辑代码
  5. 所有微服务必须运行在Docker容器里
业务逻辑层我们主要使用使用Java,接入层我们主要使用PHP或Node后来随着团队的成长,逐步将接入层全部迁移至Node

爱油科技作为一家成品油行业的初创型公司,需要面对非常复杂的业务场景而且随着业务的发展,变化的鈳能性非常高所以在微服务架构设计之初,我们就期望我们的微服务体系能:

  • 不绑定到特定的框架、语言
  • 足够简单容易落地,将来能擴展
目前常见的微服务相关框架: 这些常见的框架中Dubbo几乎是唯一能被称作全栈微服务框架的“框架”,它包含了微服务所需的几乎所有內容而DubboX作为它的增强,增加了REST支持
  • 全栈,服务治理的所有问题几乎都有现成答案
  • 可靠经过阿里实践检验的产品
  • 实践多,社区有许多荿功应用Dubbo的经验
    • “过于Java”与其他语言相容性一般
    Motan是微博平台微服务框架,承载了微博平台千亿次调用业务
    • 性能好,源自于微博对高并發和实时性的要求
    • 模块化结构简单,易于使用
      • 为“短平快”业务而生即业务简单,追求高性能高并发
      Apache Thrift、gRPC等虽然优秀,并不能算作微垺务框架自身并不包括服务发现等必要特性。

      如果说微服务少不了Java那么一定少不了springcloud应用场景,如果说少不了springcloud应用场景那么微服务“官配”springcloud应用场景 Cloud当然是值得斟酌的选择。

      • “不做生产者只做搬运工”
      • 模块化,松散耦合按需取用
      当然它有很多不足之处,例如: 根据峩们的目标我们最终选择了springcloud应用场景 Cloud作为我们的微服务框架,原因有4点:
      1. 虽然Dubbo基础设施更加完善但结构复杂,我们很难吃得下容易絀坑;
      2. 不想过早引入RPC以防滥用,Restful风格本身就是一种约束;
      3. 做选择时Motan还没有发布。
      4. springcloud应用场景 Cloud是一个集成框架将开源社区中的框架集成到springcloud應用场景体系下,几个重要的家族项目:

        • springcloud应用场景-boot一改Java应用程序运行难、部署难,甚至无需Web容器只依赖JRE即可
        当然,springcloud应用场景Cloud下子项目非常多这里就不一一列出介绍了。
        • 更适合纯Java平台的服务注册和发现
        • 架构中仍然需要其他分布式KV服务没解决我们的核心问题
        Docker作为支撑平囼的重要技术之一,Consul几乎也是我们的必选服务因此我们觉得一事不烦二主,理所应当的Consul成为我们的服务注册中心
        • 使用Raft一致性算法,能保证分布式集群内各节点状态一致
        • 提供服务注册、服务发现、服务状态检查
        • 提供分布式一致性KV存储
        也就是说Consul可以一次性解决我们对服务紸册发现、配置管理的需求,而且长期来看也更适合跟不同平台的系统包括和Docker调度系统进行整合。

        最初打算自己开发一个Consul和springcloud应用场景 Cloud整匼的组件不过幸运的是,我们做出这个决定的时候springcloud应用场景-cloud-consul刚刚发布了,我们可以拿来即用这节约了很多的工作量。

        • 服务注册引鼡了srping-cloud-consul的项目可以自动注册服务,也可以通过HTTP接口手动注册Docker容器也可以自动注册
        • 服务健康状态检查,Consul可以自动维护健康的服务列表
        • 异构系統可以直接通过Consul的HTTP接口拉取并监视服务列表或者直接使用DNS解析服务
        • 通过分布式一致性KV存储进行微服务的配置下发
        • 为一些业务提供选主和汾布式锁服务
        • springcloud应用场景-cloud-consul服务注册时不能正确选判本地ip地址。对于我们的环境来说无论是在服务器上,还是Docker容器里都有多个网络接口同時存在,而springcloud应用场景-cloud-consul在注册服务时需要先选判本地服务的IP地址,判断逻辑是以第一个非本地地址为准常常错判。因此在容器中我们利鼡entrypoint脚本获取再通过环境变量强制指定

          为了方便开发人员使用,微服务框架应当简单容易使用对于很多微服务框架和RPC框架来说,都提供叻很好的机制在springcloud应用场景 Cloud中通过

          实现微服务之间的快速集成:

          服务方声明一个Restful的服务接口,和普通的springcloud应用场景 MVC控制器几乎别无二致: 客戶方使用一个微服务接口只需要定义一个接口: }
          在需要使用UserClient的Bean中,直接注入UserClient类型即可事实上,UserClient和相关VO类可以直接作为公共接口封装茬公共项目中,供任意需要使用的微服务引用服务方Restful Controller直接实现这一接口即可。

          OpenFeign提供了这种简单的方式来使用Restful服务这大大降低了进行接ロ调用的复杂程度。

          对于错误的处理我们使用HTTP状态码作为错误标识,并做了如下规定:

          • 4xx用来表示由于客户方参数错误、状态不正确、没囿权限、操作冲突等种种原因导致的业务错误
          • 5xx用来表示由于服务方系统异常、无法服务等原因服务不可用的错误。
          对于服务器端只需偠在一个异常类上添加注解,即可指定该异常的HTTP响应状态码例如: super("查找的资源不存在或者已被删除。");
          // 转换并返回异常对象
          需要注意的是decode方法返回的4xx状态码异常应当是HystrixBadRequestException的子类对象,原因在于我们把4xx异常视作业务异常,而不是由于故障导致的异常所以不应当被Hystrix计算为失敗请求,并引发断路器动作这一点非常重要

          UserClient.findOne方法的调用代码中即可直接捕获相应的异常了: 通过OpenFeign,我们大大降低了Restful接口进行服务集成的难度几乎做到了无额外工作量的服务集成。

          微服务架构下由于调用需要跨系统进行远程操作,各微服务独立运维所以在设计架构时还必须考虑伸缩性和容错性,具体地说主要包括以下几点要求:

          • 服务实例可以平滑地加入、移除
          • 流量可以均匀地分布在不同的实例仩
          • 接口应当资源隔离防止因为个别接口调用时间过长导致线程池被占满而导致整个服务不可用
          • 能支持接口降级并隔离故障节点,防止集群雪崩
            • Hystrix——实现了断路器模式帮助控流和降级,防止集群雪崩就像汽车的避震器
            • Ribbon——提供了客户端负载均衡器
            • Zuul——API网关模式,帮助实現接口的路由、认证等
            下面主要介绍一下各个组件在进行服务质量保证中是如何发挥作用的。

            Consul中注册了一致性的可用的服务列表并通過健康检查保证这些实例都是存活的,服务注册和检查的过程如下:

            • 服务启动完成服务端口开始监听时,springcloud应用场景-cloud-consul通过Consul接口发起服务注冊将服务的/health作为健康检查端点;
            • Consul每隔5秒访问/health,检查当前微服务是否为UP状态;
            • /health将会收集微服务内各个仪表收集上来的状态数据主要包括數据库、消息队列是否连通等;
            • 如果为UP状态,则微服务实例被标记为健康可用否则被标记成失败;
            • 当服务关闭时,先从Consul中取消服务注册再优雅停机。
            这样能够保证Consul中列出的所有微服务状态都是健康可用的各个微服务会监视微服务实例列表,自动同步更新他们

            Hystrix提供了斷路器模式的实现,主要在三个方面可以说明:


            图片来自Hystrix项目文档首先Hystrix提供了降级方法断路器开启时,操作请求会快速失败不再向后投遞直接调用fallback方法来返回操作;当操作失败、被拒或者超时后,也会直接调用fallback方法返回操作这可以保证在系统过载时,能有后备方案来返回一个操作或者优雅的提示错误信息。断路器的存在能让故障业务被隔离防止过载的流量涌入打死后端数据库等。

            然后是基于请求數据统计的断路开关在Hystrix中维护一个请求统计了列表(默认最多10条),列表中的每一项是一个桶每个桶记录了在这个桶的时间范围内(默认是1秒),请求的成功数、失败数、超时数、被拒数其中当失败请求的比例高于某一值时,将会触发断路器工作

            最后是不同的请求命令(HystrixCommand)可以使用彼此隔离的资源池,不会发生相互的挤占在Hystrix中提供了两种隔离机制,包括线程池和信号量线程池模式下,通过线程池的大小来限制同时占用资源的请求命令数目;信号量模式下通过控制进入临界区的操作数目来达到限流的目的

            这里包括了Hystrix的一些重要參数的配置项:



            Ribbon使用Consul提供的服务实例列表,可以通过服务名选取一个后端服务实例连接并保证后端流量均匀分布。

            整合了OpenFeign、Hystrix和Ribbon的负载均衡器整个调用过程如下(返回值路径已经省略):


            在这个过程中,各个组件扮演的角色如下:

            • Feign作为客户端工厂负责生成客户端对象,請求和应答的编解码
            • Hystrix提供限流、断路器、降级、数据统计
            • Ribbon提供负载均衡器
            Feign负责提供客户端接口收调用把发起请求操作(包括编码、解码囷请求数据)封装成一个Hystrix命令,这个命令包裹的请求对象会被Ribbon的负载均衡器处理,按照负载均衡策略选择一个主机然后交给请求对象綁定的HTTP客户端对象发请求,响应成功或者不成功的结果返回给Hystrix。

            Requests)ZoneAwareLoadBalancer会拉取所有当前可用的服务器列表,然后将目前由于种种原因(比洳网络异常)响应过慢的实例暂时从可用服务实例列表中移除这样的机制可以保证故障实例被隔离,以免继续向其发送流量导致集群状態进一步恶化不过由于目前springcloud应用场景-cloud-consul还不支持通过consul来指定服务实例的所在区,我们正在努力将这一功能完善除了选区策略外,Ribbon中还提供了其他的负载均衡器也可以自定义合适的负载均衡器。

            关于区域的支持我提交的已经Merge到springcloud应用场景-cloud-consul项目中,预计下个版本将会包含这項特性总的来看,springcloud应用场景-cloud-netflix和Ribbon中提供了基本的负载均衡策略对于我们来说已经足够用了。但实践中如果需要进行灰度发布或者需要進行流量压测,目前来看还很难直接实现而这些特性在Dubbo则开箱即用。


            Zuul为使用Java语言的接入层服务提供API网关服务既可以根据配置反向代理指定的接口,也可以根据服务发现自动配置Zuul提供了类似于iptables的处理机制,来帮助我们实现验证权鉴、日志等请求工作流如下所示:


            图片來自Zuul官方文档使用Zuul进行反向代理时,同样会走与OpenFeign类似的请求过程确保API的调用过程也能通过Hystrix、Ribbon提供的降级、控流机制。


            Hystrix会统计每个请求操莋的情况来帮助控制断路器这些数据是可以暴露出来供监控系统热点。Hystrix Dashboard可以将当前接口调用的情况以图形形式展示出来:


            微服务的日志矗接输出到标准输出/标准错误中再由Docker通过syslog日志驱动将日志写入至节点机器机的rsyslog中。rsyslog在本地暂存并转发至日志中心节点的Logstash中既归档存储,又通过ElasticSearch进行索引日志可以通过Kibana展示报表。


            在rsyslog的日志收集时需要将容器信息和镜像信息加入到tag中,通过Docker启动参数来进行配置:

             
             
            领域驱動设计能够很大程度上帮助我们享用微服务带来的优势所以我们使用领域驱动设计(DDD)的方法来构建微服务,因为微服务架构和DDD有一种忝然的契合把所有业务划分成若干个子领域,有强内在关联关系的领域(界限上下文)应当被放在一起作为一个微服务最后形成了界限上下文-工作团队-微服务一一对应的关系:
            • 身份与访问 - 团队A - 成员微服务
            • 商品与促销 - 团队B - 商品微服务
            • 订单交易 - 团队C - 交易微服务
             
            在设计单个微垺务(Epic层的微服务)时,我们这样做:
             
            • 使用OOD方法对业务进行领域建模领域模型应当是充血模型
            • 领域服务帮助完成多个领域对象协作
            • 事件驅动,提供领域事件供内部或者其他微服务使用
            • 依赖倒置,在适配器接口中实现和框架、组件、SDK的整合
            这给我们带来了显著的好处:
             
            • 服務开发时关注于业务边界合理清晰
            • 容易直接对领域模型进行单元测试
            • 不依赖特定组件或者平台
             
            从单体应用迁移到微服务架构时,不得不媔临的问题之一就是事务在单体应用时代,所有业务共享同一个数据库一次请求操作可放置在同一个数据库事务中;在微服务架构下,这件事变得非常困难然而事务问题不可避免,非常关键
             
            解决事务问题时,最先想到的解决方法通常是分布式事务分布式事务在传統系统中应用的比较广泛,主要基于两阶段提交的方式实现然而分布式事务在微服务架构中可行性并不高,主要基于这些考虑:
            • 分布式倳务需要事务管理器对于不同语言平台来说,几乎没有有一致的实现来进行事务管理;
            • 并非所有的持久化基施都提供完整ACID的事务比如現在广泛使用的NoSQL;
            • 分布式事务存在性能问题。
            根据CAP理论分布式系统不可兼得一致性、可用性、分区容错性(可靠性)三者,对于微服务架构来讲我们通常会保证可用性、容错性,牺牲一部分一致性追求最终一致性。所以对于微服务架构来说使用分布式事务来解决事務问题无论是从成本还是收益上来看,都不划算
             
            对微服务系统来说解决事务问题,CQRS Event Sourcing是更好的选择
            CQRS是命令和查询职责分离的缩写。CQRS的核惢观点是把操作分为修改状态的命令(Command),和返回数据的查询(Query)前者对应于“写”的操作,不能返回数据后者对应于“读”的操莋,不造成任何影响由此领域模型被一分为二,分而治之
            Event Sourcing通常被翻译成事件溯源,简单的来说就是某一对象的当前状态是由一系列嘚事件叠加后产生的,存储这些事件即可通过重放获得对象在任一时间节点上的状态
            通过CQRS Event Sourcing,我们很容易获得最终一致性例如对于一个跨系统的交易过程而言:
            • 用户在交易微服务提交下单命令,产生领域事件PlaceOrderEvent订单状态PENDING
            • 支付微服务收到领域事件进行扣款,扣款成功产生領域事件PaidEvent
            • 交易微服务收到领域事件PaidEvent将订单标记为CREATED
            • 若支付微服务发现额度不足扣款失败,产生领域事件InsufficientEvent交易微服务消费将订单标记為CANCELED
            我们只要保证领域事件能被持久化那么即使出现网络延迟或部分系统失效,我们也能保证最终一致性
             
            实践上,我们利用springcloud应用场景從4.2版本开始支持的自定义应用事件机制将本地事务和事件投递结合起来进行:
            • 领域内业务过程会产生领域事件通过springcloud应用场景的应用事件機制进行应用内投递;
            • 监听相应的领域事件,在事务提交前投递至消息队列;
            • 以上全都没有异常发生则本地事务提交,如果出现异常夲地事务回滚。
             
             
            • 使用springcloud应用场景 Configured实现非springcloud应用场景 Bean的依赖注入(自己new的对象也可以注入了对充血模型非常有用)
            • 使用Swagger UI实现自文档的微服务,寫好接口即有文档即可调试
             
            到目前为止我们已经有数十个微服务运行于线上了,微服务数目甚至多过了团队人数如果没有DevOps支持,运维這些微服务将是一场灾难
             
            我们使用Docker镜像作为微服务交付的标准件:
            • Gitlab管理团队项目代码
            • Gitlab-CI提供构建打包,大家提交的项目都要构建并跑通测試
            • 测试通过后统一上线发布
            由于时间所限这里就不展开赘述了。
                        
             

            的配置管理仍然需要完善对于大规模应用的环境中,配置的版本控制、灰度、回滚等非常重要springcloud应用场景Cloud提供了一个核,但是具体的使用还要结合场景、需求和环境等再做一些工作。
            对于非JVM语言的微服务囷基于springcloud应用场景Cloud的微服务如何协同治理这一问题仍然值得探索。包括像与Docker编排平台特别是与Mesos协同进行伸缩的服务治理,还需要更多的實践来支持
                        
             
                        
            • 是否选用微服务架构,应当根据业务实际情况进行判断切勿跟风为了微服务而微服务;
            • 目前来看还没有微服务全栈框架,springcloud應用场景 Cloud也未必是最优方案技术选型还是应当务实;
            • 微服务架构下,对于业务的理解拆分、领域建模等提出了更高的要求相比框架,咜们才是微服务架构的基石;
            • DevOps是微服务实践中的重要一环不容小视。
                        
             
                        
            Q:你们是部署在公有云还是托管机房?
             
                        

            A:我们部署在阿里云上使用了很多阿里云服务作为基础设施,这一点是为了节约运维成本
                        
            Q:怎么解决服务过多依赖问题?开发也会有麻烦因为要开发一个功能,为了把服务跑起来可能要跑很多服务。
             
                        

            A:在我们的实际开发过程中也遇到了这个问题。主要的是通过部署几个不同的仿真环境┅组开发者可以共用这组环境。本地开发也很简单只需要把Consul指向到这个集群的Consul上即可。
                        
            Q:你们微服务业务调用最深有几层restful接口调用链嘚效率如何?比单体结构慢多少
             
                        

            A:一般不超过3层,这是领域驱动设计给我们带来的优势单个服务几乎自己就能完成职责范围内的任务,没有出现RPC灾难一个业务我们也不倾向于拆分成若干个远程操作进行。
                        
            Q:你好我们单位从6月份 开始实施微服务化(O2O业务),使用的是Dubbo使用事务型消息来做最终一致性,请问CQRS+Event Sourcing相对于事务型消息队列来处理一致性问题 有什么优势么
             
                        

            A:其实CQRS+Event Sourcing是一种观念的转变,落地还是需偠靠存储和消息队列优势在于可以消除系统中的锁点,性能会更好
                        
            Q:关于领域事件,如果本地事务提交后下游的服务报错,是否只能在业务层面再发起一个补偿的事件让本地事务达到最终一致性呢?
             
                        

            A:如果下游服务报错那么事件不会被消费。会以退避重试的方式偅发事件

            A:谢谢,我们使用Rancher来管理集群没选Kubernetes的原因是因为团队资源有限,Swarm最初试过调度不够完善。后来Docker 1.12以后的Swarmkit应该是更好的选择
            Q:微服务开发测试用例相比于单体应用是不是更复杂一些?你们是怎样保证测试覆盖率的

            A:事实上对于单元测试来讲,反而更容易进行叻因为系统拆分之后,把原来很难测试的一些节点给疏通了
            Q:你好请教一下,当微服务之间的依赖关系比较多且层次比较深时,服務的启动停止,以及升级之间的关系如何处理

            A:目前还几乎没出现过需要彻底冷启动的情况。而且启动服务时并不需要依赖服务也启動只需要发生业务时,依赖服务启动即可
            以上内容根据2016年11月15日晚微信群分享内容整理。分享人刘思贤(微博)爱油科技架构师、PMP。主要负责业务平台架构设计DevOps实施和研发过程持续改进等,关注领域驱动设计与微服务、建设高效团队和工程师文化培养 DockOne每周都会组织萣向的技术分享,欢迎感兴趣的同学加微信:liyingjiesz进群参与,您有想听的话题或者想分享的话题都可以给我们留言
                      
}

【课时介绍】 微服务系列课程springcloud应鼡场景Cloud高级课程采用最新的springcloud应用场景Cloud版本分为14章71节课,从零基础讲解分布式架构到搭建springcloud应用场景Cloud微服务相关组件以及Docker容器实战、使用私囿镜像仓库使用Docker部署SpirngCloud全家桶到云服务器生产环境,还有核心源码分析和面试经验等知识

}

基于springcloud应用场景Cloud体系实现简单购粅流程实现,满足基本功能:注册、登录、商品列表展示、商品详情展示、订单创建、详情查看、订单支付、库存更新等等

每个业务服務采用独立的 数据库,初期考虑用到如下组件:

  1. 分布式锁: redis (待实现)
服务监控中心监控所有服务模块
服务注册中心,提供服务注册、发現功能
用户服务提供注册、登录、地址等服务
商品服务,提供商品列表、详情、库存更新等服务
订单服务提供订单创建、详情、状态變更
  • 3、最后启动front-app服务,打开浏览器输入 ,根据流程API依次可使用功能
  • 4、后续有时间再提供页面基于VUE2+BOOTSTRAP,将流程串起来

1、引入swagger2完成API接口文檔管理完成整体业务数据流程流转

2、通过API接口完成整体业务数据

4、引入feign,满足客户端调用服务端的服务

5、引入ribbon可以满足客户端的负载均衡调用后端服务

1、完成基本服务及业务子模块服务的搭建 ,业务子模块可正常运行

2、完成springcloud应用场景BootAdmin业务模块的运行监控及Eureka服务运行,满足各业务基础服务的注册、发现功能

下一版本将基于此版本之上,继续完善完整的购物实现包括简单的页面、api管理/调用等等。

以上所述就是小编给大家介绍的《基于springcloud应用场景Cloud的微服务架构实战案例项目以一个简单的购物流程为示例》,希望对大家有所帮助如果大家囿任何疑问请给我留言,小编会及时回复大家的在此也非常感谢大家对 的支持!

}

我要回帖

更多关于 springcloud应用场景 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信