grafana / k6

A modern load testing tool, using Go and JavaScript - https://k6.io
GNU Affero General Public License v3.0
23.87k stars 1.2k forks source link

Support gRPC xDS (Envoy proxy) requests #3011

Open UovTech opened 1 year ago

UovTech commented 1 year ago

Feature Description

in the pr https://github.com/grafana/k6/pull/1937 , add xds protocol by update gRPC version.

However, when I try to invoke the grpc server api through the XDS as load balancing procotol, It is not effective.

I tried the following code, and i set up GRPC_XDS_BOOTSTRAP environment variables

import grpc from 'k6/net/grpc';

const client = new grpc.Client();
client.load(null, 'addsvc.proto');

export default () => {
  client.connect('xds:///server.test', { timeout: '5s' });

  const response = client.invoke('addsvc.Add/Sum', {
    a: 1,
    b: 2,
  });
  console.log(response.message.v); // should print 3

  client.close();
};

It will print an error error while dialing: lookup xds on 1.1.1.1:53 (1.1.1.1:53 is my dns server), It seems to handle server.test as a domain name for DNS resolution

can you give me a right example for invoke grpc xds through xDS?

Suggested Solution (optional)

No response

Already existing or connected issues / PRs (optional)

No response

na-- commented 1 year ago

I've never used xDS before, but from what I can see, k6 currently doesn't support it. While we may import a version of google's gRPC library that could support it, we don't have this anonymous import that seems to be required to install the xds resolvers and balancers:

import _ "google.golang.org/grpc/xds"

This is why k6 tries to resolve addsvc.Add as an DNS address, the gRPC library doesn't "know" that it has to treat addresses with an xds:// schema any differently. And while that anonymous import seems easy enough to add, just having that one line adds 16 MB (~33%) to the k6 binary size (:scream:), presumably because this is what the diff with the existing k6 dependencies is:

 614 files changed, 273275 insertions(+), 158 deletions(-)

So, yeah, I am not too keen to do this without more evaluation and consideration, especially when something like that could be done with an xk6 extension... :thinking:

Can you please share more details about your use case? Anyone else who stumbles onto this issue, please do the same and :+1: the OP, so we can gauge community interest.

synackSA commented 3 weeks ago

Figure I'll add my comment here as this is something we're currently looking to do. At this point in time, we have a suite of Python and Go microservices, and we use k6 to perform weekly load testing against the services to generate reports on performance. We're currently in the process of testing out proxyless gRPC using Istio + xDS. I finally was able to get a test service up and running and responding to requests, but I would like to now do a comparison between using xDS and normal proxy. K6 does not currently support it, so I would need to look into creating a plugin as you've suggested here, or clone and make the code change so that it's supported in the base grpc package. It's that or switch to another load testing tool, which I would need to make changes to support too.

On the istio blog page, they used Fortio (with a a code change to support xDS). They have a PR on their github to support xDS, but it was never merged in, so it might be easier to setup a test with that branch, rather than trying to update k6, but that would mean that we would have to potentially move all the current load testing we have setup over to Fortio should we find that xDS is something we want to move all our services too in the future, which could end up being even more work, so having k6 support xDS would be a more ideal situation.

synackSA commented 2 weeks ago

@na-- I was wondering if you had any extra docs, or examples, of how one might implement a plugin that would perform the extra steps needed to support xDS. I've been looking into the gRPC module in the k6 code base, and the connection is created by the Connect() function. Ideally, the extension would just be able to "overwrite" this function, as we also need to add extra functionality to support the xDS Credentials functions (on top of adding in the extra import), which is needed when doing proxyless gRPC with Istio:

import "google.golang.org/grpc/credentials/xds"

...

creds, err := xds.NewClientCredentials(xds.ClientOptions{
    FallbackCreds: insecure.NewCredentials()
})

Ideally, I don't want to (not should I have to), rewrite the whole gRPC k6 module just to support the extra functionality. I was thinking for a gRPC xDS extension, it would just wrap the current gRPC k6 module and "inject" this extra functionality. I don't really see a way to do this the way the current gRPC module is written.

So yeah, if you have any suggestions or examples I could look at to get a better idea on how this might be achieved, it would be greatly appreciated.

olegbespalov commented 2 weeks ago

Hi @synackSA

At a glance, it looks like we don't need to rewrite the whole module to support XDS. Since this is part of the grpc-go SDK, it might be implemented as opt-in. I'll try to look into it and answer you.

As for the module example, we have an archived extension, https://github.com/grafana/xk6-grpc, that we used to bring the streams into k6 (it's not part of the core). If you want, you could try to fork it and experiment with injecting functionality there and see if it works. How does that sound?

synackSA commented 2 weeks ago

@olegbespalov Sure, I can fork it and create a PR for you to review, I don't think it's going to be be too hard.

olegbespalov commented 2 weeks ago

@synackSA sure, that works, thank you!