I"m doing a stress test on vert.x application and send ~10K RPS.
My application send an http async request from a dedicated verticle.
I"m using vert.x http client, and see that around 20 seconds my application sent the http requests successfully.
After 20 seconds i"m starting to get a lot of "Cannot assign requested address" errors.
I tried to deploy more verticles, to set different values to the http client thread pool and nothing helped to solve the issue.
I guess that the issue related to the high throughput in a short time around 1 minute.
Main Class:
public static void main(String[] args) {
final VertxOptions vertxOptions = new VertxOptions()
.setMaxEventLoopExecuteTime(1)
.setMaxEventLoopExecuteTimeUnit(TimeUnit.MILLISECONDS);
final Vertx vertx = Vertx.vertx(vertxOptions);
final Injector injector = Guice.createInjector(new Dependencies(vertx));
CustomCodecRegister.register(vertx.eventBus());
final Stream<Future<String>> deploymentFutures = Stream.of(
deployWorker(vertx, injector, StatsHttpVerticle.class, 10)
).flatMap(stream -> stream);
CompositeFuture.all(deploymentFutures.collect(Collectors.toList()))
.onSuccess(successfulCompositeFuture -> { });}
private static <T> Stream<Future<String>> deployWorker(Vertx vertx, Injector injector, Class<T> workerVerticleClass, int numVerticles) {
final String poolName = workerVerticleClass.getSimpleName()
.toLowerCase()
.replace("verticle", "-worker-pool");
final int numberOfThreads = 50;
final DeploymentOptions options = new DeploymentOptions()
.setWorker(true)
.setWorkerPoolName(poolName)
.setWorkerPoolSize(numberOfThreads);
return IntStream.range(0, numVerticles)
.mapToObj(ignore -> Future.future((Promise<String> promise) ->
vertx.deployVerticle((Verticle) injector.getInstance(workerVerticleClass), options, promise)));
}
EventBusAdapter:
public void send(Map<String, Object> queryParams, HashMap<String, String> headers, boolean followRedirect, Event eventToFire) {
StatsRequest statsRequest = new StatsRequest(queryParams, headers, eventToFire, followRedirect);
eventBus.request(FIRE_GET_METRIC_TO_STATS,statsRequest);
}
WorkerVerticle:
#Override
public void start(Promise<Void> startPromise) throws Exception {
vertx.eventBus().consumer(FIRE_GET_METRIC_TO_STATS, this::fire);
startPromise.complete();
}
private void fire(Message<StatsRequest> message) {
StatsRequest body = message.body();
MultiMap multimapHeader = MultiMap.caseInsensitiveMultiMap();
WebClientOptions webClientOptions = new WebClientOptions();
webClientOptions.setMaxPoolSize(1000);
WebClient httpClient = WebClient.create(vertx, webClientOptions);
httpClient.request(HttpMethod.GET, port, "example.com", "/1x1.gif" + "?" + "queryParamsString")
.followRedirects(false)
.putHeaders(multimapHeader)
.timeout(120000)
.send()
.onSuccess(response -> {
logger.info("All good");
})
.onFailure(err -> {
logger.error("Exception: " + err.getMessage());
});
}
How can i solve this issue?
Related
I'll give some context information and hope you could get any idea on how could this issue happen.
Firstly, the main thread code for whole app is attched here.
public static void main(String args[]) throws Exception {
AppConfig appConfig = AppConfig.getInstance();
appConfig.initBean("applicationContext.xml");
SchedulerFactory factory=new StdSchedulerFactory();
Scheduler _scheduler=factory.getScheduler();
_scheduler.start();
Thread t = new Thread((Runnable) appConfig.getBean("consumeGpzjDataLoopTask"));
t.start();
}
Main method just does 3 things: inits beans by the Spring way, starts the Quartz jobs thread and starts the sub thread which subscribes one channel in Jedis and listen for msgs continuously. Then I'll show the code for the sub thread which starts subscribing:
#Override
public void run() {
Properties pros = new Properties();
Jedis sub = new Jedis(server, defaultPort, 0);
sub.subscribe(subscriber, channelId);
}
and the thread stack then message received:
But something weird happened in production environment. The quartz jobs scheduler is running properly while the consumeGpzjDataLoopTask seems to be exited somehow! I really can't get an idea why the issue could even happen, as you could see, the sub thread inits one Jedis instance with timeout 0 which stands for running infinitely, so I thought the sub thread should not be closed unless some terrible issues in main thread occured. But in prod environment, the message publisher published messages normally and the messages disappeared, and no related could be found in log file, just like the subscriber thread already been dead. BTW, I never met the situation when self testing in local machine.
Could you help me on the possibility for the issue? Comment me if any extra info needed for problem analyzing. Thanks.
Edited: For #code, here's the code for subscriber.
public class GpzjDataSubscriber extends JedisPubSub {
private static final Logger logger = LoggerFactory.getLogger(GpzjDataSubscriber.class);
private static final String META_INSERT_SQL = "insert into dbo.t_cl_tj_transaction_meta_attributes\n" +
"(transaction_id, meta_key, meta_value) VALUES (%d, '%s', '%s')";
private static final String GET_EVENT_ID_SQL = "select id from t_cl_tj_monthly_golden_events_dict where target = ?";
private static final String TRANSACTION_TB_NAME = "t_cl_tj_monthly_golden_stock_transactions";
private static Map<String, Object> insertParams = new HashMap<String, Object>();
private static Collection<String> metaSqlContainer = new ArrayList<String>();
#Autowired(required = false)
#Qualifier(value = "gpzjDao")
private GPZJDao gpzjDao;
public GpzjDataSubscriber() {}
public void onMessage(String channel, String message) {
consumeTransactionMessage(message);
logger.info(String.format("gpzj data subscriber receives redis published message, channel %s, message %s", channel, message));
}
public void onSubscribe(String channel, int subscribedChannels) {
logger.info(String.format("gpzj data subscriber subscribes redis channel success, channel %s, subscribedChannels %d",
channel, subscribedChannels));
}
#Transactional(isolation = Isolation.READ_COMMITTED)
private void consumeTransactionMessage(String msg) {
final GpzjDataTransactionOrm jsonOrm = JSON.parseObject(msg, GpzjDataTransactionOrm.class);
Map<String, String> extendedAttrs = (jsonOrm.getAttr() == null || jsonOrm.getAttr().isEmpty())? null : JSON.parseObject(jsonOrm.getAttr(), HashMap.class);
if (jsonOrm != null) {
SimpleJdbcInsert insertActor = gpzjDao.getInsertActor(TRANSACTION_TB_NAME);
initInsertParams(jsonOrm);
Long transactionId = insertActor.executeAndReturnKey(insertParams).longValue();
if (extendedAttrs == null || extendedAttrs.isEmpty()) {
return;
}
metaSqlContainer.clear();
for (Map.Entry e: extendedAttrs.entrySet()) {
metaSqlContainer.add(String.format(META_INSERT_SQL, transactionId.intValue(), e.getKey(), e.getValue()));
}
int[] insertMetaResult = gpzjDao.batchUpdate(metaSqlContainer.toArray(new String[0]));
}
}
private void initInsertParams(GpzjDataTransactionOrm orm) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Integer eventId = gpzjDao.queryForInt(GET_EVENT_ID_SQL, orm.getTarget());
insertParams.clear();
insertParams.put("khid", orm.getKhid());
insertParams.put("attr", orm.getAttr());
insertParams.put("event_id", eventId);
insertParams.put("user_agent", orm.getUser_agent());
insertParams.put("referrer", orm.getReferrer());
insertParams.put("page_url", orm.getPage_url());
insertParams.put("channel", orm.getChannel());
insertParams.put("os", orm.getOs());
insertParams.put("screen_width", orm.getScreen_width());
insertParams.put("screen_height", orm.getScreen_height());
insertParams.put("note", orm.getNote());
insertParams.put("create_time", df.format(new Date()));
insertParams.put("already_handled", 0);
}
}
I'm following the akka java websocket tutorial in attempt to create a websocket server. I want to implement 2 extra features:
Being able to display the number of connected clients, but the result
is always 0 or 1 , even when I know I have 100's concurrently
connected clients.
Websocket communication is biDirectional. Currently the server only respond with a message when client sends a message. How do I initiate sending a message from server to client?
Here's original akka java server example code with minimum modification of my client counting implementation:
public class websocketServer {
private static AtomicInteger connections = new AtomicInteger(0);//connected clients count.
public static class MyTimerTask extends TimerTask {
//called every second to display number of connected clients.
#Override
public void run() {
System.out.println("Conncurrent connections: " + connections);
}
}
//#websocket-handling
public static HttpResponse handleRequest(HttpRequest request) {
HttpResponse result;
connections.incrementAndGet();
if (request.getUri().path().equals("/greeter")) {
final Flow<Message, Message, NotUsed> greeterFlow = greeter();
result = WebSocket.handleWebSocketRequestWith(request, greeterFlow);
} else {
result = HttpResponse.create().withStatus(413);
}
connections.decrementAndGet();
return result;
}
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create();
TimerTask timerTask = new MyTimerTask();
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(timerTask, 0, 1000);
try {
final Materializer materializer = ActorMaterializer.create(system);
final Function<HttpRequest, HttpResponse> handler = request -> handleRequest(request);
CompletionStage<ServerBinding> serverBindingFuture =
Http.get(system).bindAndHandleSync(
handler, ConnectHttp.toHost("****", 1183), materializer);
// will throw if binding fails
serverBindingFuture.toCompletableFuture().get(1, TimeUnit.SECONDS);
System.out.println("Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
timer.cancel();
} catch (Exception e){
e.printStackTrace();
}
finally {
system.terminate();
}
}
//#websocket-handler
/**
* A handler that treats incoming messages as a name,
* and responds with a greeting to that name
*/
public static Flow<Message, Message, NotUsed> greeter() {
return
Flow.<Message>create()
.collect(new JavaPartialFunction<Message, Message>() {
#Override
public Message apply(Message msg, boolean isCheck) throws Exception {
if (isCheck) {
if (msg.isText()) {
return null;
} else {
throw noMatch();
}
} else {
return handleTextMessage(msg.asTextMessage());
}
}
});
}
public static TextMessage handleTextMessage(TextMessage msg) {
if (msg.isStrict()) // optimization that directly creates a simple response...
{
return TextMessage.create("Hello " + msg.getStrictText());
} else // ... this would suffice to handle all text messages in a streaming fashion
{
return TextMessage.create(Source.single("Hello ").concat(msg.getStreamedText()));
}
}
//#websocket-handler
}
Addressing your 2 bullet points below:
1 - you need to attach your metrics to the Message flow - and not to the HttpRequest flow - to effectively count the active connections. You can do this by using watchTermination. Code example for the handleRequest method below
public static HttpResponse handleRequest(HttpRequest request) {
HttpResponse result;
if (request.getUri().path().equals("/greeter")) {
final Flow<Message, Message, NotUsed> greeterFlow = greeter().watchTermination((nu, cd) -> {
connections.incrementAndGet();
cd.whenComplete((done, throwable) -> connections.decrementAndGet());
return nu;
});
result = WebSocket.handleWebSocketRequestWith(request, greeterFlow);
} else {
result = HttpResponse.create().withStatus(413);
}
return result;
}
2 - for the server to independently send messages you could create its Message Flow using Flow.fromSinkAndSource. Example below (this will only send one message):
public static Flow<Message, Message, NotUsed> greeter() {
return Flow.fromSinkAndSource(Sink.ignore(),
Source.single(new akka.http.scaladsl.model.ws.TextMessage.Strict("Hello!"))
);
}
In the handleRequest method you increment and then decrement the counter connections, so at the end the value is always 0.
public static HttpResponse handleRequest(HttpRequest request) {
...
connections.incrementAndGet();
...
connections.decrementAndGet();
return result;
}
Does anyone have an idea why is being thrown listed exception after invoking /user URL? It quite strange because all works as is expected (upstream service handles a response from downstream and sends to a response to a client). Using Ratpack 1.4.1. Full code is available: https://github.com/peterjurkovic/ratpack-demo
Edit:
I've just tried downgrade to version 1.3.3 and with this version of Ratpack it is not happening. Github issue created.
Edit 2:
The issue should be resolved in the next version 1.4.2.
public class DownstreamUserService {
Logger log = LoggerFactory.getLogger(DownstreamUserService.class);
private HttpClient httpClient;
private ObjectMapper mapper;
private URI downstreamServerUri;
#Inject
public DownstreamUserService(HttpClient httpClient, Config config, ObjectMapper mapper) {
this.httpClient = httpClient;
this.mapper = mapper;
try {
downstreamServerUri = new URI("http://" + config.getHost() + ":" + config.getPort() + "/endpoint");
} catch (URISyntaxException e) {
log.error("",e);
throw new RuntimeException(e);
}
}
public Promise<User> load(){
return httpClient.get( downstreamServerUri )
.onError(e -> log.info("Error",e))
.map( res -> mapper.readValue(res.getBody().getBytes(), User.class));
}
}
Server
public class App {
static Logger log = LoggerFactory.getLogger(App.class);
public static void main(String[] args) throws Exception {
RatpackServer.start(s -> s
// bindings..
.handlers( chain -> chain
.get("user", c -> {
DownstreamUserService service = c.get(DownstreamUserService.class);
service.load().then( user -> c.render( json(user) ));
})
}
}
Stacktrace:
[2016-08-28 22:58:24,979] WARN [ratpack-compute-1-2] i.n.c.DefaultChannelPipeline - An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.PrematureChannelClosureException: channel gone inactive with 1 missing response(s)
at io.netty.handler.codec.http.HttpClientCodec$Decoder.channelInactive(HttpClientCodec.java:261)
at io.netty.channel.CombinedChannelDuplexHandler.channelInactive(CombinedChannelDuplexHandler.java:220)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:255)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:241)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelInactive(AbstractChannelHandlerContext.java:234)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelInactive(DefaultChannelPipeline.java:1329)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:255)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelInactive(AbstractChannelHandlerContext.java:241)
at io.netty.channel.DefaultChannelPipeline.fireChannelInactive(DefaultChannelPipeline.java:908)
at io.netty.channel.AbstractChannel$AbstractUnsafe$7.run(AbstractChannel.java:744)
at io.netty.util.concurrent.SingleThreadEventExecutor.safeExecute(SingleThreadEventExecutor.java:451)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:418)
at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:306)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:877)
at ratpack.exec.internal.DefaultExecController$ExecControllerBindingThreadFactory.lambda$newThread$0(DefaultExecController.java:136)
at ratpack.exec.internal.DefaultExecController$ExecControllerBindingThreadFactory$$Lambda$129/1240843015.run(Unknown Source)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:144)
at java.lang.Thread.run(Thread.java:745)
hi im creating a simple tool using java to create,update and delete issues(tickets) in jira. i am using rest api following code is im using to authenticate jira and issue tickets.
public class JiraConnection {
public static URI jiraServerUri = URI.create("http://localhost:8090/jira/rest/api/2/issue/HSP-1/");
public static void main(String args[]) throws IOException {
final AsynchronousJiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
final JiraRestClient restClient = factory.createWithBasicHttpAuthentication(jiraServerUri,"vinuvish92#gmail.com","vinu1994");
System.out.println("Sending issue creation requests...");
try {
final List<Promise<BasicIssue>> promises = Lists.newArrayList();
final IssueRestClient issueClient = restClient.getIssueClient();
System.out.println("Sending issue creation requests...");
for (int i = 0; i < 100; i++) {
final String summary = "NewIssue#" + i;
final IssueInput newIssue = new IssueInputBuilder("TST", 1L, summary).build();
System.out.println("\tCreating: " + summary);
promises.add(issueClient.createIssue(newIssue));
}
System.out.println("Collecting responses...");
final Iterable<BasicIssue> createdIssues = transform(promises, new Function<Promise<BasicIssue>, BasicIssue>() {
#Override
public BasicIssue apply(Promise<BasicIssue> promise) {
return promise.claim();
}
});
System.out.println("Created issues:\n" + Joiner.on("\n").join(createdIssues));
} finally {
restClient.close();
}
}
}
according this code i couldn't connect to the jira
**following exception i am getting **
please suggest me best solution to do my task
It seems to me that your error is clearly related to url parameter. The incriminated line and the fact that the error message is about not finding the resource are good indications of it.
You don't need to input the whole endpoint since you are using the JiraRestClient. Depending on the method that you call it will resolve the endpoint. Here is an example that works: as you can see I only input the base url
I write a server with Vertx.
I have about 40k users. I can print every request but I don't know how to know how many current requests my server is serving
I used this class: http://vertx.io/docs/apidocs/io/vertx/core/http/HttpServer.html but this is no method to do it
Vertx is great toolkit but it can not show server status, really????
My server code:
public class MyFirstVerticle extends AbstractVerticle {
private HttpServer httpServer = null;
#Override
public void start() throws Exception {
httpServer = vertx.createHttpServer();
httpServer.requestHandler(new Handler<HttpServerRequest>() {
#Override
public void handle(HttpServerRequest request) {
String path = request.path();
System.out.println("incoming request: [" + request.remoteAddress() + "] at " + path);
}
});
httpServer.listen(9999);
}
}
Since vert.x 3.x.x http://vertx.io/docs/vertx-dropwizard-metrics is an official component of vert.x
I think what you search is this:
http://vertx.io/docs/vertx-dropwizard-metrics/java/#http-server-metrics
There are several possibilities to view the metrics
jmx http://vertx.io/docs/vertx-dropwizard-metrics/java/#jmx
http bridge for jmx http://vertx.io/docs/vertx-dropwizard-metrics/java/#_using_jolokia_and_hawtio
In our project we write periodically to a log file and send it in parallel to a graphite / grafana instance over udp
Vert.x requests are very short lived, so basing calculations solely on number of requests per second is not optimal. But, for the sake of discussion, you can achieve what you want in the following way:
public class MyFirstVerticle extends AbstractVerticle {
private HttpServer httpServer = null;
// Bad, done for the sake of simplicity
public final static AtomicInteger counter = new AtomicInteger(0);
#Override
public void start() throws Exception {
httpServer = vertx.createHttpServer();
httpServer.requestHandler(new Handler<HttpServerRequest>() {
public void handle(HttpServerRequest request) {
counter.incrementAndGet();
String path = request.path();
System.out.println("incoming request: [" + request.remoteAddress() + "] at " + path);
request.response().end();
request.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
counter.decrementAndGet();
}
});
}
});
httpServer.listen(9999);
}
}
Then to test yourself you can try something like that:
public class Main {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
MyFirstVerticle verticle = new MyFirstVerticle();
vertx.deployVerticle(verticle);
// Very bad, but our request are very short
vertx.setPeriodic(1, new Handler<Long>() {
#Override
public void handle(Long aLong) {
// Otherwise will overflow our console
if (MyFirstVerticle.counter.intValue() > 0) {
System.out.println(MyFirstVerticle.counter.intValue());
}
}
});
}
}