目录
前言
一、系统架构的演变
集中式架构
垂直拆分
分布式服务
流动计算架构(SOA)
微服务
二、服务调用方式
RPC与HTTP
Http客户端工具
Spring的RestTemplate
三、初识SpringCloud
四、微服务场景模拟
服务提供者
创建工程
编写代码
配置
实体类
UserMapper
UserService
UserController
同理创建服务调用者
存在的问题
面临的问题
五、Eureka注册中心
认识Eureka
原理图
入门案例
注册到Eureka
获取服务
Eureka详解
六、负载均衡Ribbon
负载均衡策略
学习目标
- 了解系统架构的演变
- 了解RPC与HTTP的区别
- 知道什么是SpringCloud
- 独立搭建Eureka注册中心
- 独立配置Robbin负载均衡
存在的问题:
优点:
缺点:
优点:
缺点:
特点:
RPC:Remote Produce Call远程过程调用,类似的还有RMI。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表
Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。
基于Http的客户端进行了封装,并且实现了对象与json的序列化和反序列化。
RestTemplate并没有限定Http的客户端类型,而是进行了抽象,目前常用的3种都有支持:
1、在启动类注册一个RestTemplate对象
@SpringBootApplication
public class HttpDemoApplication {
public static void main(String[] args) {
SpringApplication.run(HttpDemoApplication.class, args);
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
2、在测试类@Autowired注入
@RunWith(SpringRunner.class)
@SpringBootTest(classes = HttpDemoApplication.class)
public class HttpDemoApplicationTests {
@Autowired
private RestTemplate restTemplate;
@Test
public void httpGet() {
// 调用springboot案例中的rest接口
User user = this.restTemplate.getForObject("http://localhost/user/1", User.class);
System.out.println(user);
}
}
它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括:
架构图:
新建一个项目:itcast-service-provider,对外提供根据id查询用户的服务。
Spring Initializr-->填写项目信息-->添加web依赖-->添加mybatis依赖-->填写项目位置
依赖已自动注入
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.4
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-dependencies
${spring-boot.version}
pom
import
手动添加mapper依赖
tk.mybatis
mapper-spring-boot-starter
2.1.4
# 应用名称
spring:
application:
name: itcast-service-provider
datasource:
# 数据库驱动:
driver-class-name: com.mysql.cj.jdbc.Driver
# 数据库连接地址
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC
username: root
password: root
# 应用服务 WEB 访问端口
server:
port: 8890
#下面这些内容是为了让MyBatis映射
mybatis:
#指定Mybatis的Mapper文件
mapper-locations: classpath:mappers/*xml
#指定Mybatis的实体目录
type-aliases-package: cn.itcast.service.mybatis.pojo
@Table(name = "tb_user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String name;
private Integer age;
private Integer sex;
private Date birthday;
private Date created;
private Date updated;
//省略get、set方法
import tk.mybatis.mapper.common.Mapper;
public interface UserMapper extends Mapper {
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User queryUserById(Long id){
return this.userMapper.selectByPrimaryKey(id);
}
}
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("{id}")
public User queryUserById(@PathVariable("id") Long id){
return this.userService.queryUserById(id);
}
}
在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
consumer需要记忆provider的地址,如果出现变更,可能得不到通知,地址将失效
consumer不清楚provider的状态,服务宕机也不知道
provider只有1台服务,不具备高可用性
即便provider形成集群,consumer还需自己实现负载均衡
服务管理
如何自动注册和发现
如何实现状态监管
如何实现动态路由
服务如何实现负载均衡
服务如何解决容灾问题
服务如何实现统一配置
Eureka就好比是滴滴,负责管理、记录服务提供者的信息。服务调用者无需自己寻找服务,而是把自己的需求告诉Eureka,然后Eureka会把符合你需求的服务告诉你。
同时,服务提供方与Eureka之间通过“心跳”
机制进行监控,当某个服务提供方出现问题,Eureka自然会把它从服务列表中剔除。
实现了服务的自动注册、发现、状态监控。
Eureka:就是服务注册中心(可以是一个集群),对外暴露自己的地址
提供者:启动后向Eureka注册自己信息(地址,提供什么服务)
消费者:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新
心跳(续约):提供者定期通过http方式向Eureka刷新自己的状态
spring快速搭建-->选择Cloud Discovery-->选择依赖Eureka Service
# 应用名称
spring:
application:
name: itcast-eureka #将来作为微服务名称注入到eureka容器
server:
port: 10086
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
@SpringBootApplication
@EnableEurekaServer//启用euerka服务端
public class ItcastEurekaApplication {
public static void main(String[] args) {
SpringApplication.run(ItcastEurekaApplication.class, args);
}
}
启动访问http://localhost:10086
修改itcast-service-provider工程
在pom.xml中,添加springcloud的相关依赖。
在application.yml中,添加springcloud的相关依赖。
在引导类上添加注解,把服务注入到eureka注册中心。
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
#.yml
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
//引导类
@SpringBootApplication
@EnableDiscoveryClient//启用eureka客户端
public class ItcastServiceProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ItcastServiceProviderApplication.class, args);
}
}
启动重新访问 http://localhost:10086
客户端消费者注册同理,获取服务修改controller
@Controller
@RequestMapping("consumer/user")
public class UserController {
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient; // eureka客户端,可以获取到eureka中服务的信息
@GetMapping
@ResponseBody
public User queryUserById(@RequestParam("id") Long id){
// 根据服务名称,获取服务实例。有可能是集群,所以是service实例集合
List instances = discoveryClient.getInstances("service-provider");
// 因为只有一个Service-provider。所以获取第一个实例
ServiceInstance instance = instances.get(0);
// 获取ip和端口信息,拼接成服务地址
String baseUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/" + id;
User user = this.restTemplate.getForObject(baseUrl, User.class);
return user;
}
}
基础架构
服务注册中心
Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的itcast-eureka。
服务提供者
提供服务的应用,可以是SpringBoot应用,也可以是其它任意技术实现,只要对外提供的是Rest风格服务即可。本例中就是我们实现的itcast-service-provider。
服务消费者
消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。本例中就是我们实现的itcast-service-consumer。
高可用
Eureka Server即服务的注册中心,在刚才的案例中,我们只有一个EurekaServer,事实上EurekaServer也可以是一个集群,形成高可用的Eureka中心。
多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。
在案例中,启动了一个itcast-service-provider,然后通过DiscoveryClient来获取服务实例信息,然后获取ip和端口来访问。
但是实际环境中,往往会开启很多个itcast-service-provider的集群。此时获取的服务列表中就会有多个,到底该访问哪一个呢?
一般这种情况下我们就需要编写负载均衡算法,在多个实例列表中进行选择。
什么是ribbon
SpringBoot也提供了修改负载均衡规则的配置入口,在itcast-service-consumer的application.yml中添加如下配置:
service-provider:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName
,值就是IRule的实现类。