.Net微服务实战之技术选型篇

王者荣耀 

  去年我有幸被老领导邀请以系统架构师的岗位带技术团队,并对公司项目以微服务进行了实施。不管是技术团队仍是技术架构都是由我亲自的从0到1的选型与招聘成型的,此过程让我受益良多,所以也但愿在接下来的系列博文尽量的与你们分享个人经验。nginx

  古人有云:将军难打无兵之仗。想要把微服务很好的实施也并不是能一我的能够完成的事,一来须要有出色的运维提供支持,二来须要花时间作技术选型与攻关,三来还要开发兄弟们配合实施。所以,此次能顺利实施并非一我的的王者,而是团队的荣耀。git

  框架源码:https://github.com/SkyChenSky/Sikiro (文末有说明)github

工欲善其事,必先利其器

  以上是咱们公司的技术栈(点击图片可在浏览器打开),除了统一配置中心没有服务器资源和Hangfire还没场景使用外,其余都已经上线使用了。  面试

  俗话说得好:工欲善其事,必先利其器。一个优秀的工程师应该善于使用框架和工具,在微服务这一块的技术栈选型并不是一蹴而就,也是我屡次对比验证后,并良好的集成到公司项目而后落地实施。这系列框架单纯这么去用实际上是能够无缝集成的,可是在落实项目的时候,我为了集成得更加友好和使用上更加便利,在基础上作了扩展,例如SkyWalking添加Request和Response,CAP与Chloe.ORM的集成等,下文我会逐个分享。算法

  有须要的朋友能够参照我这套去实施,这样你们就能够花更多的时间把精力放在业务、调优、拆分、设计等方面。sql

  此外你们看得出,我全部的技术栈基本上找的都是开源社区的比较出名的项目,没有一个属于自研的。这样作的缘由:mongodb

  •   快速搭建
  •   下降成本
  •   社区支持维护
  •   利于人才引进

  其实能够看出.Net不缺优秀的开源项目,那么实施这么久让我惟一以为深入的印象是:缺乏整合。后端

  以前我也跟很多同行讨论过甚至在面试的时候,他们以为应该本身造一个轮子,缘由各类各样,但惟独缺乏了但愿在开源项目基础上完善下这个缘由。我也理解他们的心理,由于“优秀”的工程师应该本身写一套证实下本身。其实我认为这也许是包容心的在做祟,咱们应当求同存异,学会接受已经检验过的轮子,在基础上完善您的须要,有必要还能够给社区作贡献,共赢。跨域

原则

  我作技术选型的时候,坚持着三大原则,简单、适合、运维优先浏览器

  在知足需求的状况下,优先选择轻量级的框架,由于轻量级总比重量级的易学习,易于扩展,易于理解源码。试想一下,有个框架什么都很齐全,可是学习曲线高,在写一个demo的时候各类踩“坑”找缘由,还有可能出了问题不知道怎么解决,除了开始你初认识该框架以为他很厉害以外,后面使用每走一步都是阻碍和吐槽。

  在有限的资源、人力、时间,咱们更新技术的同时还要保证业务的正常开展,我会优先选择我比较熟悉的技术,我会将他们进行封装、优化、集成,尽量的减小开发人员对技术细节的认知负担,尽量以他们最熟悉的使用方式提供。此外,咱们团队是有运维岗,若是问题由运维解决更快、更方便则优先交给运维,尽量让开发关注数据流转与业务流程。

  PS:我选型的时候不是一蹴而就的,下文可能我会提到某些框架工具我没有去选择缘由,并非否定它们存在的价值,而绝大问题是这些不适用于咱们团队。最后我向伟大的开源项目与其做者致敬。

  

微服务

 

  有一条盛传于咱们行业的公式:软件 = 程序 + 软件工程

  程序就是咱们常常产出的算法、数据结构、脚本、框架、架构等。

  为何称之为软件工程?由于这是具备科学方法论引导的、多人协做、有明确目标、有阶段性的。从之前瀑布开发再到10年前盛行的敏捷开发最后到最近几年流行的DevOps,可见开发模式也随着技术架构更新也不停的演进。咱们团队选用了原型模式+DevOps模式来应对咱们的微服务架构的开发。

  书本的教条主义我就很少说了,我对微服务的理解分为服务

  如何微?微到什么程度?我借助两样东西,合理的系统架构分层DDD思想,二者分别管理架构的纵向拆分与横向拆分。

  架构分层,我采用了先后端分离+多层架构,自顶向下的依赖,各司其职。

  DDD在最近几年很是流行,然而这并不是新的技术,十几年前就已经它的出现了。随着微服务盛行,DDD的划分域的化繁为简的思想与微服务的本质-不谋而合,所以DDD也随之热门起来。

  下面是咱们的架构图,这个话题在下一篇重点再讨论。

服务

  我接下来用一段话描述一下服务化的须要。首先API网关做为咱们请求流量的入口,隔离了外网与内网的做用。接着开发人员得知道如何调用服务,那么能够从注册中心发现已注册的服务的IP地址、端口的列表,这就是服务的注册与发现;接着咱们须要知道服务下接口路径、请求与响应的格式,所以咱们须要服务描述。知足前面两个条件后,咱们就能够进行调用服务了,所以咱们须要RPC框架进行服务通讯。当服务运做后,咱们须要服务监控来监控服务的运行状况以此方便调优。随着服务拆分得越细、跨度越大,服务出问题的时候不容易定位,所以咱们须要服务跟踪进行问题定位。

  由上述可见组件主要包括如下6点:

  •   API网关
  •   服务描述
  •   服务注册中心
  •   RPC框架
  •   服务监控
  •   分布式链路跟踪

API网关

  API网关主要起到了隔离内外网、身份验证、路由、限流等做用。我用一个生活的例子搭地铁比喻来描述下:过闸前咱们须要通过安检保证客流的安全性,上下班高峰期还会排队进行限流,咱们还能够经过看指示牌或者询问工做人员了解到应该往什么方向走,这就是路由。

  咱们团队选型了Kong和KongA做为咱们的API网关,Kong是一个在Nginx运行的Lua应用程序,由lua-nginx-module实现。Kong和OpenResty一块儿打包发行,其中已经包含了lua-nginx-module。基本功能有路由、负载均衡、基本认证、限流、跨域、日志等功能,其余功能例如jwt认证能够经过插件进行扩展。

  有人会问为何不用Ocelot?回答这个问题以前,我首先声明我尊敬Ocelot项目与其开发者。

  1.易用性。须要二次开发,虽然对.Net开发者来讲能接受,但不利于运维。

  2.性能。社区不少测试数据,据我了解就是kong 11K,Ocelot 3.5K,四舍五入3倍性能差,做为流量的入口,性能这块我仍是比较注重的。

  3.可扩展性,Kong不少功能能够经过插件式按需使用与开发。

 

服务描述

  咱们团队采用了Swagger,以此来衔接先后端开发的接口对接,省去了编写接口文档的成本,此外也支持接口调试,让开发效率提升很多。咱们的服务都是以HTTP协议提供,对外API用RESTful风格,对内统一以POST的RPC风格提供。

服务注册中心

  服务注册,服务在发布后自动把IP地址与端口注册进服务中心;服务发现,经过调用服务中心的接口获取到某服务IP地址与端口的列表。咱们团队选用Consul+Consul Tamplate+nginx,Consul是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul的核心功能包括:服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等特性。

  Consul做为服务注册中心的存在,可是咱们服务发现只能拿到IP列表,咱们使用RPC调用时仍是得作负载均衡算法,因而使用了Consul Tamplate把服务列表同步到nginx的配置,那么RPC框架就无需集成负载均衡算法通过nginx路由。

  开始选型我并无选择Consul Tamplate,而是选择了fabio的这个中间件。fabio是一个应用于Consul的轻量级、零配置负载均衡路由器,开始用的时候部署起来很方便、很简单。后来上了Skywalking分布式链路跟踪系统,只要通过fabio路由的都没法把调用链串起来,虽然将就的用是没什么问题,可是Skywalking的调用链日志没法很好的展现出来就会影响往后的问题排查。我当时花了两天时间研究与issue提问,并无很好的结果,因此最后另外选择了Consul Tamplate+nginx。

服务通讯

  RPC框架主要三大核心,序列化、通讯细节隐藏、代理。协议支持分TCP和HTTP,固然还有二者兼容+集成MQ的。咱们选择了WebApiClient作客户端,服务端还是.Net Core WebAPI,主要考虑到WebAPIClient的轻量、易用,并且和Skywalking、Consul集成方便。我当时用的时候时.Net Core 2.2版本,gRPC并无集成进来。

  此外我也选择过ServiceStack,ServiceStack的技术栈很全,缺点是依赖得很深,当时试用的时候,它因此依赖的一个底层包ServiceStack.Common的某个类与WebAPI冲突了,因此对于不熟悉该框架的我判定存在依赖污染,不管我须要仍是不须要都通通依赖进来了,然而我只是但愿要一个简单的RPC框架。此外还须要破解。

  Surging也做为我当时选型的目标,开始也是我抱着最大但愿的,由于描述得很牛逼,什么都是全得。然而深刻去用的时候,没有一个完整的文档,入门demo也不友好,说实话我驾驭不住只能放弃。

服务跟踪

  市面上的分布式链路跟踪系统基本上都是根据谷歌的dapper论文实现的,基本上都分三大块,UI、收集器、代理(探针),原理大概是把涉及的服务链路的RequestID串起来。

  咱们团队选择了SkyWalking做为了项目的分布式链路跟踪系统,缘由很简单:易用,无侵入,集成良好。

  实施到咱们项目的时候我作了点扩展,把Reqeust、Response、Header、异常给记录了下来,并过滤了部分不须要记录的路径。

分布式事务

  只要在分布式系统,分布式事务必不可缺。

分布式事务
分类 理论 案例 中间件
强一致性 ACID 二阶段提交 msdtc
最终一致性 BASE 本地消息表 CAP

 

 

 

 

  本地消息表是eBay在N年前提出的方案,而CAP以该思想实现的一门框架,原理大概是,本地业务表与消息凭据表做为一个事务持久化,经过各类补偿手段保证MQ消息的可靠性,包括MQ正常发布与消费。

  我花了多天的时间专门测试了该框架可靠性,的确有保证。然而有个地方我认为能够优化,Retry的查询语句条件能够更加严谨点,只须要负责相应的Group进行Retry就好,不必所有都查询出来,由于这个问题我在测试环境与本地环境共同调试时,恰好两个环境的Group不一致,致使会Retry失败的问题。

框架源码

  写到这里,本篇的分享差很少要结束了,我将开源咱们公司的工具库,有须要的朋友能够去使用。

  •   Sikiro.Tookits -公共基础库
  •   Sikiro.Nosql.Redis-StackExchange.Redis的基本封装
  •   Sikiro.Nosql.Mongo-mongodb驱动封装更新、排序等支持lambda
  •   Sikiro.MicroService.Extension-RPC注册,微服务框架-服务注册,终端跟踪忽略
  •   Sikiro.Chloe.Extension-支持多数据、事务封装、分页、IOC
  •   Sikiro.Chloe.Cap-把Chloe,ORM与CAP整合

  额外说明下DotNetCore.CAP.MySql,这个是我从CAP源码拷贝过来而后改了MySql.Data的依赖,本来CAP.MySql是用的MySqlConnector,和个人Chloe.ORM冲突了。