[toc]

SpringCloud入门

1. 微服务简介

1.1 微服务的由来

​ 微服务最早由Martin Fowler与James Lewis于2014年共同提出,微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API,这些服务基于业务能力构建,并能够通过自动化部署机制来独立部署,这些服务使用不同的编程语言实现,以及不同数据存储技术,并保持最低限度的集中式管理。

1.2 为什么需要微服务

​ 在传统的IT行业软件大多都是各种独立系统的堆砌,这些系统的问题总结来说就是扩展性差,可靠性不高,维护成本高。到后面引入了SOA服务化,但是,由于 SOA 早期均使用了总线模式,这种总线模式是与某种技术栈强绑定的,比如:J2EE。这导致很多企业的遗留系统很难对接,切换时间太长,成本太高,新系统稳定性的收敛也需要一些时间。

1.3 微服务与单体架构区别

  1. 单体架构所有的模块全都耦合在一块,代码量大,维护困难。
    • 微服务每个模块就相当于一个单独的项目,代码量明显减少,遇到问题也相对来说比较好解决。
  2. 单体架构所有的模块都共用一个数据库,存储方式比较单一。
    • 微服务每个模块都可以使用不同的存储方式(比如有的用redis,有的用mysql等),数据库也是单个模块对应自己的数据库。
  3. 单体架构所有的模块开发所使用的技术一样。
    • 微服务每个模块都可以使用不同的开发技术,开发模式更灵活。

1.4 微服务本质

  1. 微服务,关键其实不仅仅是微服务本身,而是系统要提供一套基础的架构,这种架构使得微服务可以独立的部署、运行、升级,不仅如此,这个系统架构还让微服务与微服务之间在结构上“松耦合”,而在功能上则表现为一个统一的整体。这种所谓的“统一的整体”表现出来的是统一风格的界面,统一的权限管理,统一的安全策略,统一的上线过程,统一的日志和审计方法,统一的调度方式,统一的访问入口等等。
  2. 微服务的目的是有效的拆分应用,实现敏捷开发和部署 。
  3. 微服务提倡的理念团队间应该是 inter-operate, not integrate 。inter-operate是定义好系统的边界和接口,在一个团队内全栈,让团队自治,原因就是因为如果团队按照这样的方式组建,将沟通的成本维持在系统内部,每个子系统就会更加内聚,彼此的依赖耦合能变弱,跨系统的沟通成本也就能降低。

1.5 什么样的项目适合微服务

​ 微服务可以按照业务功能本身的独立性来划分,如果系统提供的业务是非常底层的,如:操作系统内核、存储系统、网络系统、数据库系统等等,这类系统都偏底层,功能和功能之间有着紧密的配合关系,如果强制拆分为较小的服务单元,会让集成工作量急剧上升,并且这种人为的切割无法带来业务上的真正的隔离,所以无法做到独立部署和运行,也就不适合做成微服务了。

1.6 微服务开发框架

目前微服务的开发框架,最常用的有以下四个:

  1. Spring Cloud:http://projects.spring.io/spring-cloud(现在非常流行的微服务架构)
  2. Dubbo:http://dubbo.io
  3. Dropwizard:http://www.dropwizard.io (关注单个微服务的开发)
  4. Consul、etcd&etc.(微服务的模块)

2. SpringCloud简介

Spring Cloud是一系列框架的集合。

  • 它利用Spring Boot的开发便利性简化了分布式系统基础设施的开发:
    • 如服务发现、服务注册、配置中心、消息总线、负载均衡、 熔断器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
  • Spring并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过SpringBoot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

2.1 架构图

2.2 Spring Cloud和Spring Boot是什么关系

  1. Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务。
  2. Spring Cloud是一个基于Spring Boot实现的开发工具;
  3. Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;
  4. Spring Boot使用了默认大于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置,Spring Cloud很大的一部分是基于Spring Boot来实现,必须基于Spring Boot开发。可以单独使用Spring Boot开发项目,但是Spring Cloud离不开 Spring Boot。

2.3 Spring Cloud相关基础服务组件

**服务发现——Netflix Eureka (Nacos)**:Eureka:服务治理组件,包含服务注册中心,服务注册与发现机制的实现。(服务治理,服务注册/发现)

服务调用——Netflix FeignFeign:服务调用,给予Ribbon和Hystrix的声明式服务调用组件 (声明式服务调用)

熔断器——Netflix HystrixHystrix:容错管理组件,实现断路器模式,帮助服务依赖中出现的延迟和为故障提供强大的容错能力。(熔断、断路器,容错)

服务网关——Spring Cloud GateWay /Zuul:网关组件,提供智能路由,访问过滤功能

分布式配置——Spring Cloud Config (Nacos)

消息总线 —— Spring Cloud Bus (Nacos)

Ribbon:客户端负载均衡的服务调用组件(客户端负载)

2.4 Spring Cloud的版本

Spring Cloud并没有熟悉的数字版本号,而是对应一个开发代号。

因为Spring Cloud不同其他独立项目,它拥有很多子项目的大项目。所以它的版本是版本名+版本号 (如Angel.SR6)。

  • 版本名:是伦敦的地铁名
  • 版本号:SR(Service Releases)是固定的 ,大概意思是稳定版本。后面会有一个递增的数字。

所以 Edgware.SR3就是Edgware的第3个Release版本。

Cloud代号 Boot版本(train) Boot版本(tested) lifecycle
Angle 1.2.x incompatible with 1.3 EOL in July 2017
Brixton 1.3.x 1.4.x 2017-07卒
Camden 1.4.x 1.5.x -
Dalston 1.5.x not expected 2.x -
Edgware 1.5.x not expected 2.x -
Finchley 2.0.x not expected 1.5.x -
Greenwich **2.1.x** `` ``
Hoxton 2.2.x `` ``

开发代号看似没有什么规律,但实际上首字母是有顺序的,比如:Dalston版本,我们可以简称 D 版本,对应的 Edgware 版本我们可以简称 E 版本。

小版本

Spring Cloud 小版本分为:

  1. SNAPSHOT: 快照版本,随时可能修改
  2. M: MileStoneM1表示第1个里程碑版本,一般同时标注PRE,表示预览版版。
  3. SR: Service Release,SR1表示第1个正式版本,一般同时标注GA:(GenerallyAvailable),表示稳定版本。

3. Spring脚手架创建工程

首先,我们需要模拟一个服务调用的场景,搭建两个工程:

  • justweb-service-provider(服务提供方)和justweb-service-consumer(服务调用方)。方便后面学习微服务架构:

  • 服务提供方:使用mybatis操作数据库,实现对数据的增删改查;并对外提供rest接口服务。

  • 服务消费方:使用restTemplate远程调用服务提供方的rest接口服务,获取数据。

3.1 justweb-service-provider(服务提供方)

3.1.1 application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
server:
port: 8081

spring:
datasource:
url: jdbc:mysql://cdb-o6r75r3g.bj.tencentcdb.com:10015/justweb_user
username: root
password: ******
driver-class-name: com.mysql.jdbc.Driver

#mybatis
mybatis:
type-aliases-package: cn.justweb.service.pojo
3.1.2 UserController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
   @RestController
@RequestMapping("user")
public class UserController {

@Autowired
private UserService userService;

@GetMapping("{id}")
public User queryById(@PathVariable("id") Long id) {
return this.userService.queryById(id);
}
}

//复习@PathVariable
@RequestMapping("/mm/dd/{username}/{age}")
public String testPlaceholder(@PathVariable(value = "username") String lastname,@PathVariable Integer age){
System.out.println("占位符的URL");
System.out.println( "lastname = " + lastname );
System.out.println( "age = " + age );
return "success";
}

3.2 justweb-service-consumer(服务调用方)

3.2.1 在引导类中注册RestTemplate
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
public class JustwebServiceConsumerApplication {

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(JustwebServiceConsumerApplication.class, args);
}
}
3.2.2 编写配置(application.yml)
1
2
server:
port: 8080
3.2.3 编写消费者的–UserController

RestTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Controller
@RequestMapping("/consumer/user")
public class UserController {

@Autowired
private RestTemplate restTemplate;

@GetMapping
@ResponseBody
public User queryUserById(@RequestParam("id") Long id){
User user = this.restTemplate.getForObject("http://localhost:8081/user/" + id, User.class);
return user;
}

}

4. 总结一下

4.1 刚才我们写了什么?

  • justweb-service-provider:一个提供根据id查询用户的微服务。
  • justweb-service-consumer:一个服务调用者,通过RestTemplate远程调用justweb-service-provider。

4.2 存在什么问题☆?

  • 在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
  • consumer需要记忆provider的地址,如果出现变更,可能得不到通知,地址将失效
  • consumer不清楚provider的状态,服务宕机也不知道
  • provider只有1台服务,不具备高可用性
  • 即便provider形成集群,consumer还需自己实现负载均衡

其实上面说的问题,概括一下就是分布式服务必然要面临的问题:

  • 服务管理
    • 如何自动注册和发现
    • 如何实现状态监管
    • 如何实现动态路由
  • 服务如何实现负载均衡
  • 服务如何解决容灾问题
  • 服务如何实现统一配置

以上的问题,我们都将在Spring Cloud中得到答案...