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

Spring 应对 IO 密集 的 web 业务系统有什么成熟的做法

  •  
  •   golangLover · 66 天前 · 3545 次点击
    这是一个创建于 66 天前的主题,其中的信息可能已经有所发展或是发生改变。
    也写了 spring 一段时间,发现 spring 比起 event-loop 的相关框架再处理 io 密集或者并发多的时候是性能比较低。
    查了相关的资料,总结出来就是

    1: 直接换 vert.x,但是语法以及生态完全不同。
    2: 上 spring cloud, 注册多个服务硬抗
    3:spring webflux, 好像是改了 controller 那边的方法以及拦截器之类的,但其他可以复用?不知道有没有坑,以及生态怎么样
    4: 多用 servlet3 返回 callable,复用处理线程。

    大家在业务里最主要用的是 2 吗?其他是不是都有坑或者生态问题? 想请大家指教一下。谢谢
    44 条回复    2021-08-24 10:01:25 +08:00
    zoharSoul
        1
    zoharSoul   66 天前
    一般是多个机器硬抗. 反正服务水平扩展简单
    EscYezi
        2
    EscYezi   66 天前 via iPhone
    没上 spring cloud,用的是 k8s 那一套
    ikas
        3
    ikas   66 天前
    这与 spring 有啥关系...网络 io,高性能 spring 那也是用的 netty....
    你只要选择一个高性能网络 io,比如 netty,然后再选择一个异步模型就完事了
    ikas
        4
    ikas   66 天前   ❤️ 1
    1.选择 vert.x,那就是给你全套方案
    2.选择用 spring webflux 作为 web 接口.那它就是解决了网络接入这一部分
    3.选择用 servlet3,然后使用 netty 或者 Undertow 作为 servlet 实现,同上
    2,3 你还要继续选择用啥异步框架.用 spring 的还是其他的..各种各样

    至于 spring cloud,那是架构.而不是上面的 1,2,3.....
    leonme
        5
    leonme   66 天前 via iPhone
    瓶颈不在 DB 在 spring 框架? 加个缓存轻轻松松单机 4000 QPS 啊
    wellsc
        6
    wellsc   66 天前 via iPhone
    @leonme 啥配置啊
    golangLover
        7
    golangLover   66 天前
    @ikas 不是太懂 这句话:“2,3 你还要继续选择用啥异步框架”,难道 spring webflux 不就是异步的框架了吗?你的意思是例如使用远程 api,应该使用非阻塞 http 的客户端这种?
    golangLover
        8
    golangLover   66 天前
    @EscYezi 就是增加 cluster,使得服务实例增加吗? 这个主要的优势是?
    golangLover
        9
    golangLover   66 天前
    @leonme spring 单机应该就是 500 左右吧,预设就是 200 个线程。 应该说瓶颈是在 spring 的 jdbc 连接吧。其实是看了这个: https://www.techempower.com/benchmarks/ 。Spring 在 IO 密集的 fortunes 评分,跌到 300 位以外,比起 node.js 甚至 php 的都低很多。。。。。。
    ikas
        10
    ikas   66 天前
    @golangLover spring webflux 是一个异步的 web 框架,它异步采用的模型是 Reactor...
    但是你 web 层之后的代码.不一定就是选择采用 Reactor 异步的模型,毕竟 java 有那么多异步库可以用
    比如你可以用 spring 的 project reactor,也可以用 rxjava,甚至用 jdk 内置的 CompletableFuture
    再往下说那就更烦了..比如 jdbc 要选啥样的异步库...如果用到 httpclient 又要选择啥样的....
    golangLover
        11
    golangLover   66 天前   ❤️ 1
    @ikas 但是 rxjava 在后端很少有落地的吧,基本上都是安卓前端用的。我觉得可行的第一就是 completablefuture,毕竟内置的,也必须要用。其他要再研究一下。谢谢
    alamaya
        12
    alamaya   66 天前
    golanglover 干嘛搞 java,直接换 golang 不就行了吗
    chendy
        13
    chendy   66 天前
    1. 招人成本高
    2. 不需要 Spring cloud,直接加机器就行
    3. 不能同步写的异步都太难受了,业务逻辑堆起来之后更加难受
    4. 没玩过,目测也不太行
    notejava
        14
    notejava   66 天前
    这个锅,spring 不背
    leonme
        15
    leonme   66 天前
    @golangLover 简单看了下评测项目(解析 json 、返回 plain text 、数据库连接等等),从测试结果来看,一般非 GC 语言优于 GC 语言,复杂框架优于简单框架,比如 servlet 优于 spring,如果只是简单的 echo,那 servlet 肯定优于封装度高的 springmvc,但实际项目谁会直接用 servlet 呢?还有 spring 中使用了封装度很高的 JPA,性能肯定不如直接用 JDBC 啊。。。所有这种评测项目看看就好了,没太大借鉴意义
    yazinnnn
        16
    yazinnnn   66 天前
    业务简单就换 vertx+kotlin
    EscYezi
        17
    EscYezi   66 天前 via iPhone
    @golangLover 优势就是一楼所说,水平扩展简单,对于一般的 http 服务加机器就够了
    leonme
        18
    leonme   66 天前 via iPhone
    @leonme 所以
    pengtdyd
        19
    pengtdyd   66 天前
    花了非常大的力气选语言,选框架,选技术,远远没有多买一台服务器来的实在。
    golangLover
        20
    golangLover   66 天前 via Android
    @leonme #15 @chendy #13 那 java 不那么难受的异步应该怎么写。我看 completablefuture 都 50 多个方法。。。。厉害
    golangLover
        21
    golangLover   66 天前 via Android
    @leonme #15 @yazinnnn #16 @pengtdyd #19 一台新机器就并发几百。。。那得加多少啊。。
    golangLover
        22
    golangLover   66 天前 via Android
    。。。。我发现这新的 V2EX 客户端用不惯都,@错了。大佬无视就好
    chenqh
        23
    chenqh   66 天前
    并发几百确定不是数据库的问题吗?
    cubecube
        24
    cubecube   65 天前
    如果是后台的网络 io,其实用 netty 就是事件驱动的
    如果是磁盘 io,那么用啥都一样,linux 下磁盘的 aio 也就那样。

    如果你觉得线程切换太消耗资源,那么 future 拿到后,使劲回调也一样。。
    chenshun00
        25
    chenshun00   65 天前   ❤️ 1
    不管是不是 WEB 业务系统,绝大部分都是 IO 密集型的业务。

    瓶颈首先不在相关框架,Spring 只是提供了一个平台,你要异步也可以上异步,如果 DB/Cache/RPC 是同步的,框架提供的异步就没有意义了。

    没去过大厂,不知道大厂是怎么做的,我的做法加个 cache 。哪里是瓶颈其实大家心里都有点 B tree,只是改不动撒。

    1. DB(慢 SQL,机器配置,CPU...etc)
    2. 链路长(网络 IO)
    3. 相关链路服务抖动(GC/CPU 高...etc)
    4. 代码写的糙(上千次的同步 RPC 调用)
    5. 框架配置(Redis 配置导致频繁 TCP 握手挥手,全部等待链接。SQL 等待链接)
    5. 机器配置不行

    思考这些比起整异步更实际一点,大厂忽略我。
    leonme
        26
    leonme   65 天前 via iPhone
    @golangLover 你看下它这个机器配置啊,才 2core
    wupher
        27
    wupher   65 天前   ❤️ 1
    web flux 包括 RxJava 在 IO 密集场景也会有 back pressure 的问题。

    由于 event 过多,超出 reactor 出现能力,会出现 event 被丢弃的情况。

    对于这个问题,我觉得无论采用哪种解决方案,服务的无缝伸缩能力都是更重要的。
    jorneyr
        28
    jorneyr   65 天前
    负载均衡呗,多搞几台机器就可以了。
    zmxnv123
        29
    zmxnv123   65 天前
    我们的对象存储 gateway 是 spring
    zhang77555
        30
    zhang77555   65 天前   ❤️ 1
    @golangLover 到底是数据库性能瓶颈还是 web 请求处理瓶颈, 数据库瓶颈可以优化 sql 优化数据库架构, 没法优化了就加个消息队列搞异步处理, web 请求瓶颈水平扩展就行了吧
    ljzxloaf
        31
    ljzxloaf   65 天前
    fashionash
        32
    fashionash   65 天前
    @golangLover 意思是你需要把你代码里的 rpc 、jdbc 等等一系列的都更换成异步模型,否则只是部分异步(要是较真的话也不算全链路的异步了)。但理论上来说,如果能解决网络 web 部分的异步,底层 jdbc 什么的性能上来说也能满足。就看你实际业务对异步的真实需求了
    ps.我自己有个类似网关的 java 服务就用 webflux 异步化了 web 层,底层用的都是同步的,平响上也有提升
    eric96
        33
    eric96   65 天前
    netty+event loop 自己写
    glfpes
        34
    glfpes   65 天前
    处理 IO 密集的场景要靠架构设计,比较常见的是把 IO 密集的工作抽象成一个微服务,把 IO 工作外包出去独立维护。
    BBCCBB
        35
    BBCCBB   65 天前
    不知道淘宝的 rxjava 异步化进展到哪里了...
    dqzcwxb
        36
    dqzcwxb   65 天前
    用 Completablefuture 代价最低,在任何框架都可以使用
    X0ray
        37
    X0ray   65 天前   ❤️ 1
    IO 密集型应用的优化就是两个方向,异步和批量。
    异步用 completable future 就挺好。
    批量主要是接口协议的变化,比如以前 rpc 对象传参,可以把请求响应都改成 list,这样减少调用次数和 rtt.
    golangLover
        38
    golangLover   65 天前 via Android
    @ljzxloaf #31 这个之前看过,一时间把它忘了。哈哈
    golangLover
        39
    golangLover   65 天前 via Android
    @fashionash #32 webflux 的坑大吗,改造 spring 的会不会很麻烦,想预估一下时间。谢谢
    golangLover
        40
    golangLover   65 天前 via Android
    @glfpes #34 这也算一个办法。谢谢
    golangLover
        41
    golangLover   65 天前 via Android
    @dqzcwxb #36 现在在用了,不过并发连接的吞吐量还是太低
    golangLover
        42
    golangLover   65 天前 via Android
    @zhang77555 #30 是 web 并发吞吐量觉得不是太好。
    golangLover
        43
    golangLover   65 天前 via Android
    @X0ray #37 如果有 async await 就最好了,cf 现在还是用的有点辛苦
    ming159
        44
    ming159   64 天前
    String contenxt = File.read("path");

    首先,代码运行是在 CPU 中执行;

    其次,CPU 再向 IO 设备,例如内存,硬盘,或者网络发出读写指令;

    最后,CPU 等待 IO 设备反馈;

    此时,问题就来了,CPU 以纳秒为单位, 无论是内存,硬盘,还是网络,尤其是网络 以毫秒为单位,相差了多少倍,请自行换算.

    就意味着,如果是同步 IO 模型,那在 CPU 发出读写指令后,会令当前线程

    阻塞

    阻塞

    阻塞

    等收到设备数据后,当前线程,继续往下执行.

    针对以上过程,所谓的 "性能" 也好 "吞吐量" 也好,绝大多数浪费在了 CPU 等待 IO 设备反馈的时间上了. 那如何解决这个问题呢?
    请自行阅读 https://segmentfault.com/a/1190000039898780 5 种 IO 模型.

    所以如果想提高 "性能" 两方面入手:

    1. 框架本身基于更高效的 IO 模型
    2. 业务层代码,也使用更高效的 IO 模型库:

    比如将 同步 IO 代码

    String contenxt = File.read("path");
    更换为 异步 IO 代码
    String contenxt = await File.read("path");

    async / await 都是语法糖,语法糖,语法糖,只是语言层面为了开发人员简化书写提供的便捷写法. 而底层 IO 机制无外乎前文中的 5 种 IO 模型
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1630 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 17:17 · PVG 01:17 · LAX 10:17 · JFK 13:17
    ♥ Do have faith in what you're doing.