1、能说出微服务架构特点。
2、能说出微服务技术栈的构成。
3、理解Spring Cloud Eureka服务治理的流程。
4、理解Spring Cloud Ribbon负载均衡的应用方法。
5、理解Spring Cloud Hystrix 断路保护的应用方法。
6、理解Spring Cloud Zuul 网关的作用及方法。
7、了解Spring Cloud Config、Spring Cloud Bus、Spring Cloud Sleuth等其它子项目的应用场景。
优点:
缺点:
优点:
缺点:
基于SOA的架构思想将重复公用的功能抽取为组件,以服务的方式给各各系统提供服务。
各各项目(系统)与服务之间采用webservice、rpc等方式进行通信。
ESB企业服务总线作为项目与服务之间通信的桥梁。
优点:
缺点:
优点:
缺点:
为适应企业的业务发展,提高软件研发的生产力,降低软件研发的成本,软件架构也作了升级和优化,将一个独立的系统拆分成若干小的服务,每个小服务运行在不同的进程中,服务与服务之间采用http 轻量协议(比如流行的RESTful)传输数据,每个服务所拥有的功能具有独立性强、高内聚的特点,这样的设计就实现了单个服务的高内聚,服务与服务之间的低耦合效果,这一个一个的小服务就是微服务,基于这种方法设计的系统架构即微服务架构。
微服务的兴起出现了很多优秀的公司和技术:
服务治理:Dubbo(阿里巴巴)、Dubbox(当当)、Eureka(Netflix)等 。
配置管理:Disconf(百度)、QConf(360)、Diamood(淘宝)等 。
服务跟踪:Hydra(京东)、Zipkin(Twitter)、Sleuth(Spring Cloud)等 。
Spring Cloud 提供一站式的微服务架构解决方案,如下图:
微服务架构的优点表明它可以提高我们的生产力,但是分布式系统本身的技术成本问题给互联网那些创业型公司不少的挑战,阿里、百度等巨头所提供的微服务技术只是解决其中某个问题,而整合封装这些优秀的技术恐怕是Spring最擅长的领域了,Spring Cloud也正因为此而诞生。
使用Spring Cloud来构建微服务架构可以省去你整合各家技术的成本,Spring Cloud为我们构建微服务架构提供了一站式的解决方案,就好比当初Spring诞生是为解决EJB企业应用开发的众多问题而提供的一站式轻量级企业应用开发解决方案一样,随着使用Spring Cloud公司数量的增加,相信微服务将被Spring Cloud一统江湖。
Spring Cloud的很多技术来源于Netfix(https://netflix.github.io/),摘自百度百科的信息如下:
Spring Cloud是基于Spring Boot构建,本课程使用Spring Boot 1.5.4版本。
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.4.RELEASEversion>
parent>
Spring Cloud为了避免和各子项目的版本名称混淆,它采用伦敦地铁站命名。
当前版本情况如下:
本课程 使用Dalston.SR3版本。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Dalston.SR3version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
MySQL作为数据库的第二把交椅甚至直逼Oralce这个老大,在互联网开发中MySQL的应用是最广泛的。本课程采用MySQL5来构建架构。
IntelliJ IDEA功能的强大及易用性不亚于Eclipse,据统计其使用人数已直逼Eclipse,成为老大指日可待。
本课程 使用IDEA作为开发工具。
微服务架构的缺点中最主要的就是由于微服务数量众多导致维护成本巨大,服务治理为解决此问题而产生的。服务治理的作用是让维护人员从人工维护中解放出来,由服务自维护,微服务作为服务提供方主动向服务治理中心注册,服务的消费方通过服务治理中心查询需要的服务并进行调用。
Spring Cloud Eureka 是对Netflix公司的Eureka的二次封装,它实现了服务治理的功能,Spring Cloud Eureka提供服务端与客户端,服务端即是服务注册中心,客户端完成服务的注册与发现。服务端和客户端均采用Java语言编写(Eureka支持多语言)。
如下图显示了Eureka Server与Eureka Client的关系:
1、创建Spring Boot工程
SpringBoot启动类
package cn.itcast.microservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer //声明这是一个Eureka服务
@SpringBootApplication
public class SpringcloudEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudEurekaApplication.class, args);
}
}
2、在pom.xml中添加依赖(spring boot 、spring cloud、Eureka Server)
<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.0modelVersion>
<groupId>cn.itcastgroupId>
<artifactId>springcloud-eurekaartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>springcloud-eurekaname>
<description>Demo project for Spring Bootdescription>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.4.RELEASEversion>
<relativePath/>
parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Dalston.SR3version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eureka-serverartifactId>
dependency>
dependencies>
<build>
<finalName>${project.artifactId}finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-resources-pluginartifactId>
<configuration>
<encoding>UTF-8encoding>
configuration>
<version>2.6version>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>UTF-8encoding>
configuration>
plugin>
plugins>
build>
project>
3、配置application.yml
server:
port: ${port} #服务端口 通过启动脚本传入参数
spring:
application:
name: itcast-microservice-eureka #指定服务名
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,本身就是所有无需注册
fetchRegistry: true #是否从Eureka中获取注册信息
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: ${eureka.server}
instance:
prefix-ip-address: true #将自己的ip地址注册到Eureka服务中
ip-address: 127.0.0.1
instance-id: ${spring.application.name}:${server.port} #指定实例id
server:
enable-self-preservation: false #禁用自我保护模式
eviction-interval-timer-in-ms: 60000 #清理间隔(单位毫秒 默认是60*1000)
4、部署两台Eureka Server,并且互相注册,实现高可用。
注意:如果没有设置Eureka Server的复制结点eureka默认会找8761端口。
5、配置两个启动脚本
6、启动eureka1和eureka2,并分别访问地址 http://localhost:6868/
用户信息服务实现用户信息查询、用户注册、用户信息修改等功能。
开发用户信息服务采用Spring Boot、SpringMVC、Mybatis架构,数据库采用MySqL5。
SQL语句:
CREATE TABLE user (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(32) NOT NULL COMMENT '密码,加密存储',
`name` varchar(50) DEFAULT NULL COMMENT '名字',
email varchar(30),
`birthday` datetime NOT NULL COMMENT '生日',
sex char(2) not null,
state char(1) not null,
code varchar(10),
PRIMARY KEY (`id`),
UNIQUE KEY `username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8 COMMENT='用户表';
服务注册完成将用户信息服务注册到Eureka Server中,供服务消费方查询。
1、在用户信息服务中配置Eureka服务中心地址及用户信息服务名称。
2、在SpringBoot的启动类中添加注解@EnableDiscoveryClient
3、注意Eureka服务中心地址配置两个,因为有两台Eureka服务中心。
4、用户服务注册中心启动两个服务,为后边测试负载均衡准备。
package com.itheima.microservice.user.controll;
import com.itheima.microservice.user.pojo.User;
import com.itheima.microservice.user.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* Created by Administrator on 2017/12/6.
* 需要热加载的bean需要加上@RefreshScope注解,
* 当配置发生变更的时候可以在不重启应用的前提下完成bean中相关属性的刷新。
*/
@RestController
@RefreshScope
public class UserController {
@Autowired
private UserService userService;
/**
* 对外提供接口服务,根据账号查询用户信息
*
* @param username
* @return
*/
@GetMapping(value = "user/{username}")
public User getUserByUsername(@PathVariable("username") String username) {
return this.userService.getUserByUsername(username);
}
}
UserService.class
package com.itheima.microservice.user.service;
import com.itheima.microservice.user.mapper.UserMapper;
import com.itheima.microservice.user.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Created by Administrator on 2017/12/6.
*/
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
/**
* 根据账号查询用户
*
* @param username
* @return
*/
public User getUserByUsername(String username) {
return userMapper.getUserByUsername(username);
}
}
UserApplication.class 启动类
package com.itheima.microservice.user.mail;
import com.itheima.microservice.user.util.SpringContextUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/**
* Created by Administrator on 2017/12/6.
*/
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan(basePackages={
"com.itheima.microservice"})
@MapperScan("com.itheima.microservice.user.mapper")
public class UserApplication {
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(UserApplication.class, args);
SpringContextUtils.setApplicationContext(applicationContext);
}
}
UserMapper.class
package com.itheima.microservice.user.mapper;
import com.itheima.microservice.user.pojo.User;
/**
* Created by Administrator on 2017/12/8.
*/
public interface UserMapper {
User getUserByUsername(String username);
}
User.class
package com.itheima.microservice.user.pojo;
import java.util.Date;
/**
* Created by Administrator on 2017/12/10.
*/
public class User {
private String id;
private String username;
private String password;
private String name;
private String email;
private Date birthday;
private String sex;
private int state;
private String code;
public String getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public Date getBirthday() {
return birthday;
}
public String getSex() {
return sex;
}
public int getState() {
return state;
}
public String getCode() {
return code;
}
public void setId(String id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setState(int state) {
this.state = state;
}
public void setCode(String code) {
this.code = code;
}
public User(String id, String username, String password, String name, String email, Date birthday, String sex, Integer state, String code) {
this.id = id;
this.username = username;
this.password = password;
this.name = name;
this.email = email;
this.birthday = birthday;
this.sex = sex;
this.state = state;
this.code = code;
}
public User() {
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", email='" + email + '\'' +
", birthday=" + birthday +
", sex='" + sex + '\'' +
", state=" + state +
", code='" + code + '\'' +
'}';
}
}
SpringContextUtils.class
package com.itheima.microservice.user.util;
import org.springframework.context.ApplicationContext;
/**
* Created by Administrator on 2017/12/8.
*/
public class SpringContextUtils {
private static ApplicationContext applicationContext;
public static void setApplicationContext(ApplicationContext context) {
applicationContext = context;
}
public static Object getBean(String beanId) {
return applicationContext.getBean(beanId);
}
}
UserMapper.xml
<mapper namespace="com.itheima.microservice.user.mapper.UserMapper">
<select id="getUserByUsername" resultType="User">
SELECT id,username,password,name,email,birthday,sex,state
FROM user WHERE username = #{username}
select>
mapper>
application.yml
server:
port: ${port} #服务端口
spring:
application:
name: itcast-microservice-user #指定服务名
################################################################
# mysql 属性配置
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://127.0.0.1:3306/store?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: root
password: root
# jpa:
# hibernate:
# #ddl-auto: create #ddl-auto:设为create表示每次都重新建表
# ddl-auto: update #ddl-auto:设为update表示每次都不会重新建表
# show-sql: true
################################################################
################################################################
#spring集成Mybatis环境
#pojo别名扫描包
mybatis:
type-aliases-package: com.itheima.microservice.user.pojo
################################################################
################################################################
eureka:
client:
registerWithEureka: true #是否将自己注册到Eureka服务中,默认为true
fetchRegistry: true #是否从Eureka中获取注册信息,默认为true
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址
defaultZone: http://127.0.0.1:6868/eureka/,http://127.0.0.1:6869/eureka/
eurekaServerConnectTimeoutSeconds: 60
eurekaServerReadTimeoutSeconds: 60
instance:
prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
ip-address: 127.0.0.1
instance-id: ${spring.application.name}:${server.port} #指定实例id
lease-expiration-duration-in-seconds: 30 #续约更新时间间隔(默认30秒)
lease-renewal-interval-in-seconds: 10 # 续约到期时间(默认90秒)
leaseRenewalIntervalInSeconds: 10 #心跳时间
################################################################
################################################################
logging:
level:
root: debug
# org.springframework.web: DEBUG
file: /log/log/my_provide.log
pattern:
console: "%d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n"
file: "%d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n"
################################################################
management:
security:
enabled: false #是否开启actuator安全认证
pom.xml
<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.0modelVersion>
<groupId>cn.itcastgroupId>
<artifactId>userartifactId>
<version>0.0.1-SNAPSHOTversion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>1.5.4.RELEASEversion>
parent>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Dalston.SR3version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eureka-serverartifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformatgroupId>
<artifactId>jackson-dataformat-xmlartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.11version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.0.9version>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-configartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-bus-amqpartifactId>
dependency>
<dependency>
<groupId>org.springframework.retrygroupId>
<artifactId>spring-retryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
dependencies>
<build>
<finalName>${project.artifactId}finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-resources-pluginartifactId>
<configuration>
<encoding>UTF-8encoding>
configuration>
<version>2.6version>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>UTF-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
添加启动配置
访问如下:user服务已经注册到eureka server中
如下图是负载均衡的架构图:
Spring Cloud Ribbon是基于客户端的负载均衡工具,负载均衡分为服务端负载均衡和客户端负载均衡,3.1小节的图形指的是服务端负载均衡,客户端负载均衡与服务端负载均衡的区别在于客户端要维护一份服务列表,Ribbon从Eureka Server获取服务列表,Ribbon根据负载均衡算法直接请求到具体的微服务,中间省去了负载均衡服务。
如下图是Ribbon负载均衡的流程图:
单点登录服务提供用户登录、用户退出等功能。
单点登录服务需要调用用户信息服务查询用户信息。
单点登录服务采用Spring Boot、SpringMVC开发。
单点登录服务需要从EurekaServer查询用户信息服务。
1、配置Eureka Server服务地址。
2、在SpringBoot的启动类中添加注解@EnableDiscoveryClient
1、定义RestTemplate对象
2、配置 @LoadBalanced
3、设置负载均衡算法。
4、使用RestTemplate调用微服务。
Spring Cloud Hystrix 是基于Netflix的开源框架Hystrix的整合,它实现了断路器、线程隔离、信号隔离等容错功能。
下图是Hystrix断路器示意图:
1.要在服务消费方添加hystrix。
2、使用Hystrix实现容错。
3、在Spring boot的启动类上添加@EnableHystrix注解
服务网关是在微服务前边设置一道屏障,请求先到服务网关,网关会对请求进行过虑、校验、路由等处理。有了服务网关可以提高微服务的安全性,校验不通过的请求将被拒绝访问。
前边介绍的Ribbon客户端负载均衡技术可以不用经过网关,因为通常使用Ribbon完成微服务与微服务之间的内部调用,而对那些对外提供服务的微服务,比如:用户登录、提交订单等,则必须经过网关来保证微服务的安全。
Spring Cloud Zuul是整合Netflix公司的Zuul开源项目实现的微服务网关,它实现了请求路由、负载均衡、校验过虑等 功能。
1、部署用户信息服务A、单点登录服务B,每个服务部署至少两台机器。
2、将用户信息服务A、单点登录服务B注册到EurekaServer中。
3、开发并部署zuul。
4、在zuul中配置路由
5、可以定义filter,需要集成zuul提供filter类,进行校验拦截。
6、在spring boot的启动类中配置注解
7、根据上边的路由配置访问微服务。
凡是以/sso/打头的请求,路由到 itcast-microservice-sso微服务。
zuul网关,不仅提供对外服务访问 ,微服务也可以通过zuul请求其它的微服务。