Distributed 微服务相关
微服务
微服务是分布式的一个子集,由分布式演变而来。
微服务更注重系统之间的解耦,把原本一个完整的项目拆分成多个互相独立互不影响的小项目通过REST API等其他方式进行数据交互。
相比于分布式服务来说,微服务的粒度更小,服务之间耦合度更低,更加适合敏捷开发。
分布式逐步演变成微服务,这是一种必然的趋势,但微服务也并非没有缺点,设计难度极大(服务拆分力度,服务通信策略等都需要考虑),后期维护较为困难等都是其不可忽视的缺点。
总体来说,分布式更加注重资源共享与用户的访问速度,而微服务在分布式的基础上更加注重系统功能部分的分工与解耦。
架构区别
单体架构
单体架构依然会是小型业务的主流选择方案。
优点:
- 开发简单,集中式管理
- 基本不会重复开发
- 功能都在本地,没有分布式的管理和调用消耗
缺点:
- 效率低:开发都在同一个项目改代码,相互等待,冲突不断
- 维护难:代码功功能耦合在一起,新人不知道何从下手
- 不灵活:构建时间长,任何小修改都要重构整个项目,耗时
- 稳定性差:一个微小的问题,都可能导致整个应用挂掉
- 扩展性不够:无法满足高并发下的业务需求
分布式架构
其实分布式架构拿在这里面不好做对比,它是优化用户体验,防止业务出现故障提升高可用性而产生的。
如图所示,将原本的1个系统横向扩展成3个,提高并发量,优化用户体验:
微服务架构
有了分布的概念,微服务的概念才能产生。
微服务有效的拆分了大的应用,实现敏捷开发和部署,并且对后期扩展及其友好。
同时使用微服务架构时,可以非常方便的用多种语言进行业务实现,如优惠活动的服务采用Java语言编写,支付服务采用Go语言进行编写等:
架构组成
要实际的应用微服务,需要解决以下问题:
- 客户端如何访问这些服务
- 每个服务之间如何通信
- 如此多的服务,如何实现?
- 服务挂了,如何解决?(备份方案,应急处理机制)
如下图:
![image-20210410202829396](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210410202829396.png)
统一访问
如同kubernetes,所有的请求都必须基于API网关进入整个系统中。
同时系统内部各个服务的数据交互也必须通过API网关确认记录后再将其存放至消息中间件中进行通信。
API网关相关功能:
- 提供统一服务入口,让微服务对前台透明
- 聚合后台的服务,节省流量,提升性能
- 提供安全,过滤,流控等API管理功能
![image-20210410231455968](https://images-1302522496.cos.ap-nanjing.myqcloud.com/img/image-20210410231455968.png)
API网关不依赖于任何组件、语言,你可以自由的对其进行定制。
一般来说,API网关的编写需要采用性能较高的语言进行构建,当然,万能的互联网也有一些开源的API网关供大家选择。
此外还有一点注意事项,API网关应当充分的对实现高可用性进行思考,一旦API网关服务出现异常,整个微服务集群将变为闭塞的状态。
内部通信
内部通信经由API网关确认后,可分为两种方案进行通信:
方案1,同步消息调用:
- REST
- RPC
同步信息调用一般来说都是REST风格,比较简单且一致性较强,总体来说方便实用。
而RPC通信则传输协议更高效,安全也更可控,相较于REST基于HTTP协议进行通信,RPC有多种选择方案。
具体来说,还是按照公司实际情况进行选择。
方案2,异步消息调用:
- MQ
- Kafka
异步方案相比于同步方案当然更加的高效,它能使各个服务之间的耦合性更低,又能确保大量消息不会冲垮被调用方。
但是也有一些问题,如怎么保证接口幂等性需要好好进行思索。
在编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同,并非是消息接受者和发送者的数据必须保持一致。
集中管理
在微服务设计中,所有的单一服务都会进行多份拷贝,达到负载均衡、高可用的目的。
但是众多的集群势必导致管理的混乱,如何实时的掌握、监控一个微服务系统中任意一个服务的状态就成了令人头疼的问题。
我们会借用Zookeeper等分布式管理工具来方便整个微服务集群的管控。
在新的服务要加入微服务集群中,必须先经过注册后才能进入,同时由Zookeeper监控整个微服务集群,一旦有某个子服务丢失心跳出现故障都会及时的进行下线和替补。
在集中管理中,日志的记录及权限的分配也都是统一进行调度的,不会因为服务的拆分而拆分。
高可用性
微服务的拆分本身提供了一定的高可用性,任意一个子服务出现问题都不会影响到全局服务(单点的API网关除外)。
但是,微服务架构中所有子服务相互之间又都是链式调用,必须确保任一环节出问题都不至于影响整体链路。
相应的手段有很多:
- 重试机制
- 限流
- 熔断机制
- 负载均衡
- 降级(本地缓存)
名词释义:
1)重试机制:对于突然网络抖动造成的服务异常,加入重试措施重新进行调用,如果一次都重试直接启用新的备胎服务,则代价太大。
2)限流:限制系统能承受的并发量进入,对超出承受能力之外的请求做一些其他处理,如漏桶算法、令牌桶算法等。
3)降级:比方说很多人在买票,还有人在问路,或者在咨询问题的,对于那些问路的或咨询问题的就不处理了,只处理买票
4)熔断:一个接口不能使用的时候,用一个后台程序去监听这个接口,而请求则去访问其他接口,当该接口恢复正常功能时停止监控允许访问
5)负载均衡:对系统本身做横向扩展,将1台机器的并发量分担到3台机器上,举个例子,1个人举100斤的木头举不动时发动影分身之术用3个人来举这根木头
限流算法
漏桶算法(适用于持续的高并发访问):我的服务器只能承受100万/s的并发量,如果你持续的按照100万正负2万的数量/s进行访问,我只按照100万/s进行处理,其他的我所不能承受的请求就漏掉吧。
令牌桶算法(适用于突发性的高并发访问):我的服务器只能承受100万的并发量,12点有个抢购活动预计有1000万用户要来参与,那么我提前放好100万个令牌,在活动开始时发放令牌,先到先得,领到令牌的请求提供服务,无令牌的请求拒绝服务。