微服务和服务处理
介绍
随着需求的变化,用户、模块越来越多。
我们从单一服务转变到微服务
对服务、数据的处理,也多出了很多种不同的方式,
最后只为了保障服务的性能和稳定性。
主要简单的介绍一些微服务的常识和我们运用保障服务的哪些方案。
目录
一:微服务与单体
二:网关层
三:分布式锁、事物和多库DB:
四:分布式的一些小应用与技巧:
五:缓存
六:负载
七:限流、服务降级、服务熔断
微服务与单体
微服务
1.松耦合,开发阶段和部署阶段都是独立的,这样一个服务出现问题,不会影响整个应用。
2.容易支持不同的语言进行开同一应用的开发。
3.理论上,每个微服务都很小,这样使代码更容易理解,使开发人员更容易聚焦、专注,只需要关注自己的服务以及工作业务.
4.部署灵活,因为是分布式,所以一个服务不大的情况下,是可以快速启动好的,不会发生单一服务构建时间长的事故。
5.高并发:可以更好的承受并发,因为模块是分散式的。
6.有效的利用资源,一台服务一个机器,很浪费,微服务使用容器化部署,一个服务,一个进程,更好的利用资源。分配机器
单体
1. 开发简单直接,集中式管理, 基本不会重复开发
2.功能都在本地,没有分布式的管理开销和调用开销。
3.重点是比微服务:业务实现上和部署维护上,要简便了很多,不会搞得那么复杂.
网关层
api-gateway
我们处理的简单,目前是直接使用了一套api-gateway来做的转发,前端会走http请求,进入
到api-gateway,从而在转发到我们内部的grpc请求,模版是proto定义的,只要定义了
proto,api-gateway就能自动生成对应的http,提供前端请求不过我们的权限认证,并
没有放在api-gateway里,而是每个服务请求过滤那一层,就会调用grpc进行权限角色
的认证.
权限认证:
每个服务在过滤层,会进行调用grpc来判断是否有权限,之前在做单一服务或者是拆分服务,
做了一些简单的分布式操作,也只是在过滤写好代码,直接查询db在进行
判断看是否有权限,其实这样非常不好,因为权限业务有
稍微的变动,可能就会引发其他服务的变动,而且也没有统一性,有些同学就会觉得那为了统
一,直接写个包,放到gitlab上,在引用到项目不就好了,那肯定是不行的,且不说版本
跟新,按照微服务一个服务一个db的操作(这样使开发人员只需要关注自己的业务,管理属于
自己服务的架构),就已经不太具备了,
当然,这里不是说一定要一对一的关系,只是提倡这样。
分布式锁、事物和多库DB:
分布式锁:
主要是利用redis setnx来实现的,因为是原子性的原因,所以不用考虑在查询之前发生了两次改变怎么办。
分布式事务:
问题:当需要经历不同的服务来做数据改变时,而且数据源也是不同的DB,那么事物怎么做?
我之前做的分布式事务是按照任务的方式,来记录已经成功到哪一步了,每一步也有详细的记录.
当这个事物最后一步,或者是中间一步失败时,会有个补偿机制,根据一个频率再次执行几次失败的逻辑,
如果最后还是失败,那么就有两种方式,要么直接把之前的回滚,要么就是等待工作人员来看失败的详细日志,来进行修复.
多库DB:
有的时候,我们有很多的库,包括mysql里,可能也有很多的数据源,但是我们需要连表查询咋办。
我们使用的是presto,这个是基于内存计算的,他会统计你需要用到的数据做个整合,然后在允许你用sql来进行连
表查询,因为它是基于内存,所以速度非常的快,只不过耗内存嘛,我们也是用的阿里云上的,所以也相当
的烧钱,当然前提并不是所有数据,而是通过你的sql,来晒选出你需要的数据.
如果是超大数据量,建议使用hive
分布式的一些小应用与技巧
封装包上传到公网然后在引用:
就上面说的,直接写个包,放到gitlab上,在引用到项目里,这里就具备统一性,一些公用的函数就可以这样使用.
定时任务:
想起这个就很有意思,我呆过的几家公司,可能也是之前刚开始工作技术不够,用了很多很low的办法.
因为是分布式的,所以一个服务的定时任务,是会同时执行多次,这样情况很多业务是不允许的,那就需要处理
第一种:定时任务不写到服务里,所有定时任务,有专门的一个服务,然后进行执行.
需要把全部的业务操作、db操作写到一起很不好、而且服务负载也不好,因为要是同一时间执行的量大,这样处理
起来就会很麻烦
第二种:服务把定时任务变成api,然后通过一个专门的服务定时调用api.
容易进行负载,但是需要专门写个接口调用的服务,而且这样的话其实是不够准时的.
第三种:利用第三方工具,来校验哪个服务已经在执行定时任务,哪个不该执行.
负载可行,就是需要借助第三方工具.大多还需要自己搭建.
第四种:消息队列,同一分组、主题下只有一个tag能消费到。
负载可行,也简单.
emmm,没错,这四种都是我使用过的,消息队列是实现起来又简单又好用,赞.
串行化:
前端出现的这种情况比较少,由于转变成微服务,那么服务之间的通信就多了很多,比如一个接口需要请求另外服务
的收获信息,
商品详细信息,成本信息,这三个信息分别是在三个不同的服务才能取到,这样就需要先请求收获信息在请求
商品详细信息,以此内推,就会有一个等待的过程,其实这些信息并不是完全关联的,可以一次性查完,
所以同时请求三个接口就好了。
统一化:
统一模版,统一生成初始架构,尽量除了和本服务业务相关的代码,其他代码,都统一好,或者封装好上传,进行引用.
数据组合:
接口的数据组合,最好交给后端,尽量让客户端,做少量的工作,数据的组装聚合,数据量不是很大的情况下,
没有特别麻烦的处理,其实不会造成什么压力,反而这样做会使整个架构更清晰,不会导致稍微一个接口变动,就使得
前端也需要变.
还有一种情况,就是有些特殊的接口,就是计算量大,并发性高,这时候咋办,自己的服务器肯定是吃不消,
那一般这样的话,就直接交给
客户端处理了,就想游戏行业,其实很多数据处理都是由用户的手机、电脑来处理的,这样就能降低公司服务器的压力.
DB连接池
这个程序员应该都比较熟,最基本的概括一下.
超连接时、最大连接数、最小连接数.
其实最初以前很多项目都是没有用连接池的,都是直接open打开单个数据库连接,然后在操作DB。
这样做很消耗资源,因为每执行一条sql,就需要认证、重新建立连接、tcp过程、释放连接。(当
然我没有这么干过)
所以服务专门弄了一套连接池管理,就是用来管理DB的连接的。(很多第三方包都写好了)
简单就说一下,最大连接数和最小连接数就好了
最小连接数是该连接池最初始,以及最少应该建立好多少个连接.
最大连接就连接池允许出现的最大连接数量.
tx会占用连接,所以记得最后一定要提交或回滚,否则它一直占用着连接.
当本地开发时,程序启动过慢,也可以降低最小连接数,这样初始化的时候,就不用初始化那么多连接数了。
线上预估好平均需要活跃的DB连接数,在进行最小连接数配置就好
还有一个之前公司遇到的一个问题,就是当某一刻,并发量请求sql需要的连接数量比最小连接数多很多时,服务和数据库
之间就需要立马建立很多的连接,其实在那一刻是来不及的,所以这个时候只需要加大最低连接数,让服务初始化的时候,
准备足够的连接来响应就好了。
缓存
我们没弄多重缓存,可能是用户的并发量还达不到需要我们用几层缓存的程度。
我们就两种方式:第一种普通的redis就省略了。
第二种:自己启动一个服务当作缓存进行存储,我记得是之前好像有个需求需要实现树状图结构,redis肯定实现不了然后就专门
启动了一个服务实现,我反正最常用的就是临时缓存,先把数据库一小块数据缓存到本地服务,判断条件是接口是不是常用到此块数据,是的话,再根据跟新的频率,来确认是否添加缓存,这样的好处是,快,减少db压力,坏处是:占用一部分内存,跟新需要维护.
运用场景:读超多,写超少。
负载
一开始只有http请求,用的是nginx和阿里云付费的负载,进行服务分发请求.
后面来了grpc,长连接,流式的请求,自己就弄了一套基于etcd的负载
本来以为etcd负载这个技术点以前写过文章的,想直接拷贝链接进来的,结果没有......那就在粗略的写下大概.
负载是在客户端做的,服务端会有注册,心跳使用的是etcd过期机制。
客户端首先会根据etcd获取还有哪些服务在线,然后自己写了两套随机和平均调用,进行请求的发送.
服务端启动时,会给etcd注册服务信息,然后每隔一段时间,会告诉etcd自己还存在,并设置过期时间.
当服务不可以用时,服务在etcd上的信息过几秒(自己设置),就会销毁,就实现了心跳的过程.
emmm,虽然有点low,但当时还挺有用。
好一点的话其实中间有一层服务来专门做服务发现,而不是由客户端来做。
后面就是用k8s来实现整体的负载了。
限流、服务降级、服务熔断
限流
记得几个最常见的:
1.时间段访问量,比如一个小时之类不允许超过1000访问量.否则直接抛出请求.
2.并发量,也就是请求没有结束之前,一共正在执行多少请求,超过1000,则直接抛出请求.
3.令牌桶算法:
就是有桶有令牌,然后生成的一个规则
桶子:用来存放所有请求,在丢给令牌执行.
令牌:一个请求对应一个令牌,只有拥有令牌的请求,才可以执行.
可以设置最高能有多少令牌
令牌恢复速度:当n个令牌里的请求结束后,不是立马恢复,而是通过一个恢复速度逐渐恢复,再给请求执行.
规则:
所有进来,包括后续进来的请求都放在桶里,根据现有的令牌来执行请求,当请求结束后,在按照速度比来恢复
令牌的使用权
4.分布式限流.
就是多个服务,如何一起统计限流,总体的核心,就是就是计数然后限制,一般都是直接使用redis做存储,
然后计数,在使用
对应的算法。
服务降级
当时做一个游戏行业的时候,就是手动,虽然很low,但是还是有点用,就是某些不重要的业务模块,有点吃性能,
或者是不可用,直接通过
配置文件使其不执行,直接抛出维护提示,只让核心业务执行.
当然也可以通过检测警等一系列方式进行自动降级.
我们之前使用的警报就是普罗米修斯,当然我没用这个做,一般情况下可以自己检测一下本服务器的内存,
cpu使用率,网络等等,等达到了
自己预期的最高值,就可以进行降级,保证核心业务没有问题,让一些无关紧要的业务可以先暂缓,
过段时间在恢复。
服务熔断
个人经历,我们项目当中最容易出现这种情况,就是DB操作,因为关于压力测试,其实我们
服务器完全承受得住,主要是mysql,当到达了n亿,tb级别在往上走,并发在高点,sql在麻烦点,
那就不好意思,DB,就容易出现问题,这个时候它往往也没有直接挂掉,只是它不能及时响应客户
端的请求,当服务连接数据库,sql超时设置的是10秒,这种情况就会出现,每次访问这个db时,
此请求都要等待10秒,这样并发上来了,整个服务
n个请求都会陷入等待,从而导致更多的服务挂掉.
可以自己设置一个阈值,当多久请求一个接口或者db连续返回了n次超时或失败后,
直接不进行调用,或者多久不进行调用.
好,结束了,想不到别的了,有疑惑的或者是觉的哪儿可以改善得更好都可以私信交流 —end