微服务架构学习笔记(SpingBoot+Dubbo+Zookeeper)

微服务架构

自述

    近段时间在学习微服务架构,结合前辈们的一些博客、网上的教学视频以及官方的一些技术文档,我整理了一下自己的学习笔记,一边归纳一边复习。在这里上传笔记做以后的回顾储备。

微服务架构基本概念介绍

一、什么是微服务?什么是微服务应用?什么是微服务架构?

  1. 微服务:从技术维度的角度理解,微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或销毁,甚至可以拥有自己独立的数据库。(微服务可以使用不同的语言进行开发,微服务只是业务逻辑的代码,不会和html,css或其他界面组件混合)
  2. 微服务应用: 使用伸缩立方的模式来进行部署的概念,我们会有一个专门的负载均衡服务器,每一个实例部署到docker容器之上,每一个服务都有他独立的数据库,那么这就是微服务应用。
  3. 微服务与微服务架构(区别):

    微服务:*eclipse工具里面用maven开发的一个个独立的小moudle,它具体是使用springboot 开发的一个小模块,专业的事情交给专业的模块来做,一个模块就做一件事情。强调的是一个个的个体,每个个体完成一个具体的任务或者功能(举例:医院里各个单一的科室就相当于一个个的微服务*)

    微服务架构:微服务架构是一种架构模式,它强调的是整体,运用哪些方式把一个个的微服务组装拼接起来,对外形成一个整体,对外暴露服务。
区别举例:中华民族是一种微服务架构,中华民族由56个民族构成,每一个民族就是一个个的微服务。

二、传统开发模式与微服务架构开发模式的区别

  1. 传统开发模式(单体式开发):所有的功能打包在一个 WAR包里,基本没有外部依赖(除了容器),部署在一个JEE容器(Tomcat,JBoss,WebLogic)里,包含了 DO/DAO,Service,UI等所有逻辑。
    传统服务模式


优点:

(1)开发简单,集中式管理

(2) 基本不会重复开发

(3)功能都在本地,没有分布式的管理和调用消耗


缺点:

(1) 效率低:开发都在同一个项目改代码,相互等待,冲突不断

(2) 维护难:代码功功能耦合在一起,新人不知道何从下手

(3) 不灵活:构建时间长,任何小修改都要重构整个项目,耗时

(4) 稳定性差:一个微小的问题,都可能导致整个应用挂掉

(5) 扩展性不够:无法满足高并发下的业务需求

  1. 微服务架构开发模式:有效的拆分应用,实现敏捷开发和部署
    微服务架构模式

    关于微服务的一个形象表达:
    微服务架构形象图

    X轴:其上运行着多个实例,每个服务配合负载均衡器以满足吞吐量和可用性

    Y轴:将应用进一步分解为微服务(分库)

    Z轴:大数据量时,将服分区(分表)


优点:

(1) 通过分解巨大单体式应用为多个服务方法解决了复杂性问题

(2) 使得每个服务都可以有专门开发团队来开发

(3) 微服务架构模式是每个微服务独立的部署

(4) 微服务架构模式使得每个服务独立扩展

(5)可以灵活的搭配,连接公共库+连接独立库


缺点:

(1) 微服务架构是一个分布式系统,其使得整体变的复杂。开发者需要选择和实现基于消息或者RPC的进程间通讯机制,并且需要编写代码来处理局部故障

(2) 微服务架构是分区数据库架构,通常不会选择分布式事务,不仅仅是因为CPA定理,微服务架构根本不支持NoSQL和消息代理,事务的使用也变的及其困难。在单体式开发中,使用事务可能就一个注解可以解决,而微服务架构不行。你最终不得不使用基于最终一致性的方法。

(3) 在变更服务之前,必须理清楚各个服务间的依赖关系,由高到低的依次变更。比较好的是大多数变更只会影响一个服务

(4) 测试微服务应用程序也很复杂,一个简单的测试类对于微服务来说需要启动该服务及其他所依赖的所有服务,或者至少为这些服务配置存根

三、微服务(架构)的具体特征

  1. 来自官方的定义:

    (1) 一些列的独立的服务共同组成系统

    (2) 单独部署,跑在自己的进程中

    (3) 每个服务为独立的业务开发

    (4) 分布式管理

    (5) 非常强调隔离性

  2. 大致的标准:

    (1) 分布式服务组成的系统

    (2) 按照业务,而不是技术来划分组织

    (3) 做有生命的产品而不是项目

    (4) 强服务个体和弱通信( Smart endpoints and dumb pipes )

    (5) 自动化运维( DevOps )

    (6) 高度容错性

    (7) 快速演化和迭代

四、怎么具体实现微服务架构?


要实现的应用微服务,需要解决一下四点问题:
1. 客户端如何访问这些服务?

解决:一般在后台N个服务和UI之间一般会一个代理或者叫API Gateway,他的作用包括:

① 提供统一服务入口,让微服务对前台透明

② 聚合后台的服务,节省流量,提升性能

③ 提供安全,过滤,流控等API管理功能

其实这个API Gateway可以有很多广义的实现办法,可以是一个软硬一体的盒子,也可以是一个简单的MVC框架,甚至是一个Node.js的服务端。他们最重要的作 用是为前台(通常是
移动应用)提供后台服务的聚合,提供一个统一的服务出口,解除他们之间的耦合。

  1. 每个服务之间如何通信?

    两种方法,一种是“远程过程调用(RPC)”,另一种是“消息驱动API(基于rest API 的方式)”

    http(restful):各种语言都支持http协议,对于开放的API,比如开放平台等使用http协议较为广泛,因为它没有了对使用技术语言的限制。

    **RPC:**rpc协议的性能要高上许多,例如Protobuf、Thrift、Kyro等,(算上序列化的话)吞吐量近乎http的两倍,响应时间也更为出色。

    ps:模块间通过语言级方法/过程调用互相调用

  2. 如此多的服务,如何实现?

    实现:基本都是通过zookeeper等类似技术做服务注册信息的分布式管理。当服务上线时,服务提供者将自己的服务信息。注册到ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过ZK寻址,根据可定制算法, 找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK会发通知给服务客户端。

    客户端做:优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支持,比如Dubbo。

    服务端做:优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多。
    服务治理

  3. 服务挂了,如何解决?(备份方案,应急处理机制)

    几种解决方法如下:

    ①重试机制

    ②限流

    ③熔断机制

    ④负载均衡

    ⑤降级(本地缓存)

五、六种常见的微服务架构设计模式

  1. 聚合器微服务设计模式

    这是一种最常见也最简单的设计模式:聚合器调用多个服务实现应用程序所需的功能。它可以是一个简单的Web页面,将检索到的数据进行处理展示。它也可以是一个更高层次的组合微服务,对检索到的数据增加业务逻辑后进一步

    发布成一个新的微服务,这符合DRY原则。另外,每个服务都有自己的缓存和数据库。如果聚合器是一个组合服务,那么它也有自己的缓存和数据库。聚合器可以沿X轴和Z轴独立扩展。
    聚合器微服务设计模式
  2. 代理微服务设计模式

    这是聚合模式的一个变种(如下图所示),在这种情况下,客户端并不聚合数据,但会根据业务需求的差别调用不同的微服务。代理可以仅仅委派请求,也可以进行数据转换工作。
    代理微服务设计模式
  3. 链式微服务设计模式

    这种模式在接收到请求后会产生一个经过合并的响应(如下图所示),在这种情况下,服务A接收到请求后会与服务B进行通信,类似地,服务B会同服务C进行通信。所有服务都使用同步消息传递。在整个链式调用完成之前,客户端会一直阻塞。因此,服务调用链不宜过长,以免客户端长时间等待。
    链式微服务设计模式
  4. 分支微服务设计模式

    这种模式是聚合器模式的扩展,允许同时调用两个微服务链,如下图所示:
    分支微服务设计模式
  5. 数据共享微服务设计模式

    自治是微服务的设计原则之一,就是说微服务是全栈式服务。但在重构现有的“单体应用(monolithic application)”时,SQL数据库反规范化可能会导致数据重复和不一致。
    因此,在单体应用到微服务架构的过渡阶段,可以使用这种设计模式,如下图所示:

    数据共享微服务设计模式

    在这种情况下,部分微服务可能会共享缓存和数据库存储。不过,这只有在两个服务之间存在强耦合关系时才可以。对于基于微服务的新建应用程序而言,这是一种反模式。
  6. 异步消息传递微服务设计模式

    虽然REST设计模式非常流行,但它是同步的,会造成阻塞。因此部分基于微服务的架构可能会选择使用消息队列代替REST请求/响应,如下图所示:
    异步消息传递微服务设计模式

后台微服务模式架构的项目实践(springboot集成dubbo,注册中心使用zookeeper)

一、搭建项目


搭建方案与之前的单体开发相似,不同之处在于微服务的那种模式(优点:高可用,高并发),即:每一个服务都是一个项目,每一个项目都会提供它相应的服务(划分不宜太细和太大)。此处实践后台开发与单体开发思路差不多,主要是将每个服务单独提出来作为微服务项目的节点。
1. 创建依赖管理项目(dependencies):自定义的properties(后文举例起名为“dependencies”),提供依赖服务,并作为后面服务的parent
2. 创建通用工具项目(Commons):因为微服务架构的原理,几个服务不是一个人在开发,可能你处在一个协同开发的状态。所以,你在开发某个服务的时候,实际上你并没有你需要的这个依赖服务,所以你需要把这个依赖服务安装到本地的maven仓库中(这样才有的依赖)。在实际开发过程中,则一般会创建一个maven私服,每个小组成员会将自己完成的模块上传到私服上,所有的的协同可以通过私服来下载这个版本。

(1)安装到本地仓库:Terminal ——>cd 依赖服务 ——>mvn clean install
3. 创建数据库管理项目(database):主要就是用来放实体类的,则我们需要将database生成的实体类移植过来(就是将database自动生成的实体类及相关mapper文件,这里只需要将database生成的实体类加入进去,生成的mapper和application.yml文件复制到admin服务中,admin服务需引入Commons服务依赖,并修改包名和mapper中的路径等)。
4. 创建管理后台接口项目(admin-api):整个大的项目是使用dubbo来做RPC通讯,所以我们会有一个项目(服务)只负责定义接口,则称“接口项目”。
5. 创建管理后台实现项目(admin):仅负责接口的实现,接口业务逻辑和对数据库的操作都在这里完成。在使用dubbo来实现服务间通讯时,这里为服务提供者。
6. 创建前台web项目(admin):作为服务消费者,调用接口

创建的服务截图

服务消费者

二、问题与技术选型

  1. 问题1:新建一个web服务,调用接口展示数据。问题在于,web服务依赖“定义接口的服务”则如何能够获取接口的实现呢?如果web服务依赖“接口实现服务”,则耦合度增高,违背微服务架构思想,与单体开发无差别,最多称为“模块式开发”。解决问题1,就要采用其他方式去实现服务间的通讯,而不是通过单纯的依赖引用。
  2. 通讯方式:对内RPC,对外REST(补充:内部都是采用性能更高的RPC方式。而对外开放的才是RESTful。)
  3. 选择以上通讯方式,选择实现技术是:使用dubbo来实现服务间的rpc通讯,“服务治理”采用的是zookeeper的方式来实现,因为zookeeper实现了分布式锁,一是解决了“单点故障”问题,二是解决了“多组多重”问题(以上两点具体介绍见“三、Dubbo与zookeeper”)。
  4. 做微服务架构最起码的三样东西:服务注册、服务调用、服务网关(没有服务注册就没有高可用)

三、Dubbo和Zookeeper


dubbo实现的是高性能(分布式特点),zookeeper实现的是高可用(集群特点),“高可用”就是指一直可以用。
1. Dubbo

服务提供方(provider)、一个服务消费方(consumer)

(1)服务治理:

服务

(2)核心功能:
1. 远程通讯,提供多种NIO框架抽象封装,包括“同步转异步”和“请求-响应”模式的信息交换方式
2. 服务框架,提供基于接口方法的透明远程过程调用,包括多协议支持,以及负载均衡,失败容错,地址路由,动态配置等集群支持
3. 服务注册中心,服务自动发现:基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明

(3)组件角色:

组件角色

关系说明
2. Zookeeper

服务注册中心。开发过程中解决“单点故障”的方法是采用“主从模式”提供服务,zookeeper解决了以上方法出现的脏读、脏写以及脏数据的问题。

单点故障

单点故障

传统方式解决单点故障

解决单点故障

备用节点会不定时的去ping主节点,主节点接收ping包之后会发送一个ack包(回复包)给备用节点。备用节点接收到ack包,则表示主节点还活着。若备用节点没能接收到ack包,则接替主节点提供服务。但是,如果网络出问题了导致备用节点没能接收到ack包,则备用节点和主节点会一并都在提供服务,导致脏读、脏写以及脏数据(见“出现脏数据问题”)。

出现脏数据问题

脏数据

在此处,抢主程序是包含在服务程序中,需要程序员来手动写抢主逻辑的,比如当当开源框架elastic-job中,就有关于选主的部分。zookeeper自己在集群环境下的抢主算法有三种,可以通过配置文件来设定,默认采用FastLeaderElection,不作赘述;此处主要讨论集群环境中,应用程序利用master的特点,自己选主的过程。程序自己选主,每个人都有自己的一套算法,有采用“最小编号”的,有采用类似“多数投票”的,各有优劣。

结构展示图

结构图解释:左侧树状结构为zookeeper集群,右侧为程序服务器。所有的服务器在启动的时候,都会订阅zookeeper中master节点的删除事件,以便在主服务器挂掉的时候进行抢主操作;所有服务器同时会在servers节点下注册一个临时节点(保存自己的基本信息),以便于应用程序读取当前可用的服务器列表。

四、使用前准备

  1. 安装Zookeeper到虚拟机,使用docker来跑
  2. 本地操作:登录https://github.com/

    搜索dubbo

    转到https://github.com/apache/incubator-dubbo路径下

    进入之后,点击Links下的Dubbo-ops,克隆ops源码

    在当前ops源码目录下,使用cmd(命令行操作符)打包:mvn clean package(在这步之
    前先确认一下dubbo-admin的pom中的打包方式,不是war包的改成war包)

    打完包,进入dubbo-admin/target/,复制“dubbo-admin-版本号”这个文件

    放到Tomcat下webapps/,替换dubbo-admin文件为“dubbo-admin-版本号”再删去版本号

    因为注册中心这里使用的是zookeeper,所以需要配置一下注册中心:
    1. Tomcat/webapps/dubbo-admin/WEB-INF路径下的dubbo-properties文件中配置
    2. 运行Tomcat/bin/startup.bat
    3. 启动Tomcat查看dubbo(http://localhost:8080/dubbo-admin

五、具体在项目中使用

修改依赖管理项目


增加dubbo的starter pom与zookeeper客户端的相关依赖

web层依赖了api服务是因为需要和admin服务之间通讯,而api服务又依赖了domain,在domain服务依赖了Druid,且在application.yml,我们配置了数据库连接,这里这样配置是不合理的,因为web层不应该能访问数据库,它应该只可以访问业务逻辑,由业务逻辑去访问数据库。

修改方法:
1. 在自定义的dependencies服务中增加第三方仓库(直接将一下代码加入到对应的pom.xml)

如图配置的话:项目在寻找依赖时,会先在中央仓库找,中央仓库如果没有的话会在如下配置的仓库中寻找依赖。

用于依赖Alibaba的Dubbo Starter POM
依赖
2. 增加Alibaba Dubbo Starter POM
Alibaba
3. 增加Zookeeper客户端依赖

zookeeper
4. 修改domain服务

在domain服务的pom.xml文件中,将依赖的Druid删除,在application.yml配置文件中删除Druid配置,并且删除mybatis配置(原application.yml移至admin服务),将domain服务下的自定义MyMapper接口放到Commons服务中,因为他是通用的,其他的mapper都要继承他。

如上操作之后,commons服务需要依赖tk-mybatis,让mymapper可以继承如下两个类:
接口继承

所以,修改dependencies服务中的依赖,添加一个只是tk-mybatis的依赖

tk-mybatis

在Common服务中添加如下依赖:

mybatis

domain中所有的实体类需要实现虚拟化接口,如下图:
jiekou

最后删去domain服务中的mapper包和utils包

5. 修改admin服务

将domain服务中的mapper移到admin中,将domain服务中的resource包下的application.yml(配置了Druid和mybatis)移至admin服务下的resource包。

在admin服务中引入Commons服务依赖:
commons

之后再修改mapper相关文件的引用类的路径,同时修改启动类中的basePackages为当前mapper类位置。

六、配置服务提供者(对admin服务进行配置)

  1. pom添加依赖:

    引入的依赖可以参考代码中admin的pom文件
  2. 配置dubbo
    dubbo引用

    base-package:接口服务在哪里,这里就指定哪里(service所在的路径)

    id、name:这是dubbo应用的id和name

    protocol:dubbo协议

    上述配置是根据GitHub上的教程来的https://github.com/apache/incubator-dubbo-spring-boot-project
    application启动

    上图是在admin服务中的启动类添加的一行代码,意思是在告诉dubbo,admin服务是“容器”(根据dubbo的组件角色,我们知道服务提供者往往也是容器)

七、配置服务消费者(对web服务进行配置)


按照官方文档进行添加配置

八、问题解决

1.这里项目实践中依赖的是“高速序列化工具 kryo”,然而项目中的依赖dubbo版本是2.5.9,不支持高速序列化,所以要添加dubbo依赖2.6.0版本(该版本支持rest、高速序列化kryo等)。在dependencies服务的pom中添加dubbo依赖(可以上到中央仓库:mvnresponsity,搜索dubbo找到2.6.0的配置依赖代码)
更换依赖版本

然后再在domain服务中添加dubbo依赖,因为需要依赖dubbo的就服务提供者和服务消费者,而这两者都需要依赖domain服务,所以添加dubbo依赖到domain服务。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值