系统结构演变
单一应用->垂直拆分->分布式服务->SOA->微服务架构->Service Mesh
集中式架构
数据访问框架(ORM)
分布式服务
将核心业务抽取出来,作为独立的服务,逐渐形成服务中心
服务治理(面向服务SOA)
增加一个调度中心基于访问压力实时管理集群容量
- 服务注册中心实现服务自动注册和发现,,无需人为记录服务地址
- 服务自动订阅,服务列表自动推送,服务调用透明化,无需关心依赖关系
- 动态监控服务状态监控报告,人为控制服务状态
不符合DevOps思想(软件开发人员(Develop)”和“IT运维技术人员(Operations)”之间沟通合作的文化、运动或惯例)
Docker类似于虚拟机,轻量级、跨平台,可打包成镜像
微服务
对系统进行拆分
传统SOA技术栈一致,全用同一种技术
微服务 | SOA |
---|---|
能拆分就拆分 | 服务能放一起就放一起 |
纵向业务划分 | 水平分多层 |
由单一组织负责 | 按层级划分不同的部门组织负责 |
细粒度 | 粗粒度 |
独立的子公司 | 类似大公司划分出来的业务单元(BU) |
组件小 | 组件复杂 |
业务逻辑存在每个服务中 | 业务逻辑横款多个业务领域 |
使用轻量级通信,如HTTP | 企业服务产总线(ESB)充当服务之间通信角色 |
特点:
- 单一职责
- 拆分粒度小
- 面向服务:每个服务需要对外暴露服务接口API,与平台、语言无关,只提供Rest的接口
- 自治:服务间相互独立
- 团队独立
- 技术独立
- 前后端分离
- 数据库分离
- 部署独立
远程调用方式
- RPC:Remote Procedure Call远程过程调用,自定义数据格式,类似的还有RMI(远程方法调用Remote Method Invocation),现在热门的Dubbo就是RPC的典型。基于原生的TCP通信。
- HTTP:基于TCP通信。缺点是消息封装臃肿,Rest是HTTP协议实现
RPC
允许运行于一台计算机的程序调用另一台计算机的子程序,无需为而外的交互进行编程。调用过程对于用户是透明的。
实现远程调用,想调用本地服务一样调用远程服务。包括Socket通信,动态代理进行隐藏,封装
采用TCP为底层传输协议,定义好请求好请求和响应的个数。数据在网络中需要进行序列化,约定统一的序列化方式。
HTTP
应用层协议
响应
区别
- RPC没有规定数据传输格式,可任意指定。不同的RPC协议可以有不同的格式
- HTTP定义了资源定位的路径,RPC不用
- RPC在调用过程在API层面进行封装(像调用本地服务一样调用远程服务),限制开发的语言环境
- RPC更透明,HTTP更灵活没有规定语言和API,但是数据繁琐
Http客户端工具
- URLConnection:java原生的类实现Http请求
- HttpClient
- OKHttp:比HttpClient更轻量,Android用的多
HttpClient
Http Components下的子组件,支持Https协议,通过Http代理建立透明的连接,自动处理Set-Cookie中的Cookie
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient-cache</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.1</version>
</dependency>
package edu.qut.httpdemo;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.qut.pojo.User;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.junit.Before;
import org.junit.Test;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
/**
* @Author: AmberXu
* @Date: 2018/9/24 21:49
*/
public class HttpTests {
CloseableHttpClient httpClient;
ObjectMapper mapper = new ObjectMapper();
@Before
public void init(){
//创建httpClient的客户端
httpClient = HttpClients.createDefault();
}
@Test
public void testGet()throws IOException{
//发起get请求
HttpGet request = new HttpGet("http://www.baidu.com");
//执行请求
String response = this.httpClient.execute(request,new BasicResponseHandler());
System.out.println(response);
}
@Test
public void testPost()throws IOException{
//可能会被鉴定为爬虫
HttpPost request = new HttpPost("http://www.oschina.net/");
//头信息
request.setHeader("User-Agent","Mozila/5.0(Window NT 10.0; WOW64) AppleWebkit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36");
String response = this.httpClient.execute(request,new BasicResponseHandler());
System.out.println(response);
}
@Test
public void testGetPojo()throws IOException{
//远程调用,只需知道URL,获取到JSON
HttpGet request = new HttpGet("http://localhost/hello");
String response = this.httpClient.execute(request,new BasicResponseHandler());
// 将JSON数据转化为User
User user = mapper.readValue(response, User.class);
// 转换List<User>
// List<User> userList = mapper.readValue(response,mapper.getTypeFactory().constructCollectionType(List.class,User.class));
// List<User> userList = mapper.readValue(response, new TypeReference<List<User>>(){});
System.out.println(user);
}
}
在百度直接输入网址是Get,不能用post
JsonUtils把对象变成Json字符串(序列化),把Json字符串变成对象(反序列化)
Spring的RestTemplate
模板工具类,基于Http客户端的封装
@RunWith(SpringRunnner.class)
@SpringBootTest(classes = HttpDemoApplicationTests.class)
public class HttpDemoApplicationTests {
@Autowired
private RestTemplate restTemplate;
@Test
public void httpGet(){
User user = this.restTemplate.getForObject("http://localhost/hello",User.class);
System.out.println(user);
}
}
Spring Cloud
微服务框架
配置管理、服务发现、智能路由、负载均衡、熔断器、控制总线、集群状态
- Eureka:注册中心
- Zuul:服务网关
- Ribbon:负载均衡
- Feign:服务调用
- Hystix:熔断器
微服务场景模拟
新建一个服务,对外提供查询用户的服务
右键点击new,选择Module->Spring Initializr->next
待完善
Eureka注册中心
定时发送Http请求,维持“心跳(续约renew)”。管理服务,实现服务的自动发现、自动注册、服务的监管
定期拉取服务列表
对于客户端添加@EnableDiscoveryClient
添加@EnableEurekaServer,编写application.yml
eureka:
server:
wait-time-in-ms-when-sync-empty: 0
enable-self-preservation: true # false 关闭自我保护,不管如何都要剔除心跳检测异常的服务
instance:
hostname: eureka1
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {
public static void main(String[] args) {
new SpringApplicationBuilder(EurekaApp.class).web(true).run(args);
}
}
<!-- 注册中心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 服务轨迹跟踪 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<!-- 配置中心服务器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 配置总线依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- 监控埋点 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
一个服务下可以有多个实例
服务提供者:提供服务的应用,并注册到Eureka的注册中心
服务消费者:从注册中心获取服务列表,从而得知每个服务提供者的信息。通过DiscoveryClient对象getInstances(服务名称)获取服务,返回集合List<ServiceInstance>,可能是集群,编写负载均衡算法。ServiceInstance对象通过getHost和getPost获取。