单体应用向微服务架构演进
在单体应用时代,所有的功能模块耦合在一个应用中,并部署到一个进程中,比如一个电子商城服务就包含订单模块、用户模块、商品模块等等,随着业务增加,单体应用面临的问题越来越多。
1、部分模块出现问题时会影响整个应用。
2、部署成本越来越高,更新部分模块功能时需要部署整个应用,如果发布过程中没有做无损下线会导致部分请求报错。
3、技术栈受限,要求开发人员使用相同的语言开发。
4、整体结构不稳定,拓展性不足,增删改业务风险大。
5、并发能力受到限制,不能根据业务量定向增强某个模块
微服务是一种架构风格。
微服务架构就是将单体应用的不同模块进行拆分,分别部署。这样做的好处是:
1、每个微服务之间独立,一个服务出现问题影响的只是当前服务,不会对整个业务造成影响。
2、每个微服务独立开发、独立运行、独立部署。
3、每个微服务可以用不同的语言开发。
4、不同团队维护不同的微服务,职责单一。
5、可以根据业务量定向扩容或缩容某个微服务。
微服务架构存在的缺点
各个微服务相互独立,每个微服务,由多台机器或者单机器不同的实例组成,各个微服务之间存在错综复杂的相互关联调用,因此微服务的节点信息维护是一个棘手的问题。
为了维护这些关系,我们需要考虑几点
1、要配置方便,便于维护节点信息
2、要可监控,知道每一个微服务的状态
3、要高可用,排除不可用微服务
服务注册与发现模式就是为了解决这些问题产生的,调用过程如下:
服务提供者(Provider)向注册中心注册所提供服务,消费者(Consumer)去注册中心发现服务,并在服务列表中选择一个调用。
Spring Cloud 统一了服务注册与发现模型
其代码定义在spring-cloud-commons-*.jar 中
- org.springframework.cloud.client.discovery.DiscoveryClient
- org.springframework.cloud.client.discovery.ReactiveDiscoveryClient
- org.springframework.cloud.client.discovery.EnableDiscoveryClient
- org.springframework.cloud.client.serviceregistry.ServiceRegistry
- org.springframework.cloud.client.ServiceInstance
DiscoveryClient与ReactiveDiscoveryClient用于从注册中心发现服务,区别是ReactiveDiscoveryClient定义的是基于响应式服务发现接口,具体代码如下
/**
* 表示发现服务(如Netflix Eureka或consul.io)通常可用的读操作。
*/
public interface DiscoveryClient extends Ordered {
int DEFAULT_ORDER = 0;
/**
* 描述
*
*/
String description();
/**
* 根据serviceId获取ServiceInstance列表
*/
List<ServiceInstance> getInstances(String serviceId);
/**
* 获取所有的serviceId
*/
List<String> getServices();
@Override
default int getOrder() {
return DEFAULT_ORDER;
}
}
/**
* 表示发现服务(如Netflix Eureka或consul.io)通常可用的读操作。
*/
public interface ReactiveDiscoveryClient extends Ordered {
int DEFAULT_ORDER = 0;
/**
* 描述
*/
String description();
/**
* 根据serviceId获取ServiceInstance列表
*/
Flux<ServiceInstance> getInstances(String serviceId);
/**
* 获取所有的serviceId
*/
Flux<String> getServices();
@Override
default int getOrder() {
return DEFAULT_ORDER;
}
}
ServiceInstance定义了服务发现接口中返回的抽象实例模型,代码如下:
/**
*表示发现系统中服务的实例
**/
public interface ServiceInstance {
/**
* 获取实例Id
*/
default String getInstanceId() {
return null;
}
/**
* 获取服务Id
*/
String getServiceId();
/**
* 获取地址
*/
String getHost();
/**
* 获取端口
*/
int getPort();
/**
* 是否使用https
*/
boolean isSecure();
/**
* 获取服务调用地址
*/
URI getUri();
/**
* 元数据
*/
Map<String, String> getMetadata();
default String getScheme() {
return null;
}
}
ServiceRegistry定义了provider(提供者)向注册中心注册/注销等行为接口,其中注册抽象实例“Registration” 继承了“ServiceInstance” 后没有添加新内容。
/**
* 约定向Service Registry注册和注销实例
*/
public interface ServiceRegistry<R extends Registration> {
/**
* 注册
*/
void register(R registration);
/**
* 注销
*/
void deregister(R registration);
/**
* 关闭
*/
void close();
/**
* 设置注册状态。
*/
void setStatus(R registration, String status);
/**
* 获取注册状态。
*/
<T> T getStatus(R registration);
}
public interface Registration extends ServiceInstance {
}
以上内容描述了“服务注册(ServiceRegistry)”与“服务发现(DiscoveryClient/ReactiveDiscoveryClient)”的方式以及流程中传输的实例(ServiceInstance/Registration)的定义,接下来我们说一下“注册中心”
常用的注册中心有四种
组件名称 | 所属公司 | 开发语言 | CAP | 简介 |
---|---|---|---|---|
Eureka | Netflix | Java | AP | springcloud最早的注册中心,已停止更新进入维护状态,不推荐使用 |
Zookeeper | Apache | Java | CP | 本质上是一个分布式协调系统,可以实现注册中心功能 |
Consul | Hashicorp | Golang | CP | Consul 简化了分布式环境中的服务的注册和发现流程,通过 HTTP 或者 DNS 接口发现。支持外部 SaaS 提供者等。 |
Nacos | Alibaba | Java | AP | 是注册中心,也是配置中心 |
CAP 是什么
CAP原则又称CAP定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。
- Consistency 一致性:所有数据备份,在同一时刻是否同样的值。
- Availability 可用性:在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。
- Partition Tolerance 分区容错性:当集群节点之间通讯出现故障时,保证各个节点仍然可用。
分布式系统/微服务架构系统中网络故障和节点宕机时有发生,因此“P” 必不可少,根据业务需求,系统需要在可用性(A)和一致性(C)之间二选一。
Nacos的使用
下载并启动Nacos服务
官方文档:什么是 Nacos
下载地址:GitHub - alibaba/nacos at 0.2.1
编译好的项目下载:https://github.com/alibaba/nacos/releases/download/v0.1.0/nacos-server-0.1.0.zip