一、分布式基础概念
1、微服务
微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API。这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署。这些服务使用不同的编程语言来书写,以及不同数据存储技术,并保持最低限度的集中式管理。
简而言之:拒绝大型单体应用,基于业务边界进行服务化拆分,各个服务独立部署运行。
2、集群&分布式&节点
集群是个物理形式,分布式是个工作方式。
只要是一堆机器,就可以叫集群,他们是不是一起协作着干活,这个谁也不知道;
分布式是指将不同的业务分布在不同的地方。建立在网络之上的软件系统。
集群指的是将几个服务器集中在一起,实现同一业务。
分布式中的每一个节点,都可以做集群。而集群不一定就是分布式的。
节点: 集群中的一个服务器。
3、远程调用
在分布式系统中,各个服务可能处于不同主机,但是服务之间不可能避免的需要相互调用,我们成为远程调用。
SpringCloud中使用HTTP+JSON 的方式完成远程调用。
4、负载均衡
分布式系统中,A服务调用B服务,B服务在多台机器中都存在,A调用任意一个服务器均可完成功能。
为了是每一个服务器都不要太闲或者太忙,我们可以负载均衡的调用每一个服务器,提升网站健壮性。
常见的负载均衡算法:
轮询: 为第一个请求选择健康池中的第一个后端服务器,然后按顺序往后依次选择,直到最后一个,然后循环。
最小连接: 优先选择连接数最小,也就是压力最小的后端服务器,在会话较长的情况下可以考虑采取这种方式。
散列: 根据请求源的IP的散列(hash)来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。如果你的应用需要处理转态而要求用户能连接到和之前相同的服务器,可以考虑采取这种方式。
5、服务注册/发现&注册中心
A服务调用B服务,A服务并不知道B服务当前在哪几台服务器有,哪些正常的,哪些服务已经下线。解决这个问题可以引入注册中心;
如果某些服务下线,我们其他人可以实时的感知到其他服务的状态,从而避免调用不可用的服务
6、配置中心
每一个服务最终都有大量的配置,并且每个服务都可能部署在多台机器上。我们经常需要变更配置,我们可以让每个服务在配置中心获取自己的配置。
配置中心用来集中管理微服务的配置信息
7、服务熔断&服务降级
在微服务架构中,微服务之间通过网络进行通信,存在相互依赖,当其中一个服务不可用时,有可能会造成雪崩效应。要放置这样的情况,必须要有容错机制来保护服务。
1)、服务熔断
设置服务的超时,当被调用的服务经常失败到达某个阈值,我们可以开启断路保护机制,后来的请求不再去调用这个服务。本地直接返回默认的数据
2)、服务降级
在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务降级运行。
降级: 某些服务不处理,或者简单处理【抛异常、返回null、调用Mock数据、调用Fallback处理逻辑】。
8、API网关
在微服务架构中,API Gateway作为整体架构的重要组件,它抽象了微服务中都需要的公共功能,同时提供了客户端负载均衡,服务自动熔断,灰度发布,统一认证,限流流控,日志统计等丰富的功能,帮助我们解决很多API管理难题。
二、环境搭建
1.安装linux虚拟机
推荐使用VMware 或者VrtualBox,这里用VirtuBox演示:
下载并安装VirtualBox。(需要开启cpu虚拟化)
https://download.virtualbox.org/virtualbox/6.0.10/VirtualBox-6.0.10-132072-Win.exe
安装好后就可以在VirtualBox里安装linux系统,可以使用传统方式安装,也可以使用Vagrant技术安装:
Vagrant下载地址: https://releases.hashicorp.com/vagrant/2.2.5/vagrant_2.2.5_x86_64.msi
如何验证Vagrant是否安装成功? 在cmd>> vagrant 。如果提示Vagrant的命令提示则证明安装成功.
使用Vagrant快速的给VirtualBox创建linux虚拟机:
在windows cmd窗口下运行 Vagrant init centos/7,即可初始化一个centos7系统。
执行命令vagrant up ,此过程时间稍长
连接虚拟机: 执行 vagrant ssh
退出虚拟机的连接: exit
以后启动虚拟机只需在cmd窗口下执行vagrant up命令即可,前提是保证 当前用户文件夹下有Vagrantfile文件;
通过vagrant ssh命令连接该虚拟机。
配置虚拟机的ip,给虚拟机一个固定的ip地址,让windows可以ping通
更改linuxip可以用vagrant命令,但是太麻烦了,还可以在windows用户目录下的Vagrantfile文件中更改相关配置(35行)
首先需要确定VirtualBox的ip
然后改Vagrantfile中的配置
改完后重启虚拟机: 执行命令vagrant reload
重新连接: vagrant ssh
查看虚拟机ip是否已经变为192.168.56.10;
1、教程变了,但是我实际测试没有,不知道怎么回事?显示我的重启时间超时,本子性能太差或者操作有错误
2、如果成功,windows和虚拟机之间可以相互ping通;不过即便我的没有更改ip,也可以相互ping通;
2.安装docker
docker是虚拟化容器技术,docker基于镜像,可以秒级启动各种容器.每个容器都是一个完整的运行环境,容器之间相互隔离.
安装:https://docs.docker.com/engine/install/centos/
① 首先需要卸载旧版本
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
② 安装yum-utils软件包(依赖包,提供yum-config-manager实用程序)并设置稳定的存储库
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
③ 安装docker引擎
$ sudo yum install docker-ce docker-ce-cli containerd.io
④ 启动docker
$ sudo systemctl start docker
启动后可以通过docker -v命令进行查看是否启动成功;
通过$ sudo docker images 命令查看docker中的镜像列表;
当前的状态下每次启动linux虚拟机时docker不会自动启动,都需要命令进行启动,很麻烦,所以设置docker开机自启:
$ sudo systemctl enable docker
⑤ 配置docker镜像加速
推荐阿里。产品与服务>> 容器镜像服务>>镜像加速器>>CentOS>>依次执行4条命令
3.docker安装mysql
1.下载镜像文件
在https://hub.docker.com/上查看mysql的各个版本,如果直接执行$sudo docker pull mysql,将会下载最新版mysql,这里我将下载5.7版本:
执行命令:$ sudo docker pull mysql:5.7
下载好后可以使用$ sudo docker images命令查看下载好的mysql镜像
2.创建实例并运行
docker run -p 3306:3306 --name mysql\
-v /mydata/mysql/log:/var/log/mysql\
-v /mydata/mysql/data:/var/lib/mysql\
-v /mydata/mysql/conf:/etc/mysql\
-e MYSQL_ROOT_PASSWORD=root\
-d mysql:5.7
然后可以通过docker ps查看docker中正在运行的程序
由于刚才已经将mysql的配置文件挂在到了mydata/mysql/conf主机路径下,所以在这个路径下进行配置myslq即可
[root@MyLinux ~]# docker exec -it 0eba91b55307 /bin/bash 进入容器内部
root@0eba91b55307:/# ls
bin dev entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint-initdb.d etc lib media opt root sbin sys usr
root@0eba91b55307:/# whereis mysql 查看容器安装目录
mysql: /usr/bin/mysql /usr/lib/mysql /etc/mysql /usr/share/mysql
运行 :cd mydata/mysql/conf 进入conf目录下,改路经下目前没有任何文件,所以运行 vi my.cnf写入相关配置:
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection=utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
退出编辑后重启mysql: docker restart mysql;
至此配置完成,可以通过交互模式查看mysql的配置信息,运行
# docker exec -it mysql /bin/bash
# cd /etc/mysql
# cat my.cnf
4.docker安装redis
1.下载redis镜像
运行:# docker pull redis ,此处没有写版本后缀,表示下载最新官方镜像
2.创建实例并启动
mkdir -p /mydata/redis/conf
touch/mydata/redis/conf/redis.conf
docker run -p 6379:6379 --name redis -v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
避免入坑,先创建目录:mkdir -p /mydata/redis/conf,cd mydata/redis/conf,
再创建文件touch redis.conf,
再执行
docker run -p 6379:6379 --name redis -v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
安装好的redis默认是不支持持久化的,所以在reids.conf文件中添加配置,执行vi redis.conf命令进入文件后,插入appendonly yes (让redis启用持久化);
5.统一开发环境
1.Maven
2.idea&VsCode
3.安装配置git
①.下载git:https://git-scm.com
②.配置git: 进入git bash
# 配置用户名
git config --global user.name "binhaizhijun" //名字
# 配置邮箱
git config --global user.email "binhaizhijun@163.com" //注册账号时用的邮箱
③.配置ssh免密登录
进入git bash,使用: ssh-keygen -t rsa -C “binhaizhijun@163.com”命令。连续回车3次生成秘钥。
执行cat ~/.ssh/id_rsa.pub查看秘钥。
登录码云>>设置>>ssh公钥>>输入标题和秘钥>>保存。
执行ssh -T git@gitee.com命令查看是否设置成功.
6.创建项目微服务
1).从gitee初始化一个项目
在gitee中新建一个仓库,填写好信息后
2).创建各个微服务项目
①.创建各个微服务服务
用spring向导创建商品服务,选择web和OpenFegin组件
②.将各个微服务工程聚合到gulimall工程上
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>gulimall</name>
<description>聚合服务</description>
<packaging>pom</packaging>
<modules>
<module>gulimall-product</module>
<module>gulimall-order</module>
<module>gulimall-member</module>
<module>gulimall-ware</module>
<module>gulimall-coupon</module>
<module>renren-fast</module>
</modules>
</project>
③.提交代码到Gitee上
需要在idea中安装Gitee插件,
过滤掉idea中的垃圾文件:
④.为各个微服务创建数据库
在windows 下的cmd窗口中,运行vagrant ssh 连接虚拟机, 执行$ sudo docker ps -a 查看容器中的所有镜像,
执行$ sudo docker update mysql —restart=always将mysql设定为自启动,以后启动虚拟机mysql就会启动了。
接下来执行sql步骤略过…
7.安装node.js
前端开发少不了node.js,node.js是基于Chrome V8 引擎的javaScript运行环境.
我们关注node.js的npm功能就行.
NPM是随同node.js一起安装的包管理工具,JavaScript-NPM, Java-Maven;
官网下载安装node.js,并使用node -v 命令检查版本
配置npm使用淘宝镜像
npm config set registry http://registry.npm.taobao.org/
npm config set registry https://registry.npm.taobao.org/
8.前端VsCode的使用
npm install
npm run dev
9.使用renren-generator快速生成增删改查
使用renren-generator为各个微服务快速构建增删改查。将下载好的项目导入到工程中后,修改generator工程的数据库配置以及在generator.properties的配置(更改包结构)
10.子模块的微服务整合mybatis-plus
1、导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.4.0</version>
</dependency>
2、配置
1)、配置数据源
①.导入数据库驱动
由于工程中各个微服务都会操作数据库,所以将驱动直接导入common工程中,导入的驱动版本一定要和数据库保持一致
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.21</version>
</dependency>
②.配置数据源: 推荐使用application.yml格式
# 数据源
spring:
datasource:
username: root
password: root
url: jdbc:mysql://172.18.43.249:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
2)、配置mybatis-plus:
① 使用@MapperScan注解告诉Mybatis-plus 要扫描的mapper(dao)接口在哪里,例如
②.告诉Mybatis-plus,sql映射文件在哪里; 以及实体类在数据表中主键的生成规则
mybatis-plus:
# mapper-locations: classpath*:/mapper/**/*.xml #多个*表示不但扫描自己mapper还扫描其他路径下的
mapper-locations: classpath:/mapper/**/*.xml # 扫描sql映射文件位置
三、搭建分布式系统的基本环境
上面创建了几个微服务,并且用逆向工程的形式生成了基本的增删改查代码。现在来搭建分布式系统的基本环境。
微服务-注册中心,配置中心,网关
每一个微服务上线后都需要注册到注册中心中,比如若干商品服务注册到注册中心里,订单服务通过注册中心里找到需要调用的商品服务,来进行远程调用.
配置中心:各个微服务的配置众多,
网关:所有前端的请求先通过网关,比如进行鉴权、过滤、路由等,由网关抵达其他服务,来做一些预先的工作
1.技术搭配方案:
SpringCloud Alibaba -Nacos :注册中心(服务发现/注册);
SpringCloud Alibaba -Nacos:配置中心(动态配置管理);
SpringCloud -Ribbon :负载均衡
SpringCloud-Feign :声明式HTTP客户端(调用远程服务);
SpringCloud Alibaba -Sentinel: 服务容错(限流、降级、熔断);
SpringCloud -Gateway :API网关(webflux编程模式);
SpringCloud -Sleuth: 调用链监控
SprngCloud Alibaba -Seata : 原Fescar,即分布式事务解决方案
2.版本选择
3.如何引入SpringCloud Alibaba依赖
如果需要使用已发布的版本,在 dependencyManagement 中添加如下配置。(在父工程上引入一次就够了呦!!!)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.3.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后在 dependencies 中添加自己所需使用的依赖即可使用。
4.使用SpringCloud Alibaba-Nacos作为注册中心
1、下载nacos-server
https://github.com/alibaba/nacos/releases
2、 启动nacos-server
双击bin中的startup.cmd文件即可;访问http://localhost:8848/nacos/
3、 将微服务注册到nacos中
①首先,修改pom文件,引入Nacos Discovery Starter。
由于各个微服务都会注册到Nacos注册中心中(相当于每个微服务工程都会用到Nacos),所有直接将Nacos Discovery Starter依赖引入到父级工程上。并且此处不需要额外再指定版本号了。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
4、在配置文件中配置nacos-server的地址
在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
5、在启动类中添加注解
使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
6、 启动应用,观察nacos服务列表是否已经注册上服务
注意:每一个应用都应该有名字,这样才能注册上去,修改application.properties 中添加基本配置信息
spring.application.name=service-provider
server.port=18082
5.使用Feign声明式远程调用
Feign是一个声明式的HTTP客户端,它的目的就是让远程调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。
Feign整合了Ribbon(负载均衡)和Hystrix(服务熔断),可以让我们不再需要显式的使用这两个组件。
SpringCloudFeign在NetflixFeign的基础上扩展了对SpringMVC注解的支持,在其实先下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了SpringCloudRibbon自行封装服务调用客户端的开发量。
1、引入OpenFeign
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、编写一个接口,告诉SpringCloud这个接口需要调用远程服务
①声明接口的每一个方法都是要调用哪个远程服务的那个请求
②在接口上添加@FeignClient注解,值为要调用的服务名称
3、开启远程调用功能
在启动类上添加@EnableFeignClients注解,值为feign接口的全路径名,表示服务启动后,会扫描该路径下标有@FeignClient注解的接口
@MapperScan("com.atguigu.gulimall.member.dao")
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients(basePackages = "com.atguigu.gulimall.member.feign")
public class GulimallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallMemberApplication.class, args);
}
}
6.使用SpringCloud Alibaba-Nacos作为配置中心
实际的分布式微服务工程中,每个微服务都需要一些配置信息,项目发布后如果需要更改配置信息,需要停止响应的微服务(同一个微服务运行在多台服务器上都要一一停止),更改配置信息后在一一启动,很麻烦,也不允许。nacos作为配置中心可以解决这个问题
1、修改 pom.xml 文件,引入 Nacos Config Starter
由于每个微服务都会用到配置中心,所以直接将该依赖引入到父工程pom中。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2、在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 元数据
创建bootstrap.properties文件,该文件会优先于application.properties加载。
spring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
3、 需要给配置中心默认添加一个叫数据集(Data Id)。
默认规则为:应用名.properties;
4、在数据集中添写任何配置信息
5、 动态获取配置
@RefreshScope : 动态获取并刷新配置
@Value(“${配置项的名}”) :获得到的配置
注:如果配置中心和当前应用的配置文件中都配置了相同的项,优先使用配置中心的配置.
6、Nacos的更多详细配置
① 命名空间 : 配置隔离
默认是public(保留空间):默认的新增配置都在public空间下。
1、开发,测试,生产:利用命名空间来做环境隔离。
注意:在bootstrap.properties配置上需要使用哪个命名空间下的配置。例如:spring.cloud.nacos.config.namespace=59cb3393-30ee-4e15-b4a5-12d7266a3bd7
2、基于微服务之间互相隔离配置,每个微服务都创建自己的命名空间,只加载自己命名空间下的所有配置
② 配置集: 所有的配置的集合
③ 配置集id:类似文件名
Data Id:类似文件名
④ 配置分组
默认所有配置集都属于DEFAULT_GROUP, 使用哪个分组需要在bootstrap.properties文件中添加如下配置:spring.cloud.nacos.config.group=组名
同时加载多个配置集,如下:
7、 nacos配置中心总结
微服务任何配置信息,任何配置文件都可以放在配置中心中
只需在bootstrap.properties中说明加载配置中心里的那些配置文件即可
@Value,@ConfigurationProperties…以前SpringBoot任何方法从配置文件中获取值,都能使用。
配置中心有的配置优先使用配置中心中的配置
7.使用SpringCloud Gateway 作为服务网关
Gateway简介:网关作为流量的入口,常用功能包括路由转发、鉴权校验、限流控制等。而SpringCloud Gateway作为SpringCloud官方退出的第二代网关框架,取代了Zuul网关。
1、 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2、开启服务注册发现
将gateway服务注册到nacos-server注册中心,这样网关想将请求路由到其他服务上,就知道其他服务在哪里了
1、在启动类上添加@EnableDiscoveryClient;
注:需保证网关服务引入了nacos-discovery的相关依赖
2、配置nacos注册中心的地址
在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gulimall-gateway
3、 设置配置中心地址
为了方便网关的相关配置,可以将网关的配置信息添加在配置中心中
在bootstrap.properties文件中填写配置中心地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=98145fd4-0d81-45fb-bf33-57921dc98ad4
4、设置网关
在application.yml中设置,例如: