前言
最近看了很久的微服务,想谈谈自己的感受以及一些理解。
说到微服务,就肯定要先说一下架构发展史:单体架构->垂直架构->微服务架构。
单体架构
顾名思义就是一个独立的程序撑起了一整个后端服务,前期可以说是非常靠谱,就像一个家庭主妇,能做所有事情:做饭、洗衣、带孩子。可是,随着孩子长大(业务不断扩展),突然发现自己变得有点力不从心,可能会有点“焦虑”了——这时候单体架构就得退场了。
垂直架构
个人理解就是在单体架构的基础上进行修改,把一整个后端服务分割成很多的模块,每个模块负责一个业务,业务之间基本上独立。同时在设计URL上也做了二级路由,看起来更规范。就像把家庭主妇分配给了多个小家庭,各司其职。听起来很高效,但你会发现这些小家庭之间还是有共享资源的问题,最后又卡住了——数据源共享的痛苦就像是买不起两个卫生间的家庭,越来越难忍受。
说不定现在很多公司宣称“微服务”时,其实还是在做这种“伪微服务”的垂直架构。
微服务
我们先来看看官方定义是怎么描述的:
2014年,Martin Fowler 与 James Lewis 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用HTTP API通信。同时服务会使用最小的规模的集中管理 (例如 Docker) 能力,服务可以用不同的编程语言与数据库等组件实现。
按照我的理解就是,在垂直架构的基础上再解耦合(模块再进行细分),每个模块变成一个独立的且互相没有依赖的的Server,每个server都有自己的数据库。最后将Server进行打包成镜像最后再由一些容器化组件进行统一管理维护。
简单来说,就是让每个模块独立出来,像你把所有家庭成员都安排去各自的地方住,每个人有自己的资源(数据库)和目标。微服务的目标就是解耦合!解耦合到极致,每个服务就像一个孤独的小岛——但这也带来了一个问题:如果你有多个小岛,怎么让它们不迷路?
流水线
前端发起请求后,首先经过一个API网关,比如 Nginx,根据 URL 进行“导航”,把请求分发到不同的服务。接下来,路由函数会接手请求,并进行一些中间件的处理,比如验证 JWT、记录日志等。一切确认无误后,它会通过 gRPC 向负责逻辑处理的服务发起请求。
听起来好像和垂直架构差不多,都是分模块处理嘛。可是,微服务最关键的一个特点就是“解耦合”——每个服务都是独立的个体,就像是不同的超人,每个人都有自己的技能和责任。而且,它们不仅可以使用不同的编程语言,还可以有不同的数据库!你看,服务数量可以从一个变成多个,例如:server_stu_1, server_stu_2, server_stu_3,它们的职责完全一致——就是负责处理学生的请求,只不过有三个“超级英雄”同时在线。
不过这就引出了一个问题:在传统的架构中,只有一个服务会监听路由,这样请求就直接能找到对应的函数。但在微服务世界里,既然有多个服务,我们可不能写死路由函数让它只绑定到一个服务上,那样就像是在给它戴上“单身”的紧箍咒。那问题来了,如何让路由函数聪明地知道应该唤醒哪个服务呢?
服务注册与发现
要想快速找到对应的服务,我就应该有一个表来存放我的服务。etcd就是这样的一个东西,注册服务同时发现服务。在路由函数执行逻辑函数的时候,在etcd里面搜索这个服务是否存在,并且进行调用。而在某一个服务存在多个的情况下etcd还会负载均衡,保证每个服务都雨露均沾不受到孤立。
服务治理
当一个服务收到大量的连接时肯定要做出回应
我们的韭菜正在我们的网店进行限时购物,流量一大,我们也要设定“人流管制”。设置一个限流器,达到阈值后就直接告诉用户“活动火爆,请稍后再试”,别说,你就算是在“宕机”状态,也能给客户一种“是我忙得不可开交”的错觉,呵呵。
这就是限流:限制一部分请求,某一段时间直接收一定数量的连接,超过的直接返回503(也可以自定义返回)
如果实在撑不住了,那就得“关机”了。类似电器的“过载保护”,熔断机制会在服务连续失败时触发,停止一段时间,等自愈恢复后再上线。就像是你发现服务“心态崩了”,给它一点时间去疗伤,别让它继续崩溃。
熔断:服务直接关机,当一个服务在被调用时发生了故障并且超过了一定的阈值,我们肯定要停止调用防止越来越多的报错,那么服务就会进行关闭,熔断器会根据报错率来判断是否关闭服务,同时拥有自愈重启功能
如果用户坚持不懈地访问(就是这么执着),熔断也不够优雅,那就干脆自定义个“假装不崩溃”的降级页面。例如,访问的时候总能看到:“服务器正在进行豪华升级”,结果其实是服务器已经崩溃了,哈哈,但让用户看起来还是“高大上”!
降级:上述两种情况出现了肯定直观的甩出503,用户体验肯定不好,那么我们可以自定义回复内容:访问一些网页的时候经常会看到活动异常火爆,请稍后再试;这是假的,就是访问报错了安慰你的假象罢了。
DevOps
既然服务做起来了,肯定要想到如何去部署了。
CI(持续集成)
我们写完代码先不着急上线,先让它通过一番“严格面试”运行单元测试、集成测试等,验证代码逻辑和系统行为。也就是说检测新的代码块与老代码能否和谐相处。
CD(持续交付/部署)
代码通过CI的面试后,我们就开始将代码部署啦,这里如果CI和CD是分开的话就需要写一个自动化脚本去检测新上线的代码,将代码进行打包封装成镜像,再编写对应脚本去操控k8s拉取镜像并运行。
k8s
k8s是一个管理容器的东西进行编排的,让微服务部署和管理变得像拆乐高一样简单,minikube来保证你在本地也能“模拟”一把,体验一下云端生活。
总结
一套完整流程:
业务代码->gitlab(ci:测试代码)->Jenkins(cd:生产镜像,部署服务)->k8s(运行并维护服务)
一套完整的微服务架构在业务层面上一定是庞大的,否则还不是一个简单的单体架构来得直接。毕竟,微服务就像是开车,你得有一辆性能稳定的车,才敢把一堆零件塞进去。