Surging实践经验

背景

在去年9月份的时候,我入职一家做航空软件产品的公司。当时公司部门领导决定构建一个技术平台(或称为技术中台),通过该技术平台进而孵化各个业务系统。说白了就是需要通过一个分布式框架或是微服务框架提高应用系统的性能和并发处理能力、业务处理能力。
当时现有的系统是在 .net framework平台上搭建的简单的单体应用,并不具备可用性、扩展性、易用性等。
我在入职前也学习过一些微服务相关的知识,并通过搜索引擎了解了.net平台下的一些微服务框架和分布式架构。在对比不同技术框架的背景后,我决定使用surging作为公司的技术平台。原因在于:

  • Surging的设计思想和理念更符合微服务的架构思想,通过dotnetty框架实现的RPC通信,内置了服务治理保证通信的可靠性。
  • 通过向服务注册中心(Zookeeper、Consul)注册相关元数据来管理集群的服务命令、路由信息、缓存中间件等数据,服务注册不需要进行额外的处理
  • Surging内置了负载均衡算法。
  • Surging支持多种协议的通信方式,并且支持ws服务主机与一般服务(Http、TCP)主机之间直接通过RPC进行通信。
  • 服务之间的调用很方便,作者提供了基于ServiceProxyProvider、和基于ServiceProxyFactory的rpc调用方式,简单易用。
  • 模块化设计,很方便的对模块进行扩展。
  • 支持事件总线,通过消息对象实现的时效件纵向的适配可以实现发布订阅的交互模式。
  • .net core 跨平台,性能更高。

架构维护

由于作者一直在维护surging,而且我们也需要对surging的一些模块进行调整,也需要扩展一些surging的组件包,所以我们在使用surging的过程中是直接获取源代码后,在公司维护一份自己的源码,然后打包成nuget包,并发布到内部的nuget服务,通过内部的nuget对surging组件进行分发。
在获取surging源码后,我对surging进行了如下调整:

  1. 根据公司要求,对名称空间和包名称进行了调整。
  2. 对异常处理进行了重构
  3. 将消息返回的数据结果名称重命名为Data,统一了消息返回码。
  4. 修改了默认的json序列化器,默认使用camelCame风格
  5. 重构了签发token的方法(使用jose-jwt组件)
  6. 支持通过RpcContext设置token的payload和获取payload,通过扩展RpcContextSession获取运行时登录用户
  7. 扩展了Dapper、Domain、Validation、Schedule(基于Quartz的分布式任务调度)等组件包
  8. swagger文档支持jwt token验证
  9. 新增surging打包脚本等等
  10. 现在surging的demo案例和内部的开发者文档

如果你在使用surging的过程中,对surging源码较为熟悉,并希望对surging进行一定的调整、扩展自己公司的一些组件的时候,您可以通过社区获取surging的源代码,并在公司的代码库维护自己的分支。但是需要对作者对源码的修改要及时了解和熟悉。
nuget服务的搭建可以使用nuget官方提供的nuget.server或是nexus 。
对架构的维护可能是一个持续的和长久的过程,你可以通过企业内部的需求和作者对框架的调整对技术框架持续的进行调整和维护。在对surging进行调整维护后,就通过通过打包脚本进行打包发布到内部的nuget服务。

业务框架

构建微服务主机

由于在构建每个微服务主机的代码和配置文件都是一致的,无法就是对配置文件的一些配置项进行调整,所以可以将构建微服务主机的代码和配置文件抽象出来,统一放置在Shared目录中,再在项目文件中通过import进入即可。
如何将公共的脚本、配置文件、属性抽象出来,可以参考:https://github.com/surging-cloud/Surging.Hero/tree/develop/hero/src/Shared 。
如何构建主机呢?Surging通过ServiceHostBuilder来构建微服务主机,在构建主机过程中,可以添加一些服务组件或是指定相应的配置文件。构建主机的代码如下:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
var host = new ServiceHostBuilder()                 .RegisterServices(builder =>                 {                     builder.AddMicroService(option =>                      {                          option.AddServiceRuntime()                           .AddClientProxy()                           .AddRelateServiceRuntime()                           .AddConfigurationWatch()                           .AddServiceEngine(typeof(SurgingServiceEngine))                           ;

                          builder.Register(p => new CPlatformContainer(ServiceLocator.Current));                      });                 })                 .ConfigureLogging(loggging =>                 {                     loggging.AddConfiguration(                         AppConfig.GetSection("Logging"));                 })                 .UseServer(options => { })                 .UseConsoleLifetime()                 .Configure(build =>                 {#if DEBUG                     build.AddCacheFile("${cachePath}|/app/configs/cacheSettings.json", optional: false, reloadOnChange: true);                     build.AddCPlatformFile("${surgingPath}|/app/configs/surgingSettings.json", optional: false, reloadOnChange: true);                     build.AddEventBusFile("${eventBusPath}|/app/configs/eventBusSettings.json", optional: false);                     build.AddConsulFile("${consulPath}|/app/configs/consul.json", optional: false, reloadOnChange: true);

#else                    build.AddCacheFile("${cachePath}|configs/cacheSettings.json", optional: false, reloadOnChange: true);                                          build.AddCPlatformFile("${surgingPath}|configs/surgingSettings.json", optional: false,reloadOnChange: true);                                        build.AddEventBusFile("configs/eventBusSettings.json", optional: false);                    build.AddConsulFile("configs/consul.json", optional: false, reloadOnChange: true);#endif                 })                 .UseProxy()                 .UseStartup<Startup>()                 .Build();

            using (host.Run())            {                Console.WriteLine($"服务主机启动成功{DateTime.Now}。");            }

需要注意的是可以通过SurgingServiceEngine来指定surging服务引擎扫描的业务组件的目录。以及也可以通过Startup注入相应的服务或是制定配置文件。

业务框架的分层

一般地,我会将每个微服务组件分为如下几层:

1. Host

用于构建微服务主机和服务寄宿,一般我会直接引用Application层,托管应用服务本身。

2. IApplication 应用接口层

  • 用于定义应用接口,每个应用接口都应当继承IServiceKey,Surging通过应用接口生成服务条目(ServiceEntry)
  • 使用ServiceBundle特性来标识路由模板。
  • 可以使用ServiceCommand来对Action进行注解,该元数据会被注册到服务注册中心,在RPC通信过程中,通过ServiceCommand注解的元数据实现服务治理。该特性可不需要配置,可以通过SurgingSettings.json统一指定相关的配置,如果配置了ServiceCommand特性,会优先选择特性指定的配置值。
  • 可以通过Service特性指定Action的一些元数据。
  • 应用接口层除了定义应用接口之外,还需要定义相关的DTO对象。
  • 应用接口层可以被其他微服务组件应用或是通过nuget进行分发,通过IServiceProxyFactory创建应用接口的代理,从而实现RPC通信。

3. Application 应用层

  • 应用层主要是实现业务流程和输入输出判断,不实现复杂的业务逻辑
  • 应用层的应用需要实现应用接口定义的接口,并继承ProxyServiceBase,基类ProxyServiceBase提供了一些通用的方法。

4. Domain 领域层

  • 领域层主要是实现具体的业务逻辑

5. Domian.Shared

  • 定义微服务组件通用的值类型(model或是枚举类型),可被其他微服务组件引用

容器化服务和服务编排

服务容器化

docker是一款优秀的容器引擎产品。将服务容器化,能够最大化的发挥微服务的体验性。能够让开发者感受到docker构建一次,处处运行的魅力所在。所以我强烈推荐在开发过程中,使用docker容器化服务组件,使用docker-compose编排微服务组件。
vs对docker-compose进行开发调试提供了非常友好的体验性。
一般地,会在服务组件的Host层提供Dockerfile用于构建docker镜像。如下的dockerfile提供了微服务组件的编译、构建等过程。

1234567891011121314151617181920212223242526
FROM microsoft/dotnet:2.2.0-runtime AS baseWORKDIR /appARG rpc_port=100ARG http_port=8080ARG ws_port=96ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone EXPOSE ${rpc_port} ${http_port} ${ws_port}

FROM microsoft/dotnet:2.2-sdk AS buildWORKDIR /srcCOPY . .ARG sln_nameRUN dotnet restore ${sln_name} && \    dotnet build --no-restore -c Release ${sln_name}

FROM build AS publishARG host_workdirWORKDIR ${host_workdir}RUN dotnet publish --no-restore -c Release -o /app

FROM base AS finalARG host_nameENV host_name=${host_name}COPY --from=publish /app .ENTRYPOINT dotnet ${host_name}

服务编排

使用docker-compose编排微服务组件,一般的,使用docker-compose.yml定义镜像构建的上下文、指定网络、镜像名称、挂载的目录等,通过docker-compose.override.yml来指定配置文件的环境变量,.env来设置环境变量的值,通过docker-compose.vs.debug.yml来指定调试过程中的相关设置(部署中可不指定该编排文件)。

需要注意的是,surging在开发过程中,基础服务也通过docker-compose来编排和启动,且必须在开发和调试前启动基础服务。基础服务和surging服务组件指定的网络必须同一个。

基础服务编排如下所示:

12345678910111213141516171819202122232425262728293031323334353637383940
version: ‘3.7‘

services:  consul:    image: consul:latest    ports:      - "8400:8400"      - "8500:8500"      - "8600:8600"      - "8600:8600/udp"    command: "agent -server -bootstrap-expect 1 -ui -client 0.0.0.0"    networks:      - surging_hero_service_net  redis:    image: redis:latest    ports:      - "6379:6379"    networks:      - surging_hero_service_net  rabbitmq:    image: rabbitmq:management    environment:      RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG"      RABBITMQ_DEFAULT_USER: "rabbitmq"      RABBITMQ_DEFAULT_PASS: "rabbitmq"      RABBITMQ_DEFAULT_VHOST: "/"    ports:      - "15672:15672"      - "5672:5672"    networks:      - surging_hero_service_net

networks:  surging_hero_service_net:     driver: bridge    name: surging_hero_service_net    ipam:      driver: default      config:      - subnet: 172.22.0.1/16

由于开发过程中的基础服务并没有考虑到高可用,在生产环境中建议基础服务集群化。

微服务组件的编排请参考: https://github.com/surging-cloud/Surging.Hero/tree/develop/hero/docker-compose/surging.hero

开发与调试

其实在开发过程中,由于业务模块的不同,责任人不同,开发团队不同,开发者拥有的权限不同,业务模块的代码有可能放到不同的git仓库。建议将微服务服务组件的应用接口层和Domian.Shared可以发布的企业内部的nuget服务。其他微服务组件可以通过nuget服务引用应用接口层和Domian.Shared组件。
如果源代码都放到一个git仓库中,也可以建立多个解决方案或是docker-compose编排文件项目来编排不同的服务,方便开发和调试。

常见问题

首次使用docker-compose进行调试服务时,由于vs会从网络上下载vsdbg组件,由于网络原因,一般都会比较慢,开发者可以从其他同事的电脑的家目录下拷贝vsdbg到本机,重新打开vs,然后再进行调试。

Devops

业务流程

在开发过程中,我们使用Jenkins实现持续集成和部署。整个流程如下所述:

  1. 开发者编写业务代码或修复完bug后,提交代码,push到远程仓库,并发起pr请求,请求合并到develop分支。
  2. 当代码审核通过后,合并到develop分支后,通过设置gitlab或是giteewebhook,触发jenkins执行构建。或是通过设置Jenkins的定时任务检测代码库变化,当代码库变化后,jenkins获取最新代码,执行构建操作(由于当时我们Jenkins部署的环境是内网,gitee无法访问公司内网,所以无法设置webhook)
  3. Jenkins通过预先设置好的命令和脚本执行构建打包程序。本质上是执行docker-compose build打包docker镜像,当完成构建和打包docker镜像后,然后将镜像推送到企业内部的docker镜像仓库。
  4. 之后,jenkins通过Jenkins SSH插件将部署脚本拷贝到k8集群的master节点,通过ssh插件在k8s master节点执行部署命令。完成后,微服务集群将自动部署到指定的k8s集群中。

整个devops流程如下所述(但是我们没有与钉钉做集成):

注意事项

  1. 企业内部的docker仓库除了可以使用harbor搭建之外,还可以使用nexus。推荐使用nexus作为仓库管理服务,因为nexus除了支持docker镜像仓库之外,还支持nuget包、npm等格式的包管理。
  2. 建议企业内部在构建业务平台时,根据业务模块划分主题,一个主题对应一个数据库,一个git仓库,一个项目组,多个相关的微服务组件,一个Jenkins构建项目。每个主题独立的进行持续集成与部署。
  3. 建议基础服务consul、rabbitmq、redis考虑集群。

产品交付和部署

  1. 一般的,我们通过docker镜像完成产品交付与部署。可以通过编写部署脚本在k8s集群或是通过rancher进行部署。
  2. 可以使用k8s或是rancher提供的Dashborad进行容器和服务的监控和管理。

体会

  1. surging的设计思想是无疑正确的。相比于市面上其他的.net微服务框架或是分布式框架,无论是服务治理还是内部通信机制,服务引擎设置,主机寄宿均有独到之处。(abp vnext的微服务框架通过内部网关Ocelot进行通信,完全违反的去中心化设计,而且性能也相对较差的多)
  2. 在使用surging的过程中,也遇到了一些问题或是bug(例如:1.首次访问性能较差;2.服务实例无法支持同时扩展),在反馈到github社区或是请求作者协助,都能够得到及时反馈。目前作者已经即将完成对surging2.0的开发,相信会有更优秀的体验。
  3. 在开发和测试、部署和产品交付中推荐将服务容器化,推荐使用linux作为部署服务器。

最后

  • 如果你对surging感兴趣,可以在github(https://github.com/dotnetcore/surging)上对surging关注。
  • 如果你对如何使用surging落地开发,您可以在github上关注surging.hero(https://github.com/surging-cloud)。
    • surging.hero是一个使用surging作为开发框架的权限管理平台。目前项目刚刚开始,欢迎各位开发者加入,如果您想加入surging.hero的开发或是愿意为surging的生态做出贡献,欢迎加入surging-cloud社区。
    • 如果你希望加入surging-cloud社区,可以将你的github账号通过email到:[email protected],并备注`申请加入 surging-cloud社区 即可。
    • 如果您对surging.hero感兴趣并希望加入surging.hero的开发,也可以申请加入qq群:713943626
  • 如果大家对surging确实感兴趣,后期我有时间的话,可以写一些我使用surging的经验或是对源码的理解。

原文: https://liuhll.github.io/hexo-blog-deploy/2019/07/22/2019-07-surging-practical-experi/

原文地址:https://www.cnblogs.com/bea084100123/p/11234877.html

时间: 2024-10-14 10:12:56

Surging实践经验的相关文章

MAVEN实践经验

1安装与配置 jdk: 1.6或以上 下载MAVEN3.x版本,解压后放在随便一目录,然后在系统环境变量配置MAVEN路径. 运行cmd-->输入 mvn -version 会出现maven版本信息. 此处有机会出错,如显示JAVA_HOME问题,请配置JAVA_HOME即jdk路径,然后在path中比maven变量靠前的位置配置JAVA_HOME变量,最后记得重启.问题解决. 因为有前人总结,我就不作太多说明了. 具体请参照: http://blog.csdn.net/chenxuejiaka

deep learning实践经验总结2--准确率再次提升,到达0.8,再来总结一下

deep learning实践经验总结2 最近拿caffe来做图片分类,遇到不少问题,同时也吸取不少教训和获得不少经验. 这次拿大摆裙和一步裙做分类, 多次训练效果一直在0.7,后来改动了全链接层的初始化参数.高斯分布的标准差由0.001改为0.0001,就是调小了. 然后效果很明显,准确率高了,权重图画出来后,也看得出是有意义的了,部分权重图是人的轮廓或者裙子的轮廓. 先看看图片: 大摆裙      一步裙      然后找一些响应图看一下,当然我这里展示的是一些效果好的响应图. 大摆裙   

根据实践经验,讲述些学习Java web能少走的弯路,内容摘自java web轻量级开发面试教程

在和不少比较上进的初级程序员打交道的过程中,我们总结出了一些能帮到合格程序员尽快进阶的经验,从总体上来讲,多学.多实践不吃亏.本文来是从 java web轻量级开发面试教程从摘录的. 1  哪些知识点可以延后了解 在Java Core方面,下表中的知识点你可以不学习或者到用的时候再学习. 知识点 学习的时机 界面开发方面的知识,比如Swing等 Java主要用在Web方面,很少有项目会用到这些UI部分的知识点.大家可以等实际用到时再学习 Socket编程方面 可以先了解概念,等有项目需求时再学习

MaxCompute读取分析OSS非结构化数据的实践经验总结

摘要: 本文背景 很多行业的信息系统中,例如金融行业的信息系统,相当多的数据交互工作是通过传统的文本文件进行交互的.此外,很多系统的业务日志和系统日志由于各种原因并没有进入ELK之类的日志分析系统,也是以文本文件的形式存在的. 1. 本文背景 很多行业的信息系统中,例如金融行业的信息系统,相当多的数据交互工作是通过传统的文本文件进行交互的.此外,很多系统的业务日志和系统日志由于各种原因并没有进入ELK之类的日志分析系统,也是以文本文件的形式存在的.随着数据量的指数级增长,对超大文本文件的分析越来

华为云对Kubernetes在Serverless Container产品落地中的实践经验

华为云容器实例服务,它基于 Kubernetes 打造,对最终用户直接提供 K8S 的 API.正如前面所说,它最大的优点是用户可以围绕 K8S 直接定义运行应用. 这里值得一提是,我们采用了全物理机的方案,对于端到端资源利用率有一个很大的提升.而在 K8S 之上我们通过一层封装实现了超规模资源池.大家知道 K8S 现开源的版本最大只能支持到5000节点,并且这是在 Google 云上的验证结果,而在很多其他的云平台往往达不到.主要是受限于底层网络和存储系统. 所以在华为云,我们的做法是通过一层

.Net core2.0+Mysql5.7部署到CentOS7.5完整实践经验

原文:.Net core2.0+Mysql5.7部署到CentOS7.5完整实践经验 本文为本人最近学习将.Net Core部署到Linux的一些经验总结,也提供点也和我一样对Linux接触不多的.Net Core开发者. 一.部署用到的环境和工具 1.Linux采用最新的CentOS7.5版本,开发使用VS2017搭配的.Net Core 为2.0的SDK版本号2.1.202(可到微软官方下载:https://dotnet.microsoft.com/download/dotnet-core/

deep learning实践经验总结

近期拿caffe来做图片分类.遇到不少问题,同一时候也吸取不少教训和获得不少经验. 先看样例再总结经验. 这是一个2类分类器.分的是条纹衣服和纯色衣服. 先看几张图片. 条纹衣服:   纯色衣服: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGluZ2VybGFubGFu/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > 肉眼也非常eas

黄洁:Intel Spark应用优化和实践经验

摘要:黄洁就Spark的内存管理.IO提升和计算优化3个方面进行了详细讲解.黄洁表示,对比MapReduce,Spark擅长于复杂的机器学和图的计算.流处理等多种业务场景. [编者按]干货满满的2015 OpenStack技术大会.2015 Spark技术峰会.2015 Container技术峰会以实力赢得所有观众的认可.在Spark峰会上,英特尔大数据技术中心研发经理黄洁就Spark的内存管理.IO提升和计算优化3个方面进行了详细讲解,以下为演讲概述. 下为演讲概述 我来自Intel大数据技术

FreeWheel基于Go的实践经验漫谈——GC是大坑(关键业务场景不用),web框架尚未统一,和c++性能相比难说

摘自:http://www.infoq.com/cn/news/2017/06/freewheel-experience-on-go Go语言是FreeWheel公司目前主要力推的一个方向,在其看来,面向服务的架构的大环境中,Go非常适合做一些功能相对独立.功能比较明确的微服务的语言.在结合已有的各种编程语言,计算框架(如Hadoop.Java.Ruby.C++)的基础上,FreeWheel把Go语言定位成用来实现轻量级服务或API的缺省编程语言,将之与用来完成更小粒度工作的Python结合在一