目前大部分的系统架构都是微服务架构,就算没有注册中心、服务管理,也确定是多个服务,单体服务比较少了。
你们平时须要在应用内调用rpc接口也比较多,那么有没有思考过微服务之间的调用和应用内直接调用有什么区别呢?面试时是否是常常被被问到微服务呢,本篇文章针对微服务间的方法调用和应用内方法调用的有啥区别
这个很小的点,谈谈个人经验前端
先从单体应用提及
单体应用
单体引用经过一个服务节点直接组装好数据,返回给调用者。全部的方法调用都发生在应用内部。面试
微服务应用docker
商品详情服务须要调用商品,营销等多个服务组装好商品详情页的数据数据库
微服务调用和应用内调用不一样点在于它是跨进程的,甚至是跨节点的,这意味着什么呢api
使用k8s编排微服务时,咱们可让不一样的服务放在同一个节点的不一样docker container上,可是考虑到网络不可靠,和容灾,
服务之间不可避免会放到不一样的节点/机架上,因此下文都以跨节点来讨论安全
意味着两点网络
关于网络有几个著名的错误推论架构
The network is reliable(网络是可靠的)
Latency is zero.(延迟能够为0)
Bandwidth is infinite(带宽是无限的)
The network is secure(网络是安全的)
Topology doesn't change(网络拓扑结构不会变)
Transport cost is zero(网络传输耗时为0)
The network is homogeneous(网络是同类的)tcp
存在上述两个问题后,那么咱们须要在写微服务间方法调用时注意什么的微服务
对外部有了依赖
微服务架构设计中有一条重要的原则叫严出宽进
,严出意思就是说你提供给其余服务的东西要尽量的进行严格的校验。宽进就是你调用别人的接口要宽容,兼容各类状况。好比说你须要考虑别人的节点down了/api超时/api不可用等等因素。
为了解决这个问题,咱们必需要针对具体业务,分析依赖类型,是强依赖仍是弱依赖,强依赖包装成本身的服务异常返回码/或者直接告诉前端调用不可用。弱依赖,catch全部异常,不管依赖方发生什么,不能影响个人接口返回。
此外,我依赖的服务某段时间内接口错误率很高,调用方还在不停的发送请求,那么就会一直获得错误的结果,这时候这些请求实际上是无效的,因此这时候须要客户端熔断,再也不去调用服务方,给服务方恢复的时间,等过段时间再去重试,发现服务方可用时,再去调用。
网络调用
网络调用是耗时的,因此咱们须要利用池化技术,复用链接,好比在单体应用中咱们须要与数据库链接,会利用到数据库链接池来提升数据操做效率。那么微服务调用也是这么个道理,咱们与其余服务建议http/tcp链接,也须要创建链接池。另一个服务可能会依赖多个微服务,不能由于和某个服务之间的链接出了问题,影响到与其余服务的链接,因此须要作链接池隔离。
服务间调用有可能失败,因此咱们须要有重试机制,好比由于网络抖动引起的超时问题,咱们能够经过重试提升API的可用性。
可是思考一下坏的状况,某段时间网络或者服务端真的有问题了。客户端超时时间设置的很大的话,客户端等待的时间就会很长,而后再加上重试机制,就会将客户端的链接占满,形成客户端相关API不可用。
分享几个微服务调用的故障案例,帮助你们进行场景化思考
为啥要分享这些案例呢,由于TMD的这些案例都是血的教训,形成线上故障,不是个人错,却要我背锅
案例1:
新上线了一个产品功能,须要推广,放在另一个流量比较大的产品模块中,展现一些咱们产品功能的数据。
出于某种缘由,咱们的服务mock了rpc调用数据,返回null。结果其余服务整个前台页面挂了,挂了,挂了。
典型的强弱依赖问题,调用方没有处理好依赖类型,明明是一个弱依赖没有处理,变成了强依赖,形成功能挂了
案例2:
依赖的某个服务须要根据主键List<id>
来批量查询,依赖服务内部作分库分表拆分,升级了sdk
在提供的sdk client中作分表路由,将批量id拆分红N个rpc调用。这么作的缘由是防止批量查询把数据库链接池打爆。
忽略了网络调用
案例3
别人调咱们的服务的某个接口,这个接口RT(耗时时间)P95 < 30ms。可是客户端调用的超时时间设置成了500ms,在某次不知道是什么缘由的状况下,调用方的链接大量block,形成线程阻塞,相关API不可用。看服务方监控,该接口返回时间正常,服务方没有任何异常。
没有正确的设置超时时间
微服务调用和应用内调用有很大的区别,咱们不能在进行服务间调用时无感知,须要知道它面临的问题
解法能够精炼为4条
这些问题看似都很简单,可是根据个人观察,真的有不少人写了无数的rpc调用,尚未意识到这些问题。
关注【方丈的寺院】,与方丈一块儿开始技术修行之路