wireshark抓取dubbo调用实践

发布于:2025-02-23 ⋅ 阅读:(15) ⋅ 点赞:(0)

接上一篇:https://doctording.blog.csdn.net/article/details/145790590, 本文来看下dubbo的调用,对dubbo调用有一个简单的认识

dubbo2协议

Dubbo 框架提供了自定义的高性能 RPC 通信协议:

  • 基于 TCP 的 Dubbo2 协议
  • 基于 HTTP/2 的 Triple 协议

Dubbo2 协议规范:https://cn.dubbo.apache.org/zh-cn/overview/reference/protocols/tcp/

dubbo2协议优缺点

AI回答如下:

在评估Dubbo2协议的优缺点时,我们需要了解Dubbo是一个高性能、轻量级的开源Java RPC框架,它主要用于构建分布式服务应用。Dubbo2是基于Apache Dubbo的最新版本,它继承了Dubbo的许多优点并引入了一些新特性。以下是一些Dubbo2协议的优缺点:

优点

  • 高性能:

Dubbo使用了Netty作为其网络通信框架,支持NIO,能够提供高性能的网络通信能力。

它支持多种序列化方式(如Java原生序列化、Kryo、FST、Hessian等),可以根据需求选择最合适的序列化方式以优化性能。

  • 灵活性:

Dubbo提供了多种配置方式(XML、注解、API等),使得服务的配置更加灵活。

支持多种负载均衡策略和集群容错机制,如随机、轮询、最少活跃调用等。

  • 易用性:

Dubbo提供了丰富的API和工具,简化了分布式服务的开发和管理。

  • 社区活跃,有大量的文档和教程支持,易于上手和学习。

  • 扩展性:

Dubbo具有良好的扩展性,可以通过SPI(Service Provider Interface)机制轻松扩展新功能。

支持服务治理,如服务注册与发现、动态路由、灰度发布等。

  • 兼容性:

Dubbo支持多种协议(Dubbo协议、HTTP、REST等),便于与现有系统集成。

与Spring框架无缝集成,便于在Spring生态系统中使用。


缺点

  • 复杂性:

Dubbo作为一个功能丰富的框架,其配置和使用可能比一些更简单的解决方案要复杂一些,特别是对于初学者。

  • 维护成本:

随着Dubbo的版本更新和新特性的引入,可能需要投入一定的时间和资源来维护和升级现有的系统。

  • 学习曲线:

对于不熟悉Dubbo及其生态系统的开发者来说,可能需要一定的时间来熟悉其工作原理和最佳实践。

  • 性能开销:

虽然Dubbo提供了高性能的网络通信,但在高并发场景下,仍然可能因为序列化/反序列化、网络IO等原因产生一定的性能开销。

  • 依赖管理:

在使用Dubbo时,可能需要管理多个依赖库和框架(如Netty、Zookeeper等),这可能会增加项目的依赖复杂度。


结论:
Dubbo2作为Dubbo的最新版本,继续保持了其高性能和灵活性的优点,同时也引入了一些新特性和改进,如更好的性能优化、更多的协议支持等。然而,它也可能带来一定的复杂性,特别是在配置和维护方面。因此,选择Dubbo2还是其他技术栈,需要根据具体项目的需求、团队的技术栈熟悉程度以及未来的可扩展性需求来综合考虑。如果你正在寻找一个高性能、灵活且易于扩展的RPC框架,Dubbo2是一个不错的选择。然而,如果你的项目对学习曲线和复杂性有较高容忍度,并且需要快速集成到现有系统中,那么它也是一个很好的选项。

wireshark支持dubbo

如下配置:
在这里插入图片描述

init.lua中加入dofile(DATA_DIR.."dubbo.lua")
在这里插入图片描述

直接全局配置目录下新建dubbo.lua文件,dubbo.lua文件内容参考:https://github.com/apache/dubbo/issues/13044, 不过是有错误的,还需改正,内容如下

local bit32 = require "bit32"
do
    local pDubbo = Proto("DUBBO", "Apache Dubbo")
    local fMagic = ProtoField.uint16("dubbo.magic", "Magic", base.HEX)
    local fReqFlag = ProtoField.bool("dubbo.isRequest", "IsRequest", base.NONE)
    local f2Way = ProtoField.bool("dubbo.isTwoWay", "IsTwoWay", base.NONE)
    local fEvent = ProtoField.bool("dubbo.event", "IsEvent", base.NONE)
    local fSerializationID = ProtoField.uint8("dubbo.serializationID", "SerializationID", base.DEC)
    local fStatus = ProtoField.uint8("dubbo.status", "Status", base.DEC)
    local fRequestID = ProtoField.uint32("dubbo.requestID", "RequestID", base.DEC)
    local fDataLength = ProtoField.uint32("dubbo.dataLength", "DataLength", base.DEC)
    local fDubboVersion = ProtoField.string("dubbo.dubboVersion", "DubboVersion", base.UNICODE)
    local fServiceName = ProtoField.string("dubbo.serviceName", "ServiceName", base.UNICODE)
    local fServiceVersion = ProtoField.string("dubbo.version", "Version", base.UNICODE)
    local fMethodName = ProtoField.string("dubbo.methodName", "MethodName", base.UNICODE)
    local fMethodParamTypes = ProtoField.string("dubbo.methodParamTypes", "MethodParamTypes", base.UNICODE)
    local fMethodArgs = ProtoField.string("dubbo.methodArguments", "MethodArguments", base.UNICODE)
    local fAttachment = ProtoField.string("dubbo.attachment", "Attachment", base.UNICODE)

    pDubbo.fields = { fMagic, fReqFlag, f2Way, fEvent, fSerializationID, fStatus, fRequestID, fDataLength, fDubboVersion, fServiceName, fServiceVersion, fMethodName, fMethodParamTypes, fMethodArgs, fAttachment }

    local data_dis = Dissector.get("data")

    local function DUBBO_dissector(buf, pkt, root)
        local function accumulateByteArray(byteArray)
            local idx = 0
            local sum = 0
            while (idx < byteArray:len())
            do
                -- (len - idx- 1) * 8
                sum = sum + bit32.lshift(byteArray:get_index(idx), (byteArray:len() - idx - 1) * 8)
                idx = idx + 1
            end
            return sum
        end

        local function bytesToString(byteArray)
            local str = ""
            local idx = 0
            while (idx < byteArray:len())
            do
                str = str .. string.char(byteArray:get_index(idx))
                idx = idx + 1
            end
            return str
        end

        local function getArrayLength(arr)
            if type(arr) ~= "table" then
                return 0
            end
            return #arr
        end

        local function resolvePart(byteArray, offset)
            -- 检查第一次调用 subset 是否会越界
            if offset > getArrayLength(byteArray) or offset + 4 - 1 > getArrayLength(byteArray) then
                print("第一次调用 subset 时越界,提前返回")
                return nil, offset
            end
            local partBytes = byteArray:subset(offset, 4)
            local partLength = accumulateByteArray(partBytes)
            local startIndex = 4 + offset
            -- 检查第二次调用 subset 是否会越界
            if startIndex > getArrayLength(byteArray) or startIndex + partLength - 1 > getArrayLength(byteArray) then
                -- 调整 partLength 以避免越界
                partLength = getArrayLength(byteArray) - startIndex + 1
                if partLength < 0 then
                    partLength = 0
                end
                print("第二次调用 subset 时越界,调整 partLength 为", partLength)
            end
            local partArray = byteArray:subset(startIndex, partLength)
            offset = offset + 4 + partLength
            return bytesToString(partArray), offset
        end

        local function substringIfNecessary(str, serializationID)
            -- fastjson2 offset 1
            if serializationID == 23
            then
                str = string.sub(str, 2, -1)
                return str
            else
                return str
            end
        end

        local buf_len = buf:len();
        if buf_len < 16 then
            return false
        end

        -- dubbo magic = 0xdabb
        local magic = buf(0, 2)
        if (magic:uint(0, 2) ~= 0xdabb)
        then
            return false
        end
        local t = root:add(pDubbo, buf)
        pkt.cols.protocol = "DUBBO"
        t:add(fMagic, magic)


        -- is dubbo
        local segment2 = buf:bytes(2, 1)
        local seg2Bytes = segment2:get_index(0)
        local reqFlag = bit32.band(seg2Bytes, 128)
        t:add(fReqFlag, reqFlag)

        local twoWay = bit32.band(seg2Bytes, 64)
        t:add(f2Way, twoWay)

        local event = bit32.band(seg2Bytes, 32)
        t:add(fEvent, event)

        local serializationID = bit32.band(seg2Bytes, 0x1F)
        t:add(fSerializationID, serializationID)

        -- requestID
        t:add(fRequestID, accumulateByteArray(buf:bytes(4, 8)))

        local dataLengthSegment = buf:bytes(12, 4)
        local dataBodyLength = accumulateByteArray(dataLengthSegment)
        t:add(fDataLength, dataBodyLength)

        local dataBodyBytes = buf:bytes(16, dataBodyLength)
        if (reqFlag ~= 0)
        then
            -- process request decode
            -- 1.dubbo version
            local offset = 0
            local dubboVersionString, offset = resolvePart(dataBodyBytes, offset)
            if dubboVersionString ~= nil then
                t:add(fDubboVersion, substringIfNecessary(dubboVersionString, serializationID))
            end
            -- t:add(fDubboVersion, substringIfNecessary(dubboVersionString, serializationID))

            --  2. ServiceName
            local serviceName, offset = resolvePart(dataBodyBytes, offset)
            if serviceName ~= nil then
                t:add(fServiceName, substringIfNecessary(serviceName, serializationID))
            end

            -- 3. ServiceVersion
            local serviceVersion, offset = resolvePart(dataBodyBytes, offset)
            if serviceVersion ~= nil then
                t:add(fServiceVersion, substringIfNecessary(serviceVersion, serializationID))
            end

            -- 4. MethodName
            local methodName, offset = resolvePart(dataBodyBytes, offset)
            if methodName ~= nil then
                t:add(fMethodName, substringIfNecessary(methodName, serializationID))
            end

        else
            --    process response decode

            -- 1. status
            t:add(fStatus, buf:bytes(3, 1):get_index(0))
        end
        return true
    end

    function pDubbo.dissector(buf, pkt, root)
        if DUBBO_dissector(buf, pkt, root) then
        else
            data_dis:call(buf, pkt, root)
        end
    end

    local tcpTable = DissectorTable.get("tcp.port")
    tcpTable:add(20881, pDubbo)

end

lua文件更新后可以让wireshark重新加载下

在这里插入图片描述

wireshark抓取dubbo调用

如下调用返回可以抓取到
在这里插入图片描述

附服务提供者:
dubbo://192.168.100.198:20881/com.example.demoapi.dubboprovider.TestService?anyhost=true&application=demoprovider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=com.example.demoapi.dubboprovider.TestService&loadbalance=random&metadata-type=remote&methods=add&pid=4237&release=2.7.8&side=provider×tamp=1740186111060

在这里插入图片描述