我所理解的微服务

自从去年开始工作以后就被微服务刷屏了,各大厂争先进行微服务改造,放出的各种PPT文档也是眼花缭乱,由于概念太难了我一直没搞懂。最近终于搞懂了啥是微服务,其实很简单。

首先需要确认的是一般的web后端不适合微服务,什么是一般的web后端呢?就是一些比较简单的对数据库增删查改或者对缓存进行操作、用来生成网页html的、写成一个项目也没啥问题的后端,每一次http请求都很快很简单并且没有特别消耗io或者cpu的调用,比如没有去查elastic search、没有去rpc/http访问别的接口。

而哪些任务适合写成微服务呢?就是那些可以从web后端中拆分出来的比较复杂、比较消耗io、比较消耗cpu的一些api,比如专门负责搜索的api、比如专门返回用户订单列表的api、比如需要在后端访问友商接口的api,我们把这些api分离出来做成单独的web服务,而这些web服务有的可能只需要查询一下es、数据库和缓存啥的,有的还可能需要在本次请求中再去rpc/http调用另一些内网外网的api服务。这么做好处就是开发+更新方便,服务之间不容易受到影响。那带来的坏处也有,首先就是前端服务器对api的调用需要走rpc(http rest、thrift等等),这种io消耗是需要避免的;此外还有就是微服务多了调用+上线更新变复杂了,需要自动化这个过程;因此微服务的很多工作就是来弥补这些坏处的。

我认为一个完整的微服务架构最需要满足的几点:

1、凡是涉及到io的部分必须有tcp池,包括es、mysql、redis、rpc甚至http,我们知道tcp建立连接和断开对任何一方都是有消耗的,qps大了这个消耗都必须避免

2、凡是涉及到io的部分要么用异步要么用协程,不允许阻塞,因为io部分意味着这部分消耗时间很长,如果阻塞在这里qps一大就会同时有长千上万的线程卡在io的地方,cpu调度这些线程消耗很大。很多框架为了证明自己性能喜欢用hello world的qps来压测,其实这个只能反映一部分性能,因为hello world没有任何io开销。综合第1点和第2点,php-fpm运行方式不适合微服务,应该尽量避免在 php-fpm 中开 httpclient 去访问别的 api。

3、所有内网的api服务应该实现自动注册发现(etcd、consul和redis比较多),而且尽可能的使用ip+端口号来访问,不要用内网域名也不要用https

4、所有微服务api应该实现自动更新+自动上线,假设某个api后面后AB两台服务器,那么我一旦代码库里发布了一个正式版的代码,那么需要有一个机制保证首先A的流量被切掉并且所有http都返回后,A应用stop然后更新最后start,然后轮到B。当然了这一套可以用nginx和一波openresty的扩展解决,也可以扩展成一个灰度更新机制(比如根据cookie来选择upstream),或者AB test机制。自动上线不一定非要弄个啥docker集群方案,因为我相信大多数业务都比较小可以越简单越好,比如写个shell脚本自动配置环境啥的,都行。

5、所有微服务api应该有trace机制和log收集机制,也就是说每次api调用链都打进log了并且被收集到log服务器(通常是elk),然后我可以看到本次调用时间或者哪个环境出了问题

6、关于异地部署和灾备,首先我反对异地部署同时提供服务(除非你是腾讯google那种大厂,因为太难了),异地可以做个灾备平时不用,一旦发生了严重的状况才把域名解析切到灾备平台(虽然灾备平台很难提供正常服务,不过聊胜于无)。为了避免发生灾难,我认为我们需要尽可能的把主要服务的依赖减到最低,比如我已经依赖了redis,那么当我需要服务注册发现的时候如果可以用redis就最好别去搭建一个etcd。

7、关于报警和熔断,实际上对机器的性能监控以及对api错误的监控大家都在做没啥好说的,然而我认为监控需要能看到哪些api请求异常(所以不同的api最好独立部署在不同机器上),此时咱们首先肯定加机器(这个加机器能自动自然最好),实在不行肯定就只有把异常的api调用掐掉。而异常的api调用来自cc攻击、ddos攻击以及爬虫等乱七八糟的,所以说有个很重要的一点是我们可以在load balancer的地方清洗一下流量,比如我专门有个服务去读log服务器中的异常调用ip/用户,甚至我的后台逻辑里就主动上报有问题的ip/用户,然后在load balancer的地方主动拦截掉。

以上几点就是我认为一个微服务需要具备的特点。

另外我想谈谈一种长时间io服务的情况,比如我有个api把一个关键词http传给友商,友商需要花上几十秒甚至几分钟才能完成任务,这种情况如果友商完成任务后直接回调通知我还好,如果友商可能没法回调我又或者不太稳定的话,我估计就得每隔几秒去轮询一次直到超时,那这样一个请求占了一个线程几分钟qps岂不是狂降?这个时候就用带有tcp池的协程就方便很好了,当然了你说可以用延时队列,然而我们到底应该开多少线程去盯着延时队列呢(一个线程同时只能处理一个请求)?

0

发表评论

电子邮件地址不会被公开。

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>