最近在我的秒杀深度优化课程中讲到分布式扩展的多种方法,其中有目前最火的微服务扩展及对应的落地技术,特地希望可以通过一篇文章讲清楚内容,带大家入门。
微服务的概念
首先我们尝试用一段话解释一下微服务的概念,微服务区别于讲所有的服务,数据库访问等业务及中间层代码打在一个jar或者war包内的all in one的体系结构,以业务服务及领域模型的组合为单元拆分出可独立部署,独立运行,独立风险控制的系统组件应用的结合体。微服务拥有业务服务(可以理解为spring mvc中的service)及领域模型(可以理解为spring mvc中的model)为闭环,其本身的微服务系统所提供的服务业务边界清晰,生命周期独立且可自运行,可隔离,可追踪。
举个实际一点的例子,在没有采用微服务结构前,我们的电商java代码结构类似如下
所有的服务融合在一个业务程序内,采用all in one的打包方式组成一个jar或者一个war包,并且访问同一个mysql数据库,简单粗糙,服务之间调用关系由于是在一个代码包内,可以随意互相应用,业务关系不清晰,而且部署在一起,一旦一个服务或者对应的数据库产生问题,则全盘故障。于是我们把系统做了微服务化的拆分,以服务为单位将其变成一个分布式的系统
网关接入系统负责接收对应的web请求,转发给对应后面的业务服务系统处理对应的业务并接收返回转发给前端。后面的业务服务系统各司其职,每个系统只负责自己业务范围内的职责,比如商品系统仅服务商品相关的服务,创建,更新,查询,上下架等整个的生命周期并被购物车系统依赖,服务系统之间的逻辑关系清晰,且不同系统间只能通过对方提供的接口做访问,管理方便,每个系统拥有自己独立部署服务器,拥有自己的存储数据库,故障可隔离,配合日志,消息,监控,配置中心等分部署微服务下的配合组件做到一个可监控,可隔离,又可通信的服务体系。
微服务的落地技术
微服务的落地技术有很多,但总体来讲还是可以用几个简单的点去做分类,微服务的框架目前开源的用的最多的是spring cloud,另外有人肯定会说为什么不是dubbo,那其实dubbo仅仅是解决了微服务技术中的一部分问题,例如服务通信,负载均衡,服务注册发现等,但是他没有解决降级限流,熔断控制,服务路由等问题,还需要自己实现或者结合一些第三方组件,因此spring cloud是真正意义上闭环完整的实现了所有微服务的落地功能技术。但是在这里我还是强烈推荐大家学习一下dubbo技术,毕竟在国内阿里体系公司技术流派的氛围下,阿里的开源组件是有很多爱好者和公司使用的,而且dubbo的面向服务插件的编程方式可以很容易的融合第三方库弥补其微服务的不完善性,最终做到一个闭环的服务生态,那我们一起来看一下使用dubbo做微服务技术的具体落地,微服务需要解决以下几个问题
服务通信
隔离开系统之后,本来进程内的调用就要改成进程之间的调用了,进程之间的调用最常用的方式就是网络通信,而远程的网络通信调用函数的方式就是RPC(Remote Process Call)远程过程调用,其并非是一个简单的网络通信过程,在java中依靠接口代理的通信机制使用服务消费方在进程内可以像调用本地函数一样去调用服务提供方的代码,其中间层由dubbo的服务代理机制负责搞定。
服务提供方代码:
##定义接口
package org.apache.dubbo.demo;
public interface DemoService {
String sayHello(String name);
}
##实现接口
package org.apache.dubbo.demo.provider;
import org.apache.dubbo.demo.DemoService;
@Service
public class DemoServiceImpl implements DemoService {
public String sayHello(String name) {
return "Hello " + name;
}
}
服务消费方引用服务
@Component("consumerAction")
public class ConsumerAction {
@Reference
private DemoService demoService;
public String doSayHello(String name) {
return demoService.sayHello(name);
}
}
对,RPC通信框架使得服务调用就这么简单
服务注册及发现
服务注册及发现,解决了服务通信的网络问题,大家不要忽略了,我的服务消费方怎么知道提供方的ip地址和端口,然后连接上去做服务通信的,dubbo结合zookeeper的注册和发现的通信能力做到了这一点
- 服务提供方启动后将自己的ip,端口及可以提供的demoService的接口签名注册到zookper的注册中心上
- 服务消费方启动后通过自己的reference服务依赖引用列表从注册中心找到了提供demoService接口签名的接口服务提供方,也就是我们的服务提供方的ip和端口
- 当consumer要调用对应的demoService服务时通过本地存储的提供方ip和端口连接到provider并进行服务调用后获得返回
- 当provider产生问题,例如异常退出后,由于和zookeeper注册中心之间的心跳丢失,注册中心判定provider死亡会主动通知关注demoService的服务消费方consumer,consumer于是就将对应的provider ip和端口及连接提出
- 发送方和接收方定义将服务调用量发送给monitor监控器做服务健康监控
负载均衡
在上图服务注册和发现中其实我们的provider和consumer在分布式环境下是多台的,因此我们的consumer可以通过注册中心拿到一批provider的ip和端口,当发生服务调用时可以在本地存储的provider列表上做负载均衡策略,比如可以轮训或随机的取下一次调用的provider的连接,由于上述第4步的存在,若某台provider故障则consumer会立马通过注册中心感知到并将provider踢出对应的列表,当provider恢复后又会到注册中心注册,consumer又可以得到通过将provider加回。
配置中心
dubbo依赖zookeeper提供注册中心的能力,同样我们可以将分布式环境下统一使用对应zookeeper做配置中心,将一些集群的配置信息存放在zookeeper上然后所有的关注这个配置的系统都可以实时的获得配置信息并在配置信息发生变更的时候获得第一时间的响应
异步化服务通信
我们之前所说的RPC属于同步服务通信,若我们需要使用异步化的服务通信,比如商品被下单后的销量+1操作,则可以借助rocketmq或者kafka之类的消息中间件解决异步化通信的问题
服务限流
一般我们衡量服务承载的能力为TPS(transaction per second)也就是我们每秒可以处理的服务笔数,这个数值我们可以通过压测获得,那接下来我们要做的是在服务入口层面加上一个限流器,如果每秒钟服务的调用量超过对应的笔数则要采取拒绝服务的处理措施保护我们的系统,google的guava rateLimit就可以提供给我们很好的方法
#像这样在服务初始化的时候指定我的服务只能承载一秒钟两笔的调用量
RateLimiter rateLimiter = RateLimiter.create(2);
#像这样获取令牌决定服务时候可以被执行
if(rateLimiter.tryAcquire()){
return "可以执行";
}else{
return "拒绝执行";
}
熔断降级
若你依赖的服务长时间响应失败或者超时错误次数频增,你是否就要考虑估计你的下游服务生病了,或者处理算力不够了,我们就要像参考电路板熔断器一样,我就不去调用你了,这种机制我们把它叫做“熔断”,基于熔断保护下游,给下游一个喘息的机会,一旦熔断之后我们还要间歇性的去观察下游是否恢复了,因为熔断非常态,正常服务才是我们的诉求,我们还需要提供说我间歇性的访问下你,比如每个2秒钟访问你一次,如果连续三次都没有异常,则判断你已经恢复了,我关闭熔断处理策略。在熔断的过程中我们需要定义一种异常,这种异常比如我们可以用一个特殊的错误码,一种特殊的异常,或者就是一个null的返回,我们对应的服务消费要基于这个错误码做到可降级,比如我们的商品销量获取,如果服务不可用我们就可以展示一个默认的销量,或者隐藏掉销量的展示,不要把系统错误抛给前端。hystrix框架提供给我们和好的服务隔离和熔断机制,结合dubbo的插件式编程方式做很好的融合
监控
我们需要一套监控体系配合我们的微服务健康度检查,在出现问题的时候可以快速定位问题,甚至于做到提前发现问题,防患于未然,dubbo自身的monitor并不能提供给我们太好的支持,在这里我建议大家看一下点评开源的cat监控组件,结合dubbo的插件式编程方式,将每一个服务调用以打点的方式打到cat上,并提供给我们一种可视化的监控展现。
总结
微服务本身是一个很好的工具,但是配套的所产生的系统之间的通信问题,服务的稳定性问题等对开发人员都是不小的挑战,我们建议开发人员结合自己的业务实际情况做好自己的微服务技术落地,欢迎大家找我交流微服务技术与业务的结合
热门评论
到位!期待老师的微服务课程!
写的不错,全面到位,学习了
又看到老师发文章啦,把微服务都概括了一遍,超赞!