8

2020年总结-用学习过的技术搭建一个简单的微服务框架 + 源码

 3 years ago
source link: https://www.cnblogs.com/lifeng618/p/14120044.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

框架中使用的技术知识

工作快4年了,有时很迷茫,有时很有干劲,学习了一些技术,也忘记了一些技术,即使对一些技术,了解的深度不够,至少自己学习过使用过,那么在面对问题时,不会显得那么无力,解决问题后,也能有更大的收获。

  1. NET Core基础知识,EF CORE Code First,DB First
  2. 领域驱动设计理论,三层架构,DDD经典分层架构
  3. WebApi,Swagger,WebApiClient,Grpc,Exceptionless,Serilog
  4. Redis,Consul,IdentityServer4,Rabbitmq,Kafka,CAP
  5. Ocelot,Kong,Docker,Docker-Compose,Jenkins

DDD经典分层架构,与认识

1297333-20201211144112122-1974288333.png
  1. 根据业务,将问题域逐步分解,把一个大的问题,逐步分解为小的问题,针对细分出的问题,给出相应的解决方案,降低业务的复杂性和系统实现的复杂性
  2. 领域驱动设计是有门槛的,需要全方位提升,包括,业务知识,沟通能力,了解需求的能力,分析业务的能力,软件建模能力(希望有朝一日能爬过去)
  3. 个人感觉领域驱动设计最重要的就是,让团队每个人都理解业务,达成共识,过程中留下来的文档,图例,模型,对公司对个人都是一笔财富,提升了团队能力,沉淀了业务知识
  4. 学习领域驱动设计是一个长期的过程,书本的理论知识中没有明确指出实践的方式,基本上不会有完整的案例,因为实践领域驱动设计的系统都是公司的核心系统,里面包 含了公司大量的业务,以及商业价值,一般不会开源出来分享,需要结合项目,业务,人员,团队,来综合考虑,权衡,团队需要达成共识去实践,在实践中总结,进步

服务间的通讯:WebApiClient,Grpc,EventBus,以及问题

多个服务中需要通讯的时候,我们需要根据场景,来选择不同的通讯手段,每种通讯手段都有好处和坏处,以及异常的情况,需要综合来考虑选择

在下单扣库存的场景中,我们在订单服务中下单完成后,需要扣除商品服务中的sku库存,由于在不同的服务,我们不能保证他们的事务,只能保证最终一致性

WebApiClient,Grpc来实现

WebApiClient的github地址:https://github.com/dotnetcore/WebApiClient

  1. 如何保证不超卖?扣减库存的并发量比较大怎么办?

商品服务提供RESTful API,GRPC 服务端,扣减库存接口时:利用数据库行锁,和添加扣除的数量不能大于数据库的库存数量的条件(UPDATE t_sku SET Stock=Stock - {sku.SkuQuantity} where Id = '{sku.SkuId}' AND Stock > {sku.SkuQuantity})

如何保证生成订单与商品库存的最终一致性?

重试 + 补偿 ,订单服务保存订单后,使用WebApiClient,调用RESTful API扣减库存接口,使用Grpc 请求服务端扣减库存,根据调用的返回结果,结果失败重试,重试一定次数后,记录日志,回归订单,提示失败,成功则提示下单成功!

订单服务可能会多次请求商品服务扣减库存的接口,会不会造成多次扣减库存?

商品服务扣减库存的接口需要根据订单服务提供的唯一标识做幂等,Grpc 服务端扣减库存做幂等,幂等可以采用redis 的Hash,和设置Hash的过期时间来做幂等,也可以使用幂等表,新增一张表,用订单服务的标识做唯一索引,我这里使用的是幂等表

EventBus来实现

  1. 怎么选择消息队列,Rabbitmq 还是 Kafka?

Rabbitmq 的社区比较活跃,官方文档比较详细,有.NET的客户端,性能没有Kafka高,Kafka 的原理架构比rabbitmq 容易理解,kafka的集群更好搭建,目前来说没有性能要求,工作中用的是Rabbitmq

下单扣除库存是比较重要的场景,听说消息队列会丢消息?

Rabbitmq 提供了发布者确认机制,消费者提供了ACK机制,可以保证不丢消息,消息发布到rabbitmq 服务器,开启了发布者确认,消息持久化到磁盘成功后,会返回持久化的状态,持久化磁盘成功了,代表发布消息成功了,消息者开启ACK,消息消费失败后,会返回消息队列中,多次失败后,可以把消息放到指定的延迟队列中,Rabbitmq 挂了,重启时会,不断的重试,直到成功,也可以失败一定次数后,人工干预解决问题

kafka有生产者消息确认机制,消费者ack机制,kafka 发布消息是可以设置ACK=all,消息需要,Leader持久化磁盘成功,所有的ISR中的Follower都持久化磁盘成功后,才表示真正的成功,消费者可以手动提交当前偏移量,保证不丢消息

有没有写好的,使用非常简单方便的框架,这样我就能直接搬砖了?

杨晓东老师的CAP:https://github.com/dotnetcore/CAP,一个基于本地消息表+消息队列 的分布式事务的解决方案,同样具有 EventBus 的功能,基于本地消息表意味者,多了几次IO,会影响一点性能,但是可靠,使用简直是easy,最好能了解一些原理,这样遇到一些问题,也能解决

用消息队列我还需要考虑幂等吗?

用消息队列一定要考虑幂等,很多消息队列都保证至少一次投递消息,可能出现多次投递的情况。幂等方式与上面的一致

Redis

CsRedis的github地址:https://github.com/2881099/csredis

目前接触的数据量,不用考虑缓存穿透、缓存击穿、缓存雪崩的情况,缓存同步策略,也看过一些文章,了解过一些
  1. CsRedis 幂等
  2. CsRedis 分布式锁
  3. CsRedis做缓存,加快查询的速度,缓存一些热点数据,比如权限

IdentityServer4

IdentityServer4的文档地址:http://www.identityserver.com.cn/

IdentityServer4 是为ASP.NET Core系列量身打造的一款基于 OpenID Connect 和 OAuth 2.0 认证框架。 对外提供RESTful API接口,需要Token来进行验证,JWT Token中包含一些用户信息,我们可以结合RBAC权限进行授权
  1. 在已有登录的项目中,我们可以使用密码授权模式,获取Token
  2. 使用混合流模式,结合前端使用oidc-client-js,获取Token
  3. 使用混合流模式,IdentityServer提供了一套基于 MVC 的样例 UI,可以直接从Github上拉取,引用到项目中,获取Token

Consul

使用Consul来实现服务发现与健康检查

  1. Consul提供了可视化的界面,我们可以随时查看服务的状态
  2. Consul有.net的客户端,我们可以在服务启动的时候向consul注册,服务关闭时注销,也可以通过Json文件的方式向consul中注册服务
  3. Consul的健康检查,会根据你设置的时间来对你的服务发起调用。检查服务是否正常,所以我们需要提供一个接口,表示服务的运行状态
  4. Consul可以在一个服务中注册多个Ip+端口号,客户端可以根据服务名称获取所有的Ip+端口号,根据算法,实现负载均衡

Ocelot

Ocelot文档地址:https://ocelot.readthedocs.io/en/latest/index.html

Ocelot是一个用.NET Core实现并且开源的API网关,它功能强大,包括了:路由、请求聚合、服务发现、认证、鉴权、限流熔断、并内置了负载均衡器

  1. Ocelot 可以结合Consul 实现服务发现,实现负载均衡
  2. Ocelot 所有的请求路由都走Ocelot,可以结合Identityserver4,可以在Ocelot上统一认证授权

Ocelot Swagger,Kong Swagger,遇到过的问题

Swagger 是一个很好用的接口文档,可以帮助我们前后端联调,以及多个项目接口的管理
  1. 使用Ocelot网关,多个服务,怎么统一的使用swagger 来管理

Swagger加载时请求一个IP+端口+服务名称+Swagger.json的接口,我们可以在ocelot中,配置单个服务的swagger路由,在Ocelot上配置Swagger,通过选择的服务名称,来路由到指定服务的swagger

Swagger访问的统一路径是:IP+端口/swagger,部署网关后,都是8000端口,由于Kong 的Route不能重复,我该怎么来配置?

我们可以使用KongA可视化界面,给指定的服务配置特定的路由

1297333-20201212135948899-1400870348.png

Swagger访问的统一路径是:IP+端口/swagger,我们可以为每个服务设置IP+端口/{唯一的名称}+swagger,比如订单服务:47.104.83.210:8000/orderSwagger

1297333-20201212140331340-520103261.png
我们公司现在有几十个服务,每个都需要在KongA上配置,很麻烦,怎么办?

kong有官方的文档,提供了RESTful API接口,可以调用kong的8001端口来,配置,目前Kong Admin Api 没有官方的.NET客户端,有位大佬开源了Kong.Net,可以帮助我们更快的去实现

Kong.Net的github地址:https://github.com/lianggx/Kong.Net

Docker ,Docker-Compose ,Jenkins

使用Jenkins pipeline 来实现,从git 服务器上拉取代码,发布代码,把代码打包,通过SSH,传输到Linux 服务器,在Linux 服务器执行,docker images ,docker run ,docker-compsoe,部署项目。 使用Docker,Docker-Compose,部署项目,以及安装各种需要的环境,工具。

喜欢沟通交流,欢迎大家给出意见,谢谢!

  1. 基础知识不足,技术的深度不够,没有养成记录知识的习惯,习惯性的忘记了许多东西
  2. 没有重视业务的重要性,没有沉淀积累业务知识,经常考虑一些技术或者功能实现,忽略了最重要的业务积累
  3. 做的事件很杂,很散,没有方向,也收获了一些,比如,讨论出的方案,我会思考这样做,是否会有问题,有问题的地方在哪里,提出来,大家讨论
  4. 学习领域驱动设计,让我明白了业务的重要性,我一直想要提高自己的沟通能力和需求分析能力,却没有方向,十分的迷茫,一无所有,却缺乏从头再来的勇气

码云Gitee地址:https://gitee.com/lifeng618/Sample.git


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK