Opening redis connection is too slow - connection

It sometimes takes very long time to open connection to Redis. Looks like it depends on connecting thread's count and, maybe, PC configuration. I run test for 50 threads on two workstations with 4-core CPU's, and it takes 70-100ms to open connection, and on 8-core workstation and 8-core staging server it took 1000-1500ms and sometimes much more. Strange dependency, but it' reproductible.
When IIS application pool restarts, and all threads are trying to reconnect, it causes something like cache downtime. What I have to change to get reasonable connection time?
I use BookSleeve client, and here is code sample:
static void Main(string[] args)
{
for (var i = 0; i < threadCount; i++)
threads.Add(new Thread(RunThread));
foreach (var thread in threads)
thread.Start();
foreach (var thread in threads)
thread.Join();
}
static void RunThread()
{
var connection = TryGetConnection();
while (connection == null)
{
connection = TryGetConnection();
}
}
static RedisConnection TryGetConnection()
{
var connection = currentConnection;
if ((connection != null) && (connection.State == RedisConnectionBase.ConnectionState.Open))
return connection;
lock (syncRoot)
{
if ((currentConnection != null) && (currentConnection.State == RedisConnectionBase.ConnectionState.Open))
return currentConnection;
if ((connectionTask != null) && connectionTask.IsCompleted)
connectionTask = null;
if (connectionTask == null)
{
if ((currentConnection != null) && (currentConnection.State == RedisConnectionBase.ConnectionState.Closed))
{
currentConnection.Dispose();
currentConnection = null;
}
if (currentConnection == null)
{
currentConnection = new RedisConnection(
serverAddress,
serverPort,
ioTimeout: (int) operationTimeout.TotalMilliseconds,
syncTimeout: (int) operationTimeout.TotalMilliseconds);
}
if (currentConnection.State == RedisConnectionBase.ConnectionState.New)
currentConnection.Open();
}
}
return null;
}

Let's look; we have a loop here:
var connection = TryGetConnection();
while (connection == null)
{
connection = TryGetConnection();
}
it is not clear to me that TryGetConnection is correctly handling all scenarios ("opening", etc), but frankly, it is a moot point : if you are going to do a tight loop until you get a connection, you might as well simplify significantly. The first thing you could do would be to wait on the task (with a timeout, obviously), rather than using a hot loop. Generalizing:
var task = connection.Open();
connection.Wait(task);
The Wait in the above uses the connection's specified timeout, and does some work to simplify exceptions for you.
However, in this specific case, you could probably just use something like:
var connection = TryGetConnection();
// no loop here
with:
static RedisConnection TryGetConnection()
{
var connection = currentConnection;
if ((connection != null) && (connection.State == RedisConnectionBase.ConnectionState.Open))
return connection;
lock (syncRoot)
{ // double-checked
if ((connection != null) && (connection.State == RedisConnectionBase.ConnectionState.Open))
return connection;
connection = ConnectionUtils.Connect(config);
return connection;
}
}
where config is a composite of the values; basically something like:
myserver:6389,syncTimeout=1000
This configuration string can also be more complex, including multiple redis servers (master/slave etc), a service-name (for use with sentinel), a client-name (for use with client list), etc.
I suspect some of the complexity in your method is leading to some extra looping at the moment. See if it is any more reliable with the above.

Related

Cloud Dataflow - how does Dataflow do parallelism?

My question is, behind the scene, for element-wise Beam DoFn (ParDo), how does the Cloud Dataflow parallel workload? For example, in my ParDO, I send out one http request to an external server for one element. And I use 30 workers, each has 4vCPU.
Does that mean on each worker, there will be 4 threads at maximum?
Does that mean from each worker, only 4 http connections are necessary or can be established if I keep them alive to get the best performance?
How can I adjust the level of parallelism other than using more cores or more workers?
with my current setting (30*4vCPU worker), I can establish around 120 http connections on the http server. But both server and worker has very low resource usage. basically I want to make them work much harder by sending out more requests out per second. What should I do...
Code Snippet to illustrate my work:
public class NewCallServerDoFn extends DoFn<PreparedRequest,KV<PreparedRequest,String>> {
private static final Logger Logger = LoggerFactory.getLogger(ProcessReponseDoFn.class);
private static PoolingHttpClientConnectionManager _ConnManager = null;
private static CloseableHttpClient _HttpClient = null;
private static HttpRequestRetryHandler _RetryHandler = null;
private static String[] _MapServers = MapServerBatchBeamApplication.CONFIG.getString("mapserver.client.config.server_host").split(",");
#Setup
public void setupHttpClient(){
Logger.info("Setting up HttpClient");
//Question: the value of maxConnection below is actually 10, but with 30 worker machines, I can only see 115 TCP connections established on the server side. So this setting doesn't really take effect as I expected.....
int maxConnection = MapServerBatchBeamApplication.CONFIG.getInt("mapserver.client.config.max_connection");
int timeout = MapServerBatchBeamApplication.CONFIG.getInt("mapserver.client.config.timeout");
_ConnManager = new PoolingHttpClientConnectionManager();
for (String mapServer : _MapServers) {
HttpHost serverHost = new HttpHost(mapServer,80);
_ConnManager.setMaxPerRoute(new HttpRoute(serverHost),maxConnection);
}
// config timeout
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.setSocketTimeout(timeout).build();
// config retry
_RetryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(
IOException exception,
int executionCount,
HttpContext context) {
Logger.info(exception.toString());
Logger.info("try request: " + executionCount);
if (executionCount >= 5) {
// Do not retry if over max retry count
return false;
}
if (exception instanceof InterruptedIOException) {
// Timeout
return false;
}
if (exception instanceof UnknownHostException) {
// Unknown host
return false;
}
if (exception instanceof ConnectTimeoutException) {
// Connection refused
return false;
}
if (exception instanceof SSLException) {
// SSL handshake exception
return false;
}
return true;
}
};
_HttpClient = HttpClients.custom()
.setConnectionManager(_ConnManager)
.setDefaultRequestConfig(requestConfig)
.setRetryHandler(_RetryHandler)
.build();
Logger.info("Setting up HttpClient is done.");
}
#Teardown
public void tearDown(){
Logger.info("Tearing down HttpClient and Connection Manager.");
try {
_HttpClient.close();
_ConnManager.close();
}catch (Exception e){
Logger.warn(e.toString());
}
Logger.info("HttpClient and Connection Manager have been teared down.");
}
#ProcessElement
public void processElement(ProcessContext c) {
PreparedRequest request = c.element();
if(request == null)
return;
String response="{\"my_error\":\"failed to get response from map server with retries\"}";
String chosenServer = _MapServers[request.getHardwareId() % _MapServers.length];
String parameter;
try {
parameter = URLEncoder.encode(request.getRequest(),"UTF-8");
} catch (UnsupportedEncodingException e) {
Logger.error(e.toString());
return;
}
StringBuilder sb = new StringBuilder().append(MapServerBatchBeamApplication.CONFIG.getString("mapserver.client.config.api_path"))
.append("?coordinates=")
.append(parameter);
HttpGet getRequest = new HttpGet(sb.toString());
HttpHost host = new HttpHost(chosenServer,80,"http");
CloseableHttpResponse httpRes;
try {
httpRes = _HttpClient.execute(host,getRequest);
HttpEntity entity = httpRes.getEntity();
if(entity != null){
try
{
response = EntityUtils.toString(entity);
}finally{
EntityUtils.consume(entity);
httpRes.close();
}
}
}catch(Exception e){
Logger.warn("failed by get response from map server with retries for " + request.getRequest());
}
c.output(KV.of(request, response));
}
}
Yes, based on this answer.
No, you can establish more connections. Based on my answer, you can use a async http client to have more concurrent requests. As this answer also describes, you need to collect the results from these asynchronous calls and output it synchronously in any #ProcessElement or #FinishBundle.
See 2.
Since your resource usage is low, it indicates that the worker spends most of its time waiting for a response. I think with the described approach above, you can utilize your resources far better and you can achieve the same performance with far less workers.

detecting connection lost in SignalR from client side

I am connecting a simple application to a server that hosts my web-pplication. My web-application uses SignalR 2. Everything is going smooth and my little application can sync with the web-application and receives messages sent from it. But, when the web-page is updated or the server restarts and it loses its connections, the application cannot understand that the connection is lost from server. The following is my codes:
// initializing connection
HubConnection connection;
IHubProxy hub;
connection = new HubConnection(serverAddress);
hub = connection.CreateHubProxy("MyPanel");
hub.On<string>("ReciveText", (msg) => recieveFromServer(msg));
A thread checks the connection every 1 minutes, but every time it checks, the state of the connection is “Connected” while the connection from server side is lost. Is there anything that I am missing here?
if (connection.State == ConnectionState.Disconnected)
{
// try to reconnect to server or do something
}
You can try something like that :
Comes from signalR official examples.
connection = new HubConnection(serverAddress);
connection.Closed += Connection_Closed;
/// <summary>
/// If the server is stopped, the connection will time out after 30 seconds
/// the default, and the `Closed` event will fire.
/// </summary>
void Connection_Closed()
{
//do something
}
You can use StateChanged event too like this :
connection.StateChanged += Connection_StateChanged;
private void Connection_StateChanged(StateChange obj)
{
MessageBox.Show(obj.NewState.ToString());
}
EDIT
You can try to reconnect every 15 secs with something like that :
private void Connection_StateChanged(StateChange obj)
{
if (obj.NewState == ConnectionState.Disconnected)
{
var current = DateTime.Now.TimeOfDay;
SetTimer(current.Add(TimeSpan.FromSeconds(30)), TimeSpan.FromSeconds(10), StartCon);
}
else
{
if (_timer != null)
_timer.Dispose();
}
}
private async Task StartCon()
{
await Connection.Start();
}
private Timer _timer;
private void SetTimer(TimeSpan starTime, TimeSpan every, Func<Task> action)
{
var current = DateTime.Now;
var timeToGo = starTime - current.TimeOfDay;
if (timeToGo < TimeSpan.Zero)
{
return;
}
_timer = new Timer(x =>
{
action.Invoke();
}, null, timeToGo, every);
}

Network Connection Failed after 10 minutes on blackberry

I've implemented timer task on background application.
I've collected current lat and long. and send to server each 30 seconds.
I've used below code to send the information to server. It sends successfully..
My problem is, after i've checked 10 minutes, I'm unable to send. it throws a No Network error. I've checked browser too but no network.
If reset the device, its working again well. But the same problem occurs after 5 or 10 mins.
How to resolve this?
My code is,
try
{
StreamConnection connection = (StreamConnection) Connector.open(url+suffix);
((HttpConnection) connection).setRequestMethod(HttpConnection.GET);
int responseCode = ((HttpConnection) connection).getResponseCode();
if (responseCode != HttpConnection.HTTP_OK) {
showDialog("Unexpected response code :"+ responseCode);
connection.close();
return;
}
((HttpConnection) connection).getHeaderField("Content-type");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream responseData = connection.openInputStream();
byte[] buffer = new byte[1000];
int bytesRead = responseData.read(buffer);
while (bytesRead > 0) {
baos.write(buffer, 0, bytesRead);
bytesRead = responseData.read(buffer);
}
baos.close();
connection.close();
String s = new String(baos.toByteArray());
showDialog("Responce from server "+s);
}
catch (IOException e)
{
}
Usually, when you have some problem where it works a few times, and then stops working, and you need to reset the device, you've done something that has used up all available resources, without releasing them when you're done.
When performing repeated network operations, you should clean up your streams and connections after each use.
Normally, the proper way to write network code is to declare network variables outside a try block, assign and use them inside the try, while catching any IOExceptions thrown. Then, you use a finally block to clean up your resources, no matter whether the code finished successfully or not.
I'll also note that when debugging network problems, you don't want to have a catch() handler that simply traps exceptions and does nothing with them. Print out a message to the console (for testing) or log the error to a file.
Finally, I can't see your showDialog() method, but if it's displaying a UI to the user/tester, you need to do that on the UI thread. But, the network code that you show above should be run on a background thread to keep the UI responsive. So, inside showDialog(), just make sure you use code to modify the UI on the UI thread.
So, a better implementation might be this:
private void requestFromServer() {
StreamConnection connection = null;
ByteArrayOutputStream baos = null;
InputStream responseData = null;
try
{
connection = (StreamConnection) Connector.open(url+suffix);
((HttpConnection) connection).setRequestMethod(HttpConnection.GET);
int responseCode = ((HttpConnection) connection).getResponseCode();
if (responseCode != HttpConnection.HTTP_OK) {
showDialog("Unexpected response code :"+ responseCode);
return;
}
((HttpConnection) connection).getHeaderField("Content-type");
baos = new ByteArrayOutputStream();
responseData = connection.openInputStream();
byte[] buffer = new byte[1000];
int bytesRead = responseData.read(buffer);
while (bytesRead > 0) {
baos.write(buffer, 0, bytesRead);
bytesRead = responseData.read(buffer);
}
String s = new String(baos.toByteArray());
showDialog("Responce from server "+s);
}
catch (IOException e)
{
System.out.println("Network error: " + e.getMessage());
}
finally
{
try {
if (connection != null) {
connection.close();
}
if (baos != null) {
baos.close();
}
if (responseData != null) {
responseData.close();
}
} catch (IOException e) {
// nothing to do here
}
}
}
private void showDialog(final String msg) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(msg);
}
});
}

XMPP strophe Connection attach process failed

I'm able to create a XMPP connection on page load. However whenever I move to another pages, I want to use the same connection to remove recurring notifications in client. I've used following code.
$(document).bind('connect', function (ev, data) {
var jid = $.jStorage.get('JID', null);
var sid = $.jStorage.get('SID', null);
var rid = $.jStorage.get('RID', null);
if ((jid != null) && (sid != null) && (rid != null)) {
var conn = new Strophe.Connection("http://localhost:5280/xmpp-httpbind");
conn.attach(jid, sid, rid, function () {
alert('Connection attach success.');
Gab.connection = conn;
});
}
else {
var conn = new Strophe.Connection("http://localhost:5280/xmpp-httpbind");
conn.connect(data.jid, data.password, function (status) {
if (status === Strophe.Status.CONNECTED) {
$(document).trigger('connected');
} else if (status === Strophe.Status.DISCONNECTED) {
$(document).trigger('disconnected');
}
});
Gab.connection = conn;
}
});
And in unload:
$(window).unload(function () {
if (Gab.connection != null) {
Gab.connection.pause();
$.jStorage.set('JID', Gab.connection.jid);
$.jStorage.set('SID', Gab.connection.sid);
$.jStorage.set('RID', Gab.connection.rid);
} else {
$.jStorage.flush();
}
// Gab.connection = null;
alert('paused/disconnected');
})
It attaches to connection, however as soon as it attaches, it says (POST http://localhost:5280/xmpp-httpbind 404 Not Found 36ms) in Firebug console. Any ideas?
Thanks in advance.
You should not trust unload. Instead store/update your RID on every cb from the xmpp server. Make sure your RID is getting incremented on each call as well.
Make sure to inspect the body of the message. Some XMPP servers return HTTP 404 on terminate.

NullPointerException with Texlipse and Miktex 2.9

When using Texlipse together with Miktex 2.9 on my Windows machine, the system throws a NullPointerExcpetion each time the document is compiled.
The problem disappeared after I have updated the Miktex 2.9 distribution using the Update manager. Hope this helps others who have the same problem.
Regards,
Pwndrian
To me it happens too.
This is a workaround I did, however I think that it is not quite optimal solution.
I saw that there is a bug opened http://sourceforge.net/tracker/?func=detail&aid=3306779&group_id=133306&atid=726818.
There is the class net.sourceforge.texlipse.builder.TExlipseBuilder, I made the following changes to overcome this problem(Please note the differences in both functions). The problem is that in TExlipsePlugin in the function getCurrentProject the actEditor is null since there is no active editor when importing projects or when pressing on clean while no editor is open.
#Override
protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
throws CoreException {
BuilderRegistry.clearConsole();
IWorkbenchPage page = TexlipsePlugin.getCurrentWorkbenchPage();
IEditorPart actEditor = null;
if (page.isEditorAreaVisible()
&& page.getActiveEditor() != null) {
actEditor = page.getActiveEditor();
}
if ( actEditor == null )
return null;
if (isUpToDate(getProject()))
return null;
Object s = TexlipseProperties.getProjectProperty(getProject(), TexlipseProperties.PARTIAL_BUILD_PROPERTY);
if (s != null) {
partialBuild(monitor);
} else {
buildFile(null, monitor);
}
return null;
}
/**
* Clean the temporary files.
*
* #see IncrementalProjectBuilder.clean
*/
#Override
protected void clean(IProgressMonitor monitor) throws CoreException {
IProject project = getProject();
BuilderRegistry.clearConsole();
IWorkbenchPage page = TexlipsePlugin.getCurrentWorkbenchPage();
IEditorPart actEditor = null;
if (page.isEditorAreaVisible()
&& page.getActiveEditor() != null) {
actEditor = page.getActiveEditor();
}
if ( actEditor == null )
return;
// reset session variables
TexlipseProperties.setSessionProperty(project, TexlipseProperties.SESSION_LATEX_RERUN, null);
TexlipseProperties.setSessionProperty(project, TexlipseProperties.SESSION_BIBTEX_RERUN, null);
TexlipseProperties.setSessionProperty(project, TexlipseProperties.BIBFILES_CHANGED, null);
// check main file
String mainFile = TexlipseProperties.getProjectProperty(project, TexlipseProperties.MAINFILE_PROPERTY);
if (mainFile == null || mainFile.length() == 0) {
// main tex file not set -> nothing builded -> nothing to clean
return;
}
cleanTempDir(monitor, project);
cleanOutput(monitor, project);
monitor.subTask(TexlipsePlugin.getResourceString("builderSubTaskCleanMarkers"));
this.deleteMarkers(project);
project.refreshLocal(IProject.DEPTH_INFINITE, monitor);
monitor.done();
}

Resources