【微服务】微服务相关知识

1、微服务如何理解?
背景:谈单体应用,迭代慢;功能不能服用;线上排查问题比较困难。
微服务优点:
1)职责清晰,服务足够小和内聚,独立开发独立部署
2)提高水平扩展性更灵活,只需扩展业务的瓶颈即可,资源利用率高
3)提高容错性。一个服务挂了可以集群保证高可用。一个集群出现故障,可以通过熔断避免整个系统瘫痪。
缺点:
服务之间的通信,治理,新技术问题,分布式事务一致性问题随之而现。

2、如何拆分微服务的?
前后端分离,restful通讯风格。根据akf拆分规则来看,微服务拆分维度主要基于:业务,数据,性能拆分。
akf法则提供立方体拆分:
1)x轴:水平扩展机器
2)y轴:按业务功能拆分
3)z轴:按数据数量/地域进一步拆分
我们按照x轴水平扩展机器,一些服务里面只是某一些功能业务并发量大;盲目扩展就浪费机器,就提出y轴进行按业务功能区拆分;当我们数据量大时候,地域拆分。例如长三角地区数据就送到上海,珠三角就送到深圳。

参考:https://blog.csdn.net/u011537073/article/details/120964581

3、分布式事务解决方案?
什么是分布式事务?
分布式系统中,一个大的事务涉及多个服务或数据库的事务;例如,一个下单操作中,涉及到到订单服务和库存服务。

CAP 原则的精髓是要么 AP,要么 CP,不存在 CAP。一致性 和 可用性 不能同时成立,因为分布式环境下肯定会分区部署多个副本节点,这必然会带来一致性问题,即保证多个节点的数据是相同的;而要让多个节点数据相同,就必须花时间来同步数据,这还必须在通信不会出现失败的情况下,那么在同步数据过程中为了保持一致性,就不能对外提供服务,所以这段时间就无法满足可用性的问题。

其核心思想是:既是无法做到强一致性(Strong consistency),但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。

base理论:
Basically Available:基本可用,出现故障,但本还能用,例如可能增加响应延迟。
Soft state:软状态,又称柔性状态,允许多个不同节点的数据副本存在数据延时,但不影响系统的整体可用。
Eventually consistent:最终一致性,软状态必须是有期限的,在期限过后,应当保证所有副本数据一致性,从而达到最终一致性。

分布式解决方案:
1)两阶段提交
有一个事务管理器,负责协调多个数据库的事务;
事务管理器先问各个DB:预提交 ok 吗?
如果每个数据库都回复ok,即预提交成功,开始正式提交事务。

缺点:适合单块应用中,跨多库的分布式事务,而且因其严重依赖DB层面解决事务,所以效率很低,不适合高并发场景。一般公司不用,一个微服务对应一个数据库。

2)tcc
Try 对各个服务的资源做检测,对资源进行提前锁定或者预留
Confirm 在各个服务中执行实际的操作
Cancel 如果任何一个服务的业务方法执行出错,那么这里就需要进行补偿,即执行已操作成功的业务逻辑的回滚操作

例子:
涉及到两个银行的分布式事务,如果用TCC方案来实现,思路是这样的:

Try阶段 先把两个银行账户中的资金给它冻结住,不让操作了
Confirm阶段 执行实际的转账操作,A银行账户的资金扣减,B银行账户的资金增加
Cancel阶段 如果任何一个银行的操作执行失败,那么就需要回滚进行补偿 比如A银行账户如果已经扣减了,但是B银行账户资金增加失败了,那么就得把A银行账户资金给加回去

缺点:
该方案说实话几乎很少使用,但也有使用场景. 因为这个事务的回滚实际上严重依赖于你自己写代码来回滚和补偿了,会造成补偿代码巨大,非常恶心!

优点:
比如说我们,一般来说和钱相关的支付、交易等相关的场景,我们会用TCC,严格严格保证分布式事务要么全部成功,要么全部自动回滚,严格保证资金的正确性!

3)本地消息表
A系统在本地一个事务里操作的同时,插入一条数据到消息表
接着A系统将这个消息发送到MQ
B系统接收到消息后,在一个事务里,往自己本地消息表里插入一条数据,同时执行其他的业务操作,如果这个消息已经被处理过了,那么此时这个事务会回滚,这样保证不会重复处理消息
B系统执行成功后,就会更新自己本地消息表的状态以及A系统消息表的状态
如果B系统处理失败,那么就不会更新消息表状态,那么此时A系统会定时扫描自己的消息表,如果有未处理的消息,会再次发送到MQ中去,让B再处理

4)可靠性消息最终一致性
不用本地消息表,直接基于MQ实现事务。比如RocketMQ就支持事务消息。
执行流程:
(1)A系统先发一个prepared消息到MQ,若该prepared消息发送失败,则直接取消操作,不再执行
(2)若预提交成功了,那么接着执行本地事务
如果成功就告诉MQ发送确认消息
如果失败就告诉MQ回滚消息

如果发送了确认消息,那么此时B系统会接收到确认消息,然后执行本地的事务
MQ会自动定时轮询所有prepared消息回调你的接口,问你这个消息是不是本地事务处理失败了,所有没发送确认的消息,是继续重试还是回滚? 这里你就可以查下数据库看之前本地事务是否执行,如果回滚了,那么这里也回滚吧。这个就是避免可能本地事务执行成功了,别确认消息发送失败了。
如果系统B的事务失败了咋办? 自动不断重试直到成功,若实在不行,要么针对重要业务进行回滚,比如B系统本地回滚后,想办法通知系统A也回滚;要么发送报警由人工来手工回滚和补偿

总结,用分布式事务有性能成本,代码也很复杂,开发很长时间,性能和吞吐量下跌,系统更加复杂更加脆弱反而更加容易出bug;好处,如果做好了,TCC、可靠消息最终一致性方案,一定可以100%保证你那快数据不会出错。

像资金、交易、订单这些业务,我们才可用会使用分布式事务方案来保证,会员积分、优惠券、商品信息,其实就不要这么搞了,严重影响性能!【使用打印日志,告警策略】
参考:https://zhuanlan.zhihu.com/p/73278352

5、微服务的相关组件
参考链接:https://www.cnblogs.com/findbetterme/p/11195011.html

6、项目中的微服务
服务入口:
网关层,流量控制,鉴权,路径转发;

服务发现:
思考:K8s是如何实现服务的注册与发现,然后如何做到服务的转发、实现负载均衡的?

我们使用Service 用于集群内 Pod 的访问,相当于一个虚拟vip。主要两个能力,做负载和服务发现。

1)服务发现:其实 K8s 并没有引入任何的注册中心,使用的就是 K8s 的 kube-dns 组件。然后 K8s 将 Service 的名称当做域名注册到 kube-dns 中,每一个Service在kube-dns中都有一条DNS记录,同时,如果有服务的ip更换,kube-dns自动会同步,对服务来说是不需要改动的。通过 Service 的名称就可以访问其提供的服务。

2)最终通过 kube-proxy,实现负载均衡。也就是说kube-dns通过 servicename 找到指定 clusterIP,kube-proxy完成通过 clusterIP 到 PodIP 的过程。

RoundRobin:轮询模式,即轮询将请求转发到后端的各个 pod 上,其为默认模式。
SessionAffinity:基于客户端 IP 地址进行会话保持的模式,类似 IP Hash 的方式,来实现服务的负载均衡。

如何设计一个服务注册发现中心?
前提:保证ap
服务注册:存储服务提供方节点上报的自身路由信息,并以集群形式组织数据
服务发现:服务消费方拉取服务提供方节点【可能存在延迟】
节点保活:注册中心通过与已注册节点通讯,判断节点是否健康,并将不健康节点剔除;
服务列表维护:服务消费方订阅服务提供方节点变更事件,发生变更时(发布新版本、扩缩容、服务器宕机)注册中心及时通知服务消费方

参考:https://www.likecs.com/show-204007036.html

服务调用:
工作原理:
1)通过feign 去掉用
通过 @EnableFeignCleints 触发 Spring 应用程序对 classpath 中 @FeignClient 修饰类的扫描

@FeignClient 接口的类时, 获得的是 FeignClientFacotryBean 产生的一个代理对象 Proxy.
基于 java 原生的动态代理机制, 针对 Proxy 的调用, 都会被统一转发给 Feign 框架所定义的一个 InvocationHandler , 由该 Handler 完成后续的 HTTP 转换, 发送, 接收, 翻译HTTP响应的工作。

熔断和限流

灰度方案

7、云原生理解
这句话其实是定义云原生目的是**让研发更加关注业务如何实现,而不需要业务如何被执行。**如何让业务更加关注业务本身的实现呢?云原生从开发态,和交付态去重新定义整个软件工程过程,从而推动整个软件工程相关所有体系进行升级。

deveops+微服务+容器编排+持续交付

8、springboot如何优雅停机?
优雅停机概念:在收到终止信号后,不再接受、处理新请求,但会在终止进程之前预留一小段缓冲时间,以完成正在处理的请求。

kill -9:强制终止进程,进程会被立刻终止;
kill -2 会先保存相关数据再终止进程。
kill -15:kill指令默认就是-15,只是发送一个 SIGTERM 信号通知进程终止,由进程自行决定怎么做,即进程不一定会终止。

对应用来说:

server:
#启用优雅停机。graceful 优雅、优美。默认为 immediate 立刻终止
shutdown: graceful

spring:
lifecycle:
##设置优雅停机的缓冲时间
timeout-per-shutdown-phase: 30s

使用kill -2 来关闭容器。这样才会触发java内部ShutdownHook操作,kill -9不会触发ShutdownHook。

可以使用端点监控 POST 请求 /actuator/shutdown 来执行优雅关机。

对K8s的优雅停机

1)先通知负载均衡器将该实例从后端列表中移除:Kubernetes 的 Endpoint 控制器会开始将 Pod 的 IP 从 Sevice 后端移除

2)结束当前实例上连接:kubelet 的默认停止容器使用的 SIGTERM 信号,tidb-server 在此信号下会进行优雅退出,但超时时间只有 15 秒,若线上有比较耗时较长的请求,是不够当前连接正常退出的。

3)待当前实例上连接结束或超过限定时间后,停止服务

Kubernetes 的 Endpoint 控制器会开始将 Pod 的 IP 从 Sevice 后端移除

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值