V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
gouchaoer
V2EX  ›  程序员

我所理解的微服务

  •  
  •   gouchaoer · 2017-06-27 15:18:11 +08:00 · 6656 次点击
    这是一个创建于 2466 天前的主题,其中的信息可能已经有所发展或是发生改变。

    自从去年开始工作以后就被微服务刷屏了,各大厂争先进行微服务改造,放出的各种 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 池的协程就方便很好了,当然了你说可以用延时队列,然而我们到底应该开多少线程去盯着延时队列呢(一个线程同时只能处理一个请求)?

    38 条回复    2017-06-29 09:06:37 +08:00
    timbotetsu
        1
    timbotetsu  
       2017-06-27 15:37:13 +08:00
    只说我懂的部分,好吧沟槽聚聚

    1 和 2 实际上业界更通用的做法是使用 MQ 做解耦
    3. 如果应用的配置正好能与 SCM 管理工具合作的话也基本不会用到服务发现
    4. 和我的理解上还是有点偏差,觉得过于复杂了
    5. 对,但是也不一定是必须,因为能从 upstream、传参上也能大致定位到问题在哪
    6. 异地部署和灾备的作用理解好像有点问题,涉及到 DNS 的切换的话,不是一下子就能迅速切过去的
    7. 有 API 监控的方案,但是报警方案觉得设计上会比较难,相当于一个规则系统了,做好智能包茎是挺难的
    gouchaoer
        2
    gouchaoer  
    OP
       2017-06-27 15:46:27 +08:00
    @timbotetsu 1 和 2 是我对微服务最本质的理解,是我总结的关于微服务的“两个凡是”方针,你否定了我的“两个凡是”就等于否定了我
    lovedebug
        3
    lovedebug  
       2017-06-27 15:51:08 +08:00
    我理解的微服务是系统由一堆的服务以及服务管理器组成,可以随意的增删。这要求系统必须尽可能解耦。
    heihei20088
        4
    heihei20088  
       2017-06-27 15:51:58 +08:00   ❤️ 2
    我所理解的微服务是基于业务的拆解,而不是 io,多线程的方面。
    timbotetsu
        5
    timbotetsu  
       2017-06-27 15:55:19 +08:00
    @gouchaoer 那我还是不谈了:)
    misaka19000
        6
    misaka19000  
       2017-06-27 15:55:23 +08:00   ❤️ 1
    @heihei20088 #4 我觉得也是,所以感觉微服务和 DDD 能够非常好的结合起来使用
    Morriaty
        7
    Morriaty  
       2017-06-27 16:07:17 +08:00
    @timbotetsu 你们热更新怎么做的?
    timbotetsu
        8
    timbotetsu  
       2017-06-27 16:12:58 +08:00
    @Morriaty blue-green deployment
    monsoon
        9
    monsoon  
       2017-06-27 16:24:17 +08:00
    我的一些看法,当然我不是微服务的专家!

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

    我觉得这句话其实是不正确的。一般的 Web 后端不是不适合微服务,而是没必要微服务。但是实际上一些非常简单的对数据库的删查改都非常适合做成微服务,如果这部分提供的 API 服务是你业务非常核心的业务,而且非常需要 Scale (乃至 reactive ),这时候做成微服务是非常有价值的,而且也利于迭代这部分核心的业务。

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

    我觉得这也是错误的,微服务并不需要一定有 TCP 池,一个微服务可以通过各种的形式给外接提供接口,并不需要 TCP 池,就算你通过 Atom ( https://en.wikipedia.org/wiki/Atom_(standard)) 让别人订阅数据也没关系。

    > 2、凡是涉及到 io 的部分要么用异步要么用协程,不允许阻塞,因为 io 部分意味着这部分消耗时间很长,如果阻塞在这里 qps 一大就会同时有长千上万的线程卡在 io 的地方,cpu 调度这些线程消耗很大。

    我觉得这也是错误的,在一个现实世界里,一个微服务用到一些东西是阻塞的是再说难免。比如说你用的数据库并不是在驱动级别支持异步的。但这从来不是问题,你只要讲这部分阻塞的东西放到一个很好的围栏里(放到一个线程池里并采取相应的措施)。当然你的微服务的很多阻塞的部分可能是你当前的微服务的一块比较短的短板,但是这永远也不会因为你的一个后端有阻塞的部分,而使你的后端无法成为一个微服务。
    jiangzhuo
        10
    jiangzhuo  
       2017-06-27 16:26:12 +08:00
    所有业务迁移到 lambda 上了一个月,然后我又都换回 EC2 了,那稳定性那酸爽
    cevincheung
        11
    cevincheung  
       2017-06-27 16:26:33 +08:00
    底层服务:
    SLB & POOL: SocketManager、MQ、SearchServices、Payment

    上层基础服务(应用下层):
    商品搜索:Input & Output -> SearchServices
    订单推送、短信下发:MQ & Worker
    系统订单支付、管理、对账: 订单发生->Payment,对账监控&支付结果处理:MQ

    应用层:
    商城系统,用户系统,订单系统

    我们这么设计的
    gouchaoer
        12
    gouchaoer  
    OP
       2017-06-27 16:33:00 +08:00
    @monsoon 我也不懂,因为我没做过微服务产品呢
    monsoon
        13
    monsoon  
       2017-06-27 16:45:39 +08:00
    @gouchaoer 感觉我刚刚好像批评的太多了(我的错),不要太往心里去,权当学习交流好了。
    不过这个东西真的很复杂,其实有段时间我也想学习下微服务,后来发现如果我工作里完全没用到的话,不就一点价值都没有了,然后我就没学了……
    gouchaoer
        14
    gouchaoer  
    OP
       2017-06-27 16:48:58 +08:00
    @monsoon 有理太敏感了,我根本就是字面上意思,外加一点欢乐的调侃而已。。。
    yanzixuan
        15
    yanzixuan  
       2017-06-27 16:51:36 +08:00
    @gouchaoer 微服务还有一个短路器你提到,专门解决调用响应时间长拖慢整体系统的问题。
    timbotetsu
        16
    timbotetsu  
       2017-06-27 17:21:50 +08:00
    @monsoon 你看他凶我那样,真是
    yoke123
        17
    yoke123  
       2017-06-27 17:36:37 +08:00
    太高端 看不懂 老实搬砖去了.....
    sumuu
        18
    sumuu  
       2017-06-27 17:43:11 +08:00
    微服务是属于架构层的概念,用最简单的一句话来概括就是"把一个整体项目通过适应的模式(业务),分解成多个小项目"

    举个很简单的例子:
    一个电商平台,有用户,产品,支付等系统,通过业务分开后为: 用户,产品,支付,各自解耦,分开部署,互不干涉.
    然后通过制定的通信方式,REST ? RPC? 达到各个系统的通信.

    我对微服务的抽象理解,具体用什么技术,用什么软件,这个是更细的,和微服务没有关系.
    codein
        19
    codein  
       2017-06-27 17:44:09 +08:00
    有不少互联网公司现在都跟着 netflix,用 spring cloud 那一整套
    gouchaoer
        20
    gouchaoer  
    OP
       2017-06-27 17:53:34 +08:00
    @monsoon scale 和微服务并没有关系,就算是一个单体应用我部署到多台机器上也可以 scale 啊,核心业务我封装一下复用修改也很方便,搞成微服务还有一层 rpc 消耗呢;对数据库的增删查改恰恰不适合做成微服务,而且我认为每次请 api 请求所涉及到的内部微服务调用应该尽量少。。。

    至于为什么 io 的地方一定要用协程或者异步,因为一个 api 在某次请求去 rpc 调用别的微服务的时候阻塞的时间会更长(必须等待别的微服务完成处理并返回),所以必须异步或协程,mysql 驱动必须使用异步 /协程版本的,redis 也是,httpclient 也是,rpc 也是。。。所有用同步阻塞的,qps 必然有本质降低
    chairuosen
        21
    chairuosen  
       2017-06-27 18:00:14 +08:00
    @timbotetsu 输入法出卖了你
    chairuosen
        22
    chairuosen  
       2017-06-27 18:04:51 +08:00
    @timbotetsu blue-green 只适合无状态的服务吧?
    qieqie
        23
    qieqie  
       2017-06-27 18:50:31 +08:00
    我觉得楼主就是想的太多实践不够
    helloword1995
        24
    helloword1995  
       2017-06-27 20:18:45 +08:00
    我理解的微服务就是后端解耦,解耦到服务都是“微型”的样子。 解耦主体可以是一个企业,也可以是一个项目, 比如一个电商项目的购买行为,可能需要同时使用用户服务,订单服务,支付服务,物流服务。 而没有使用微服务的架构是没有这些服务区分的。
    duoglas
        25
    duoglas  
       2017-06-27 20:22:16 +08:00
    楼主说的每个点本身都是具有一定正确性的。然而并不是有了这些就是微服务,也不是微服务就必须要有这些特性。
    zhuf
        26
    zhuf  
       2017-06-27 22:20:29 +08:00
    我们的系统刚开始是用 django 写的,后来随着功能越加越多,导致经常出问题,就按照一个个 app 拆分掉做成单独的服务了
    slixurd
        27
    slixurd  
       2017-06-27 22:38:31 +08:00
    就是需要一套服务治理框架
    还要有分布式追踪服务
    资源池 /报警 /灾备和是不是微服务没关系.....
    只要是线上服务都需要做....
    sagaxu
        28
    sagaxu  
       2017-06-27 23:01:03 +08:00
    1. 准确的说要有连接池,不管是不是微服务,连接池总归要有的。
    2. 单机 10000 个线程是个典型的分界线,10000 个以内 IO 密集型线程,调度吃得消。
    3. 服务注册和发现,规模很小(服务不到 10 个)的时候,通过配置文件其实也可行,甚至 redis 都不用。
    4. 这跟微服务没有关系啊,单体应用也要有自动发布和灰度发布,单体也是可以多机部署的。
    5. 单体应用一样要足够多的 trace 去排查一些线上问题的。
    6. 灾备必须有,但是跨机房很难,最近一两年支付宝不也出现过异地灾备失效?
    7. 单体一样需要监控和必要的防御措施,跟是不是微服务没有太大关系。

    调用外部耗时 API 占用线程,这个好解决啊,如果调用链路不深,分支不复杂,用非阻塞的 http 客户端加回调就好了。如果调用链路深逻辑复杂,最简单就是把这部分用 Go 或者 elxir 等内置协程的语言重构成一个服务。
    kuno1
        29
    kuno1  
       2017-06-28 08:04:11 +08:00
    nginx 有一篇详细的文章,讲解了微服务的架构设计,值得参考.

    https://www.nginx.com/blog/building-microservices-inter-process-communication/
    (Building Microservices: Inter-Process Communication)
    gouchaoer
        30
    gouchaoer  
    OP
       2017-06-28 10:32:49 +08:00
    @sagaxu 如果单机达到了 10000 个线程的话,内存占用已经很大了吧,我想问问 swoole 的 coroutine 或者 yield 那种半协程的内存占用是多少呢(比如我现在有 10000 个协程在跑所占用的内存)?我看了一下一个 go 的协程似乎只有 8K 字节,swoole 的协程占用内存比较多是不是因为 zend 虚拟机的栈比起 go 的栈要深很多呢?
    everhythm
        31
    everhythm  
       2017-06-28 12:48:51 +08:00
    微服务架构特点,不是要讲 微 的特点么,初看好多都是 服务架构 的特点
    sagaxu
        32
    sagaxu  
       2017-06-28 13:55:40 +08:00
    @gouchaoer Java 线程栈,默认 1M 一个,一般 128KB 也够了。Go 协程,1.4 的时候从 8KB 减少到 2KB 了,将来不管怎么变,估计是不会超过两个 page 的 size 了。我需要协程就直接用 Go 了,所以 swoole 的协程并没研究过。
    wangjxxx
        33
    wangjxxx  
       2017-06-28 14:03:06 +08:00
    这里有一系列的文章 http://blog.daocloud.io/microservices-1/
    感觉回答微服务是什么,为什么要微服务,怎么弄微服务
    Gathaly
        34
    Gathaly  
       2017-06-28 14:32:46 +08:00
    我理解其实就是一种以多进程通讯实现、将业务进行水平拆分的解决方案
    感觉这种做法之前一直都存在,最近几年是给它套了个马甲
    最大特点呢,业务重用是其次,最大作用是可以在更新时,不用停止全部服务
    可能待的不是互联网公司,我觉得它对于自己来说和 docker 一样,没有会用到的机会
    gouchaoer
        35
    gouchaoer  
    OP
       2017-06-28 23:48:02 +08:00 via Android
    @sagaxu 这就很尴尬了,我刚去看了一下 swoole 的协程发现写死了每个 worker 能开的最多协程数量是 3000 个。打比 4 核 cpu 开 8 个 worker 也才 24000 个协程,而 go 的协程可是几十上百万的吧
    abcbuzhiming
        36
    abcbuzhiming  
       2017-06-28 23:52:46 +08:00
    各位,微服务最大的问题在于每个服务背后都有一个独立的数据源啊,你们是怎么做这种分布式事务的,我觉得这才是核心问题,不论这个的话,微服务不过是把以前在一个项目组织内把功能分组进化到每个组进化为一个项目而已,如果解决不了分布式事务的问题,微服务压根也不能有效解决水平扩展问题。但是网上基本没有讲这块的具体实现的,都一股脑的说如何拆分业务
    gouchaoer
        37
    gouchaoer  
    OP
       2017-06-29 08:39:58 +08:00 via Android
    @abcbuzhiming 不要事务,也有分布式带事务的比如 tidb 啥的,不同微服务用不同数据库,数据库撑不住了上集群方案
    abcbuzhiming
        38
    abcbuzhiming  
       2017-06-29 09:06:37 +08:00
    @gouchaoer 你在大部分企业里实践微服务的第一个绕不过去的坎就是把他们原本基于传统关系数据库的系统改造成基于微服务的架构,这其中必然有一致性要求高的业务,要完全不要事务,纯粹 kv 存储是不可能,分布式事务的关系数据库,目前感觉都在发展中,鲜有成熟的例子
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3144 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 48ms · UTC 12:20 · PVG 20:20 · LAX 05:20 · JFK 08:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.