英文:
How to isolate Jetty HttpClient for multiple users?
问题
使用Eclipse Jetty HttpClient向服务器发送POST请求进行负载测试。
TL;DR:是否有一种方法可以使用单个HttpClient实例和多个用户凭据集到单个目标URL?
为此,我需要以不同的用户身份登录到正在测试的服务器。
尽管HttpClient是线程安全的,但由于其共享的身份验证存储,似乎不能在单个实例中支持这一点。
解决方案似乎很简单,只需为每个用户或每个线程使用一个HttpClient实例。
这个方法还算可以,但是HttpClient为每个实例创建了一些线程(似乎为5到10个线程),所以我的负载测试需要很大的堆空间,否则在尝试创建新线程时会抛出内存不足异常。
例如,在这个非常基本的测试中,第一个凭证集用于所有后续的POST请求:
```java
public class Test
{
static class User
{
String username;
String password;
User(String username, String password)
{
this.username = username;
this.password = password;
}
}
public static void main(String[] args) throws Exception
{
SslContextFactory sslContextFactory = new SslContextFactory.Client();
HttpClient httpClient = new HttpClient(sslContextFactory);
httpClient.start();
List<User> users = new ArrayList<>();
users.add(new User("fry", "1234"));
users.add(new User("leela", "2345"));
users.add(new User("zoidberg", "3456"));
URI uri = new URI("http://localhost:8080/myapi");
for (User user : users)
{
AuthenticationStore auth = httpClient.getAuthenticationStore();
auth.addAuthentication(new DigestAuthentication(uri, DigestAuthentication.ANY_REALM, user.username, user.password));
Request request = httpClient.newRequest(uri);
request.method("POST");
ContentResponse result = request.send();
System.out.println(result.getStatus());
}
}
}
现在,在这个刻意设计的测试中,我意识到可以在循环之间调用httpClient.getAuthenticationStore().clearAuthenticationResults()
和httpClient.getAuthenticationStore().clearAuthentications();
,但在我的实际测试中,我有多个线程同时发送POST请求。
我是否必须为每个用户使用单独的HttpClient实例?
谢谢任何想法!
<details>
<summary>英文:</summary>
I am using Eclipse Jetty HttpClient to send POST requests to a server, for load testing.
TL;DR: Is there a way to use a single HttpClient instance with multiple user credential sets to a single destination URL?
For this purpose, I need to log in to the server-under-test as separate users.
Even though HttpClient is thread safe, it does not appear to support this with a single instance, due to its shared authentication store.
The solution seems easy, just use one HttpClient per user, or per thread.
This works okay, except that HttpClient creates a number of threads (5 to 10 it seems) for each instance, and so my load test needs a very large heap or else it will start throwing OutOfMemory exceptions when trying to create new threads.
For example, in this very basic test, the first set of credentials is used for all subsequent POSTs:
public class Test
{
static class User
{
String username;
String password;
User(String username, String password)
{
this.username = username;
this.password = password;
}
}
public static void main(String[] args) throws Exception
{
SslContextFactory sslContextFactory = new SslContextFactory.Client();
HttpClient httpClient = new HttpClient(sslContextFactory);
httpClient.start();
List<User> users = new ArrayList<>();
users.add(new User("fry", "1234"));
users.add(new User("leela", "2345"));
users.add(new User("zoidberg", "3456"));
URI uri = new URI("http://localhost:8080/myapi");
for (User user : users)
{
AuthenticationStore auth = httpClient.getAuthenticationStore();
auth.addAuthentication(new DigestAuthentication(uri, DigestAuthentication.ANY_REALM, user.username, user.password));
Request request = httpClient.newRequest(uri);
request.method("POST");
ContentResponse result = request.send();
System.out.println(result.getStatus());
}
}
}
Now, I realize in this contrived test that I can call `httpClient.getAuthenticationStore().clearAuthenticationResults()` and `httpClient.getAuthenticationStore().clearAuthentications();` between loops, however that does not work for my actual testing, where I have multiple threads posting at the same time.
Am I stuck using a separate HttpClient instance for each user?
Thanks for any ideas!
</details>
# 答案1
**得分**: 2
你所需的操作可以通过在每个请求中“预先”截取身份验证标头来实现,如[文档中所述][1]。
具体步骤如下:
```java
// 单个 HttpClient 实例。
HttpClient httpClient = new HttpClient();
// 服务器 URI。
URI uri = URI.create("http://example.com/secure");
// 每个用户的身份验证凭据。
Authentication.Result authn1 = new BasicAuthentication.BasicResult(uri, "user1", "password1");
Authentication.Result authn2 = new BasicAuthentication.BasicResult(uri, "user2", "password2");
// 创建请求实例。
Request request1 = httpClient.newRequest(uri);
// 为 user1 添加授权标头。
authn1.apply(request1);
request1.send();
Request request2 = httpClient.newRequest(uri);
// 为 user2 添加授权标头。
authn2.apply(request2);
request2.send();
发送请求不需要像上面简单示例中那样是顺序的或使用阻塞的 API。
你可以通过 for
循环来完成,例如随机选择一个用户(及其对应的授权信息),并使用异步 API 来获得更好的性能。
英文:
What you need can be done by "preempting" the authentication headers for every request, as explained in the documentation.
This is how you would do it:
// Single HttpClient instance.
HttpClient httpClient = new HttpClient();
// The server URI.
URI uri = URI.create("http://example.com/secure");
// The authentication credential for each user.
Authentication.Result authn1 = new BasicAuthentication.BasicResult(uri, "user1", "password1");
Authentication.Result authn2 = new BasicAuthentication.BasicResult(uri, "user2", "password2");
// Create a request instance.
Request request1 = httpClient.newRequest(uri);
// Add the authorization headers for user1.
authn1.apply(request1);
request1.send();
Request request2 = httpClient.newRequest(uri);
// Add the authorization headers for user2.
authn2.apply(request2);
request2.send();
Sending the requests does not need to be sequential or using the blocking APIs like in the simple example above.
You can do it from a for
loop, and pick a user (and its correspondent authorization) randomly, for example, and use the asynchronous APIs for better performance.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论