Apache HttpAsyncClients DeadlineTimeoutException after several days of working application - apache-flink

I have Kinesis Analytics application running with Flink and use external Flink Sink object to transfer data with Apache HttpAsyncClients. The below code is working fine for some time.
override def open(): Unit = {
uuid = randomUUID.toString
client = HttpAsyncClients
.custom()
.setKeepAliveStrategy(
DefaultConnectionKeepAliveStrategy.INSTANCE
)
.build()
client.start()
}
override def invoke(event: String): Unit = {
log.info(s"Received Value to sink: ${event.length} Head: ${event.take(20)}")
val request = createRequest(event)
client.execute(
request,
new FutureCallback[SimpleHttpResponse]() {
override def completed(response: SimpleHttpResponse): Unit = {
val status = StatusLine(response)
if (status.isError) {
log.error(s"Request: $request Status: $status Body: ${response.getBodyText}")
}
}
override def failed(ex: Exception): Unit = {
log.error(s"Request: $request Ex: $ex")
}
override def cancelled(): Unit = {
log.error(s"Request: $request Cancelled")
}
}
)
}
private def createRequest(event: String): SimpleHttpRequest = {
SimpleRequestBuilder
.post()
.setHttpHost(new HttpHost(URIScheme.HTTPS.id, host))
.setPath(path)
.setBody(event, ContentType.APPLICATION_JSON)
.build()
}
override def close(): Unit = {
client.close(CloseMode.GRACEFUL)
}
}
I have around 80k requests every minute and this app works fine for several days, before starting to raise DeadlineTimeoutException. Initially I thought it's related to the throughput, which my server can accept, but I don't see application errors on the backend. Instead, all requests just fail after some time.
I don't really know what is happening, because if socket connection is not closed properly and there is actual timeout I should see some requests dropping off. Instead, at the event of failure I stop to receive any traffic and zero requests successful.
I believe something has to be added for the configuration of the HTTP client, and sockets should not clog. From the documentation it seems like it shouldn't happen, socket connection and leased connection should be terminated. But at this point I have no idea what has to be changed.

Related

Controlling the reactor execution for certain use cases (or get response at certain point)

I am trying to update a document in MongoDB but cannot get to checking updated status and responding back to user. Below is my code:
#Autowired
ReactiveMongoTemplate mongoTemplate;
public Mono<String> updateUser(UserIn userIn) {
UserResponse resp = new UserResponse();
mongoTemplate.findAndModify(query, update, User.class)
//.doOnSuccess(bsItem -> {
.flatMap(user -> {
if(user.getItemId().equals(userIn.getId("_id")))
resp.setStatus("Updated");
else
resp.setStatus("Failed");
return Mono.just(resp);
}).subscribe();
return Mono.just(resp.getStatus());
}
Even though update is happening in mongodb, it throws NPE while returning. How to get the control after reactor operator is executed here?
You should almost never subscribe in your own application.
The subscriber is the client that initiated the call in this case it is probably the web application. You application is just relaying the data, so your application is a publisher which means you should not subscribe. The web app subscribes.
Try this.
#Autowired
ReactiveMongoTemplate mongoTemplate;
public Mono<String> updateUser(UserIn userIn) {
return mongoTemplate.findAndModify(query, update, User.class)
.flatMap(user -> {
final UserResponse resp = new UserResponse();
if(user.getItemId().equals(userIn.getId("_id")))
resp.setStatus("Updated");
else
resp.setStatus("Failed");
return Mono.just(resp.getStatus());
});
}
A mono is not like a stream, you fetch, map and return, all in the same mono, like a chain of events. An event chain.

Flink 1.6 Async IO - How to increase throughput when enriching a stream, using a REST service call?

I am currently on Flink version 1.6 and am facing an issue with AsyncIO wherein the performance is not up to my expectation.
I am sure I am doing something wrong in my implementation, so any advice/suggestions would be appreciated.
Issue Synopsis -
I am consuming a stream of ids.
For each id, I need to call a REST service.
I've implemented a RichAsyncFunction, which performs the async REST call.
Here's the relevant code method and the asyncInvoke method
// these are initialized in the open method
ExecutorService executorService =
ExecutorService.newFixedThreadPool(n);
CloseableHttpAsyncClient client = ...
Gson gson = ...
public void asyncInvoke(String key, final ResultFuture<Item> resultFuture) throws Exception {
executorService.submit(new Runnable() {
client.execute(new HttpGet(new URI("http://myservice/" + key)), new FutureCallback<HttpResponse>() {
#Override
public void completed(final HttpResponse response) {
System.out.println("completed successfully");
Item item = gson.fromJson(EntityUtils.toString(response.getEntity), Item.class);
resultFuture.complete(Collections.singleton(item));
}
});
});
}
With the above implementation, I've tried :-
Increasing the parallelism of the enrichment operation
Increasing the number of threads in the executor service
Using apache http async client, I've tried tweaking the connection manager settings - setDefaultMaxPerRoute and setMaxTotal.
I am consistently getting a throughput of about 100 requests/sec. The service is able to handle more than 5k per sec.
What am I doing wrong, and how can I improve this ?

Only one usage of each socket address (protocol/network address/port) is normally permitted

The last few weeks we have been experiencing this error message while using the Azure Search SDK (1.1.1 - 1.1.2) and performing searches.
We consume the Search SDK from internal APIs (deployed as Azure Web Apps) that scale up-down based on traffic (so there could be more than 1 instance of the APIs doing the searches).
Our API queries 5 different indexes and maintains an in-memory copy of the SearchIndexClient object that corresponds to each index, a very simple implementation would look like:
public class AzureSearchService
{
private readonly SearchServiceClient _serviceClient;
private Dictionary<string, SearchIndexClient> _clientDictionary;
public AzureSearchService()
{
_serviceClient = new SearchServiceClient("myservicename", new SearchCredentials("myservicekey"));
_clientDictionary = new Dictionary<string, SearchIndexClient>();
}
public SearchIndexClient GetClient(string indexName)
{
try
{
if (!_clientDictionary.ContainsKey(indexName))
{
_clientDictionary.Add(indexName, _serviceClient.Indexes.GetClient(indexName));
}
return _clientDictionary[indexName];
}
catch
{
return null;
}
}
public async Task<SearchResults> SearchIndex(SearchIndexClient client, string text)
{
var parameters = new SearchParameters();
parameters.Top = 10;
parameters.IncludeTotalResultCount = true;
var response = await client.Documents.SearchWithHttpMessagesAsync(text, parameters, null, null);
return response.Body;
}
}
And the API would invoke the service by:
public class SearchController : ApiController
{
private readonly AzureSearchService service;
public SearchController()
{
service = new AzureSearchService();
}
public async Task<HttpResponseMessage> Post(string indexName, [FromBody] string text)
{
var indexClient = service.GetClient(indexName);
var results = await service.SearchIndex(indexClient, text);
return Request.CreateResponse(HttpStatusCode.OK, results, Configuration.Formatters.JsonFormatter);
}
}
We are using SearchWithHttpMessagesAsync due to a requirement to receive custom HTTP headers instead of the SearchAsync method.
This way we avoid opening/closing the client under traffic bursts. Before using this memory cache (and wrapping each client on a using clause) we would get port exhaustion alerts on Azure App Services.
Is this a good pattern? Could we be receiving this error because of the multiple instances running in parallel?
In case it is needed, the stack trace shows:
System.Net.Http.HttpRequestException: Only one usage of each socket address (protocol/network address/port) is normally permitted service.ip.address.hidden:443
[SocketException:Only one usage of each socket address (protocol/network address/port)is normally permitted service.ip.address.hidden:443]
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,Socket s4,Socket s6,Socket& socket,IPAddress& address,ConnectSocketState state,IAsyncResult asyncResult,Exception& exception)
[WebException:Unable to connect to the remote server]
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult,TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
EDIT: We are also receiving this error A connection attempt failed because the connected party did not properly respond after a period of time:
System.Net.Http.HttpRequestException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond service.ip.address.hidden:443
[SocketException:A connection attempt failed because the connected party did not properly respond after a period of time,or established connection failed because connected host has failed to respond service.ip.address.hidden:443]
at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure,Socket s4,Socket s6,Socket& socket,IPAddress& address,ConnectSocketState state,IAsyncResult asyncResult,Exception& exception)
[WebException:Unable to connect to the remote server]
at System.Net.HttpWebRequest.EndGetRequestStream(IAsyncResult asyncResult,TransportContext& context)
at System.Net.Http.HttpClientHandler.GetRequestStreamCallback(IAsyncResult ar)
As implemented in the code in your question, the cache will not prevent port exhaustion. This is because you're instantiating it as a field of the ApiController, which is created once per request. If you want to avoid port exhaustion, the cache must be shared across all requests. To make it concurrency-safe, you should use something like ConcurrentDictionary instead of Dictionary.
The "connection attempt failed" error is likely unrelated.

(Android Studio) Connecting an app to Google Endpoints Module

I'm having trouble following the second step here.
I really don't understand how this sample does anything other than return a simple toast message. How does it utilize the API to display that message?
class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private static MyApi myApiService = null;
private Context context;
#Override
protected String doInBackground(Pair<Context, String>... params) {
if(myApiService == null) { // Only do this once
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// options for running against local devappserver
// - 10.0.2.2 is localhost's IP address in Android emulator
// - turn off compression when running against local devappserver
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
// end options for devappserver
myApiService = builder.build();
}
context = params[0].first;
String name = params[0].second;
try {
return myApiService.sayHi(name).execute().getData();
} catch (IOException e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(context, result, Toast.LENGTH_LONG).show();
}
I'm afraid my this sample is too complex for my limited knowledge. How exactly do I "talk" to the Google Endpoints Module when running an app? Specifically, What is EndpointsAsyncTask();?
Are there any resources listing all the methods available to me? Is there a simpler example of an app communicating with a Google Cloud Endpoint?
The service methods available to you are defined by the backend source in section 1.
In the example you posted, this line: myApiService.sayHi(name).execute()
is an actual invocation call to the backend that you defined by annotating #ApiMethod("sayHi") on the method in the MyEndpoint.java class of your backend module.
The reason your Android app defines an EndpointsAsyncTask is because slow operations such as calls that hit the network need to happen off of the UI thread to avoid locking the UI. The demo simply puts the returned value into a Toast but you could modify onPostExecute() to do whatever you'd like with the result.
For more info on Google Endpoints check out:
https://cloud.google.com/appengine/docs/java/endpoints/
And for info about using an Android AsyncTask look here:
http://developer.android.com/reference/android/os/AsyncTask.html

What happens if an application calls more than 10 asynchronous URL Fetch on Google App Engine?

Reading the Google App Engine documentation on asynchronous URL Fetch:
The app can have up to 10 simultaneous
asynchronous URL Fetch calls
What happens if an application calls more than 10 async fetch at a time?
Does Google App Engine raise an exception or simply queue the remain calls waiting to serve them?
Umm, Swizzec is incorrect. Easy enough to test:
rpc = []
for i in range(1,20):
rpc.append(urlfetch.createrpc())
urlfetch.make_fetch_call(rpc[-1],"http://stackoverflow.com/questions/3639855/what-happens-if-i-call-more-than-10-asynchronous-url-fetch")
for r in rpc:
response = r.get_result().status_code
This does not return any exceptions. In fact, this works just fine! Note that your results may vary for non-billable applications.
What Swizec is reporting is a different problem, related to maximum simultaneous connections INTO your application. For billable apps there is no practical limit here btw, it just scales out (subject to the 1000ms rule).
GAE has no way of knowing that your request handler will issue a blocking URL fetch, so the connection 500's he is seeing are not related to what his app is actually doing (that's an oversimplification btw, if your average request response time is > 1000ms your likelyhood of 500's increases).
This is an old question, but I believe the accepted answer is incorrect or outdated and may confuse people. It's been a couple of months that I actually tested this, but in my experience Swizec is quite right that GAE will not queue but rather fail most asynchronous URL fetches exceeding the limit of around 10 simultaneous ones per request.
See https://developers.google.com/appengine/docs/python/urlfetch/#Python_Making_requests and https://groups.google.com/forum/#!topic/google-appengine/EoYTmnDvg8U for a description of the limit.
David Underhill has come up with a URL Fetch Manager for Python, which queues asynchronous URL fetches that exceed the limit in application code.
I have implemented something similar for Java, which synchronously blocks (due to the lack of a callback function or ListenableFutures) additional requests:
/**
* A URLFetchService wrapper that ensures that only 10 simultaneous asynchronous fetch requests are scheduled. If the
* limit is reached, the fetchAsync operations will block until another request completes.
*/
public class BlockingURLFetchService implements URLFetchService {
private final static int MAX_SIMULTANEOUS_ASYNC_REQUESTS = 10;
private final URLFetchService urlFetchService = URLFetchServiceFactory.getURLFetchService();
private final Queue<Future<HTTPResponse>> activeFetches = new LinkedList<>();
#Override
public HTTPResponse fetch(URL url) throws IOException {
return urlFetchService.fetch(url);
}
#Override
public HTTPResponse fetch(HTTPRequest request) throws IOException {
return urlFetchService.fetch(request);
}
#Override
public Future<HTTPResponse> fetchAsync(URL url) {
block();
Future<HTTPResponse> future = urlFetchService.fetchAsync(url);
activeFetches.add(future);
return future;
}
#Override
public Future<HTTPResponse> fetchAsync(HTTPRequest request) {
block();
Future<HTTPResponse> future = urlFetchService.fetchAsync(request);
activeFetches.add(future);
return future;
}
private void block() {
while (activeFetches.size() >= MAX_SIMULTANEOUS_ASYNC_REQUESTS) {
// Max. simultaneous async requests reached; wait for one to complete
Iterator<Future<HTTPResponse>> it = activeFetches.iterator();
while (it.hasNext()) {
if (it.next().isDone()) {
it.remove();
break;
}
}
}
}
}
500 errors start happening. Silently.
You only find out about these when you look at your log under all requests (don't get listed as errors). It simply says "The request was aborted because you reached your simultaneous requests limit".
So when you're making lots of asynchronous calls, make sure you can handle some of them spazzing out.
See if this answers your question:
http://groups.google.com/group/google-appengine/browse_thread/thread/1286139a70ef83c5?fwc=1

Resources