Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new package instrument: go-redis #1525

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

minimAluminiumalism
Copy link
Contributor

Ref #1053

This project currently does not support Redis, and this PR aims to support it.

Instrumentation for the library github.com/go-redis/redis/v8 is quite difficult, primarily because some of the available instrument functions include input params of type interface{} (this issue is also mentioned in #1209) like this:

func (c *baseClient) process(ctx context.Context, cmd Cmder)

A possible solution (found to be unfeasible after attempting)

I want to get the type of these interface{} type input params, then try to retrieving the corresponding value based on that type. The type field's position of eface is:

type eface struct {
    _type *_type
    data  unsafe.Pointer
}
type _type struct {
    size       uintptr
    ptrdata    uintptr
    hash       uint32
    tflag      uint8
    align      uint8
    fieldalign uint8
    kind       uint8
    equal      func(unsafe.Pointer, unsafe.Pointer) bool
    gcdata     *byte
    str        nameOff
    ptrToThis  typeOff
}

The biggest issue with this solution is its high level of complexity, which will exceed the instruction limit of eBPF(100W) with error program uprobe_process: load program: argument list too long: BPF program is too large. Processed 1000001 insn (4760 line(s) omitted)

The implementation is the closed PR #1522

Final selected solution

So I suppose we cannot directly start from the interface{} input parameters of instrument function. I decided to start with the RESP protocol. Redis cmds will be encoded to bytes stream(RESP), so I chose the instrument func:

func (cn *Conn) WithWriter(ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer)

But the bufio uses write-back buffer strategy. It makes me cannot determine the boundaries of a valid RESP byte stream which is significant for redis pipelining mode with multiple cmds. So I pre-fetched the segments of command through func:

func (c *baseClient) generalProcessPipeline(ctx context.Context, cmds []Cmder, p pipelineProcessor)

I also added a example httpRedis to validate the new instrumentation.

@minimAluminiumalism minimAluminiumalism requested a review from a team as a code owner December 27, 2024 21:23
@minimAluminiumalism
Copy link
Contributor Author

minimAluminiumalism commented Dec 27, 2024

CR @damemi @RonFed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant