今天我们来讨论微服务架构实践中经常遇到的一些问题,有的来自于我们自己的微服务改造项目,有的来自于客户现场的服务架构实施项目和售前计划沟通。本文只讨论关键问题,如下:微服务下的数据库划分微服务开发与技术框架选择微服务与DevOps、容器云集成微服务网关与注册中心微服务相关关键技术,如限流熔断器,针对微服务相关的基础知识,比如安全、服务链监控等,网上基本都能搜索到,不再赘述。SOA和微服务的区别,中台架构等,大家也可以参考我之前发布的。文章。分库和微服务是否一定要一对一,我们在最开始讲微服务架构的时候有讲到。为了保证每一个微服务都是独立的、自治的、松耦合的,所有的微服务都必须从数据库到逻辑层再到前台进行垂直拆分。也就是说,数据库的拆分是整个微服务架构设计中的一个关键内容。而且这里有一个关键的思想就是,在微服务的实践中,你会看到其实你上层的微服务组件的拆分会更加细化,一个不那么复杂的业务系统会被拆分成20到30个微服务组件都是正常情况。将数据库拆分成20个独立的DataBase显然是不合理的。一方面,这增加了数据库本身的管理复杂度。同时,由于数据库过于细化,也引入了更多的分布式事务处理问题,跨库数据关联查询不便。所以在这里,最好的建议是我们引入业务域的概念,即:数据库可以按照业务域进行拆分,每个业务域是相当独立的,对应一个独立的数据库,但是业务域本身可以有多个上层微服务模块组件。同一个业务域的微服务仍然是通过注册中心来访问和调用的。即同一业务域内的微服务在逻辑层仍然解耦,只能通过API接口访问和调用,方便分布式部署,但数据库层本身没有拆分,共享同一个数据库。比如在我们的项目中,我们会和4A和流程引擎微服务共享一个数据库,和费用报销、差旅报销、贷款报销等独立的微服务共享一个报销数据库。这种方式虽然没有实现数据库的完全解耦,但是我们可以通过微服务在逻辑层的拆分解耦,实现对微服务部署包更细粒度的管理。同时,当业务逻辑发生变化时,我们只需要更改相应的微服务模块即可,将变化的影响降到最低。不管你是否使用SpringCloud全家桶,你可以看到,如果你使用SpingCLoud微服务技术开发框架,那么对应的服务注册中心,限流熔断器,微服务网关,负载均衡,配置中心,安全,并提供声明式调用的所有功能。你需要做的就是使用SpringBoot框架,一个一个的开发微服务组件。当然,在我们实现的项目中还有另外一种方式,就是只使用SpringBoot框架开发单个微服务组件,然后结合集成目前业界主流的微服务开源技术组件产品。服务注册中心:阿里的Nacos注册中心服务配置中心:携程开源的Apollo配置中心限流断路器:阿里的Sentinel服务链监控:直接集成SkyWalking服务链监控API网关:使用Kong网关实现API集成和控制治理的当然,你也可以完全不使用SpringBoot,而是使用更高效的支持RPC调用的Dubbo开源框架来开发和集成微服务组件。从微服务技术平台的建设和快速发展来看,当然直接选择SpingCLoud的整个开源框架和组件是最简单的,基本可以完全满足需求。对于日常的传统企业应用,性能完全够用,不存在性能达不到的情况。毕竟不是所有项目都类似互联网海量数据访问、大并发的高性能需求。如果使用各种开源组件,自己集成技术框架,那么前期肯定有基础技术平台搭建和集成验证相关的工作量。同时,也会增加整个基础设施的复杂度。比如你使用Nacos注册中心,你还需要对注册中心进行集群配置,以满足高可用需求。基于以上描述,简单总结一下:如果想省事,对性能要求不是太高,可以直接使用SpingCloud的整体框架。如果你对性能要求高,自身技术储备充足,可以自己集成开源技术组件。然后在我们实际的微服务架构实现项目里面,我们就会看到第三个场景。例如某集团企业,其自身的计划管理系统在初步架构设计后拆分为10个微服务模块,需要邀请3名软件开发人员进行定制开发。开发人员还需要开发微服务架构。这时,我们发现了一个关键问题。各个厂商采用微服务架构并不重要,但是从整个大应用的角度来看,我们其实有对10个微服务模块进行统一微服务治理和控制的需求。类似于API网关,类似于服务配置中心等。这些组件并不适合使用SpingCLoud中的技术组件,而是需要从单一的微服务架构体系中抽取出来,形成共享的服务能力。这个时候,我们的建议是尝试集成和使用第三方的其他开源技术组件进行控制和治理。例如,在上面的例子中,三个供应商可以保留最基本的配置。即当某供应商开发A、B、C三个微服务模块时,可以启用Eureka+Feign+Ribbon完成对自己开发的三个组件的内部集成,API接口注册和调用。但是,当需要协调三个供应商的模块时,则统一使用外部搭建的共享技术服务平台。比如API接口注册到统一的Kong网关,Kong网关由平台集成商管理。比如涉及到三个公司的一些通用配置从SpingCloudConfig转移到Apollo配置中心。因此,简单总结一下,在评估是否采用全套SpingCLoud解决方案时,还需要评估跨团队之间是否存在协同效应,边界清晰。或者是否有像集团企业那样大量集成多个业务系统微服务。如果存在,则必须抽取一些通用的技术服务能力,独立构建。开发团队如何拆分?我们在进行微服务和云原生改造的时候,在大家看来是把IT系统分成了多个微服务,但更重要的是,业务组织和团队本身需要分解成微服务和高度独立自主的业务团队。每个团队配备独立的前后端开发、需求、测试人员,具有高度的自主权。那么拆分成以业务为主的团队后,如何保证原有大型应用和产品的概念一致性或架构完整性。这里我们建议整体产品规划和整体架构设计还是需要集中统一,然后拆分分配给各个微服务开发团队。那么这里的架构设计包括什么呢?具体如下:每个微服务模块的功能列表每个微服务模块的接口列表数据库拆分和数据表的所有者归属以上三点是最重要的点,需要提前进行架构设计。这个明确之后,就可以分配到各个微服务团队了。那么微服务团队是高度自治和扁平化的,各个团队可以相互协作和沟通,不需要架构师去协作和增加沟通路径。即产品规划和架构师,与微服务架构中注册控制中心的职责非常相似。这也就是我们常说的微服务的技术拆分。事实上,真正首先是业务组织团队的架构调整和职责分工。那么这个开发团队是如何拆解的呢?首先,你不可能拆分20个微服务,拆分20个开发团队。里面还是有领域划分的概念,就是需要把这20个微服务按照aspect进行分类拆分。方法一:按照垂直业务领域分类,参考我们之前的数据库拆分方法方法二:按照水平层分类,比如平台层团队,中台团队,前台,APP应用团队。团队拆分后,我们可以看到每个开发团队都要配置前端开发、后端开发和测试人员。需求可以统一配置,无需拆分成开发组。当然,也可以给每个开发组分配一个需求提炼员,整个大团队只分配产品经理来生产产品需求。产品需求的细化仍然在开发团队内部完成。为什么这么强调要拆散开发团队?简单地说,每个开发团队的内部工作应该是透明的,对其他开发团队是不可见的。开发团队高度直接,只能通过粗粒度接口交付。如果开发团队本身不拆分,你会看到,当一个开发团队管理多个微服务模块时,我们之前制定的各种微服务开发规范和协议很容易被破坏,而这些事后审核和修订需要花费大量时间更改和返工。举个简单的例子,拆分成两个DataBase库后,在由同一个开发者管理时,往往很容易通过两个库之间的跨库关联查询来解决问题,这在微服务开发规范中是有的。不允许。当然,从软件公司自身的IT治理和控制来说,这也是最好的解决方案。对于一个大型的项目或者应用系统,并不是每个开发者都能看到所有项目模块的源代码,其他不属于自己Owner的组件只能消费和使用接口,其他内容是不可见的。对于服务注册中心和API网关的选择对于服务注册中心和API网关,我前面有专门的文章详细分析。什么时候需要使用API网关?在微服务架构下,虽然没有与其他外部应用交互和集成,但整个应用本身存在于APP应用端,APP应用端通过前后端分析开发,同时需要通过互联网访问。需要有一个统一的访问API访问入口,也需要考虑与内部微服务模块进一步的安全隔离。说到这里,你会发现我们常说的API网关的服务代理或者透传能力,其实和我们常说的Ngnix反向代理或者路由是同一个意思。如果只是想统一API接口的访问出口,考虑类似DMZ区域的安全隔离,那么你的架构前期不需要马上实现API网关,直接使用Ngnix作为服务路由代理。因为在这种架构下,API接口消费者端和提供者端都是由一个开发团队开发的,非常方便分析和排查各种问题。类似的API接口安全访问也可以通过JWT、Auth2.0等实现,这个过程也不复杂。能力开放或多应用外部集成需要API控制和治理。但是,当我们面临与多个外部应用的集成,或者向多个外部合作伙伴开放自己的API接口服务能力时,这时候对API接口控制治理的需求自然会增加。即在常规服务代理路由的基础上,需要增加负载均衡、安全、日志、限流、熔断等各种能力,而我们不希望在开发API接口时考虑这些能力,但是希望这些能力在API接入网关时,通过统一灵活的配置实现管控。那么此时使用API??网关的作用就体现出来了。多个开发团队的协作,服务治理的标准化需求这是我理解的第二种需要API网关的场景,有点类似于传统IT架构下对ESB服务总线的需求。当有多个开发团队时,我们需要统一管理各个开发团队注册和访问的API接口服务,这时候就需要API网关来实现。即跨开发团队的API接口集成和交付的统一管控由API网关复制,包括安全、日志审计、流量控制等,这些内容不可能依赖内部的一些技术和开发规范单一团队当多团队协作约定俗成,但需要有一个统一的标准。同时,当多个开发团队协作集成时,必须有一个统一的集成商来协同解决问题。即使在ServiceMesh服务网格架构下,我们也能看到有一个统一协调的控制中心。使用API??网关后要注意技术组件的选择。API网关本身具备负载均衡、限流熔断、服务代理等能力。即在注册中心下,Eureka+Feign+Ribbon+Hystrix都可以通过API网关来完成。但是,一个完整的微服务架构的应用可能会有一个API接口,不仅需要满足内部组件的API消费调用,还需要通过API网关将接口暴露给外部应用。通过API网关对外预留HttpRestAPI接口,传统的API消费访问不再是Feign-like声明方式调用内部API接口。如下图所示:可以看出微服务A需要满足内部微服务B作为消费者通过服务注册中心进行消费调用的需求,同时还需要满足外部APP进行消费调用的需求通过API网关接口。那么进入微服务A集群的流量其实并没有一个统一的入口。在这种场景下,如果企业有Hystrix限流断路器,它只控制内部微服务模块组件之间的消费调用。对于外部APP限流,还是需要在网关上开启限流熔断功能。微服务架构与容器云集成的集群与负载均衡最后说一下微服务架构与Kubernetes+Docker容器云集成后的服务发现与负载均衡。前面提到,在使用Eureka服务注册中心时,对于同一个微服务模块A,我们可以启动多个不同端口号的微服务实例。端口启动后,通过Eureka实现服务的自动注册和发现。然后使用Ribbon实现服务访问的负载均衡。也就是说,我们添加和部署微服务模块一个节点是手动完成的。但是在DevOps的持续融合下,实现Kubernetes+Docker容器云后,我们可以使用k8s来实现微服务节点资源的动态扩展。扩展的Pod资源由Kubernetes统一,实现集群负载均衡,即只需要通过Node+端口号对外访问即可。所以这个时候其实有两种做法。方法一:不再使用Eureka服务注册和发现此时不再使用Eureka服务注册和发现,而是通过Kubernetes动态部署的VIP访问,Kubernetes会在后台节点进行负载均衡。这个时候我们只能按照调用HttpRestAPI接口的常规方式来消费和调用接口,原来的Feign声明式调用可能已经不适合了。也就是说,在这个场景下,你只需要使用SpringBoot来开发独立的可以暴露HttpRestAPI接口的微服务。不再使用SpringCLoud框架中的Eureka+Feign+Ribbon。方法二:使用Eureka替换Kubernetes中的Service。该场景下并没有使用Kubernetes本身的集群功能,而是将动态部署的微服务模块自动注册到Eureka服务注册中心进行统一管理。即架构还是按照传统的SpringCLoud框架体系搭建。在这种思路下,SpingCLoud下的限流、容错、心跳监控等关键能力可以进一步保留。实践3:进一步的思路是ServiceMesh。其实我们看到更进一步的思路是类似Istio的完全去中心化的微服务治理方案。在这种模式下,可以利用Sidecar更好地实现相关服务注册、发现、限流熔断、安全等各种关键服务治理和控制能力。如果所有的微服务模块都通过Kubernetes部署到Docker容器中,那么我们可以看到在k8s进行镜像和容器部署时,可以将SideCar的内容添加到具体的部署包中,实现集成。简单的说,我们在开发微服务模块时不需要过多考虑分布式API接口的集成和交互,而是在与Kubernetes和ServiceMesh集成后,具备了调用和集成分布式接口的能力。同时,还具备API接口、日志、限流、熔断等安全管理能力。因此,人们常说ServiceMesh是Kubernetes支撑微服务能力的最后一块。
