RavenDB Aggresive caching doesn't seem to do anything different - performance

Inside the following block
using (DocumentSession.Advanced.DocumentStore.AggressivelyCacheFor(TimeSpan.FromMinutes(1)))
{
return session.Query<Camera, Camera_Facets().Where(...).ToFacets("facets/CameraFacets")
}
I am executing a query and asking for facets. When I see the call on the raven server console, it takes 2.5 seconds, but when I run the same query again and again, it still takes the exact same time.
Now how is this meant to be fast? when it returns in roughly the exact same time every time. Am I missing something here. I am using build 499, and running client server mode, talking to raven on my local machine.
note: i am running the query on my data store for my domain, the camera code above is shown for reference purpose.

Faceted queries and aggressive caching currently don't work together. Faceted queries are a new feature and as yet they haven't been made to work with aggressive caching.
Note that regular queries work with aggressive caching just fine, it's only faceted queries that have this issue.

Related

Elasticsearch high level REST client - Indexing has latency

we have started using the high level REST client finally, to ease the development of queries from backend engineering perspective. For indexing, we are using the client.update(request, RequestOptions.DEFAULT) so that new documents will be created and existing ones modified.
The issue that we are seeing is, the indexing is delayed, almost by 5 minutes. I see that they use async http calls internally. But that should not take so long, I looked for some timing options inside the library, didn't find anything. Am I missing anything or the official documentation is missing for this?
Since refresh_interval: 1 in your index settings, it means it is never refreshed unless you do it manually, which is why you don't see the data just after it's been updated.
You have three options here:
A. You can call the _update endpoint with the refresh=true (or refresh=wait_for) parameter to make sure that the index is refreshed just after your update.
B. You can simply set refresh_interval: 1s (or any other duration that makes sense for you) in your index settings, to make sure the index is automatically refreshed on a regular basis.
C. You can explicitly call index/_refresh on your index to refresh it whenever you think is appropriate.
Option B is the one that usually makes sense in most use cases.
Several reference on using the refresh wait_for but I had a hard time finding what exactly needed to be done in the rest high level client.
For all of you that are searching this answer:
IndexRequest request = new IndexRequest(index, DOC_TYPE, id);
request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);

GraphQL Asynchronous query results

I'm trying to implement a batch query interface with GraphQL. I can get a request to work synchronously without issue, but I'm not sure how to approach making the result asynchronous. Basically, I want to be able to kick off the query and return a pointer of sorts to where the results will eventually be when the query is done. I'd like to do this because the queries can sometimes take quite a while.
In REST, this is trivial. You return a 202 and return a Location header pointing to where the client can go to fetch the result. GraphQL as a specification does not seem to have this notion; it appears to always want requests to be handled synchronously.
Is there any convention for doing things like this in GraphQL? I very much like the query specification but I'd prefer to not leave the client HTTP connection open for up to a few minutes while a large query is executed on the backend. If anything happens to kill that connection the entire query would need to be retried, even if the results themselves are durable.
What you're trying to do is not solved easily in a spec-compliant way. Apollo introduced the idea of a #defer directive that does pretty much what you're looking for but it's still an experimental feature. I believe Relay Modern is trying to do something similar.
The idea is effectively the same -- the client uses a directive to mark a field or fragment as deferrable. The server resolves the request but leaves the deferred field null. It then sends one or more patches to the client with the deferred data. The client is able to apply the initial request and the patches separately to its cache, triggering the appropriate UI changes each time as usual.
I was working on a similar issue recently. My use case was to submit a job to create a report and provide the result back to the user. Creating a report takes couple of minutes which makes it an asynchronous operation. I created a mutation which submitted the job to the backend processing system and returned a job ID. Then I periodically poll the jobs field using a query to find out about the state of the job and eventually the results. As the result is a file, I return a link to a different endpoint where it can be downloaded (similar approach Github uses).
Polling for actual results is working as expected but I guess this might be better solved by subscriptions.

How do you prevent nested attack on GraphQL/Apollo server?

How do you prevent a nested attack against an Apollo server with a query such as:
{
authors {
firstName
posts {
title
author {
firstName
posts{
title
author {
firstName
posts {
title
[n author]
[n post]
}
}
}
}
}
}
}
In other words, how can you limit the number of recursions being submitted in a query? This could be a potential server vulnerability.
As of the time of writing, there isn't a built-in feature in GraphQL-JS or Apollo Server to handle this concern, but it's something that should definitely have a simple solution as GraphQL becomes more popular. This concern can be addressed with several approaches at several levels of the stack, and should also always be combined with rate limiting, so that people can't send too many queries to your server (this is a potential issue with REST as well).
I'll just list all of the different methods I can think of, and I'll try to keep this answer up to date as these solutions are implemented in various GraphQL servers. Some of them are quite simple, and some are more complex.
Query validation: In every GraphQL server, the first step to running a query is validation - this is where the server tries to determine if there are any serious errors in the query, so that we can avoid using actual server resources if we can find that there is some syntax error or invalid argument up front. GraphQL-JS comes with a selection of default rules that follow a format pretty similar to ESLint. Just like there is a rule to detect infinite cycles in fragments, one could write a validation rule to detect queries with too much nesting and reject them at the validation stage.
Query timeout: If it's not possible to detect that a query will be too resource-intensive statically (perhaps even shallow queries can be very expensive!), then we can simply add a timeout to the query execution. This has a few benefits: (1) it's a hard limit that's not too hard to reason about, and (2) this will also help with situations where one of the backends takes unreasonably long to respond. In many cases, a user of your app would prefer a missing field over waiting 10+ seconds to get a response.
Query whitelisting: This is probably the most involved method, but you could compile a list of allowed queries ahead of time, and check any incoming queries against that list. If your queries are totally static (you don't do any dynamic query generation on the client with something like Relay) this is the most reliable approach. You could use an automated tool to pull query strings out of your apps when they are deployed, so that in development you write whatever queries you want but in production only the ones you want are let through. Another benefit of this approach is that you can skip query validation entirely, since you know that all possible queries are valid already. For more benefits of static queries and whitelisting, read this post: https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a
Query cost limiting: (Added in an edit) Similar to query timeouts, you can assign a cost to different operations during query execution, for example a database query, and limit the total cost the client is able to use per query. This can be combined with limiting the maximum parallelism of a single query, so that you can prevent the client from sending something that initiates thousands of parallel requests to your backend.
(1) and (2) in particular are probably something every GraphQL server should have by default, especially since many new developers might not be aware of these concerns. (3) will only work for certain kinds of apps, but might be a good choice when there are very strict performance or security requirements.
To supplement point (4) in stubailo's answer, here are some Node.js implementations that impose cost and depth bounds on incoming GraphQL documents.
graphql-depth-limit
graphql-validation-complexity
graphql-query-complexity
These are custom rules that supplement the validation phase.
A variation on query whitelisting is query signing.
During the build process, each query is cryptographically signed using a secret which is shared with the server but not bundled with the client. Then at runtime the server can validate that a query is genuine.
The advantage over whitelisting is that writing queries in the client doesn't require any changes to the server. This is especially valuable if multiple clients access the same server (e.g. web, desktop and mobile apps).
Example
In development, you write your queries as usual against your dev server which allows unsigned queries.
Then in your client build step in CI, each query is tagged with its cryptographic signature. This signature is sent by the client as a header to the server when making the request, along with the full GraphQL query string.
Your staging and production servers are configured to require a signed queries. They calculate the signature of the query received in the same way as the CI server did during the build. If the signatures don't match then they don't process the query.
Limitations:
not suitable for public facing APIs since the secret must be shared with developers
clients cannot dynamically build a GraphQL query at runtime using string interpolation, but I've never had a need for this and it is discouraged
For the Query cost limiting you could use graphql-cost-analysis
This is a validation rule which parses the query before executing it. In your GraphQL server you just have to assign a cost configuration for each field of your Schema Type Map you want.
Don't miss graphql-rate-limit 👌a GraphQL directive to add basic but granular rate limiting to your Queries or Mutations.

How can I see what is happening under the covers when an Elasticsearch query is executed?

For Elasticsearch 1.7.5 (or earlier), how can I see what steps Elasticsearch takes to handle my queries?
I attempted to turn debugging on by setting es.logger.level=DEBUG, but while that produced a fair amount of information at startup and shutdown, it doesn't produce anything when queries are executed. Looking at the source code, apparently most of the debug logging for searches is just for exceptional situations.
I am trying to understand query performance. We're seeing Elasticsearch do way more I/O than we expected, on a very simple term query on an unanalyzed field.
With ES 1.7.5 and earlier versions, you can use the ?explain=true URL parameter when sending your query and you'll get some more insights into how the score was computed.
Also starting with ES 2.2, there is a new Profile API which you can use to get more insights into timing information while the different query components are being executed. Simply add "profile": true to the search body payload and you're good to go.

How to deal with Elasticsearch index delay

Here's my scenario:
I have a page that contains a list of users. I create a new user through my web interface and save it to the server. The server indexes the document in elasticsearch and returns successfully. I am then redirected to the list page which doesn't contain the new user because it can take up to 1-second for documents to become available for search in elasticsearch
Near real-time search in elasticsearch.
The elasticsearch guide says you can manually refresh the index, but says not to do it in production.
...don’t do a manual refresh every time you index a document in production; it will hurt your performance. Instead, your application needs to be aware of the near real-time nature of Elasticsearch and make allowances for it.
I'm wondering how other people get around this? I wish there was an event or something I could listen for that would tell me when the document was available for search but there doesn't appear to be anything like that. Simply waiting for 1-second is plausible but it seems like a bad idea because it presumably could take much less time than that.
Thanks!
Even though you can force ES to refresh itself, you've correctly noticed that it might hurt performance. One solution around this and what people often do (myself included) is to give an illusion of real-time. In the end, it's merely a UX challenge and not really a technical limitation.
When redirecting to the list of users, you could artificially include the new record that you've just created into the list of users as if that record had been returned by ES itself. Nothing prevents you from doing that. And by the time you decide to refresh the page, the new user record would be correctly returned by ES and no one cares where that record is coming from, all the user cares about at that moment is that he wants to see the new record that he's just created, simply because we're used to think sequentially.
Another way to achieve this is by reloading an empty user list skeleton and then via Ajax or some other asynchronous way, retrieve the list of users and display it.
Yet another way is to provide a visual hint/clue on the UI that something is happening in the background and that an update is to be expected very shortly.
In the end, it all boils down to not surprise users but to give them enough clues as to what has happened, what is happening and what they should still expect to happen.
UPDATE:
Just for completeness' sake, this answer predates ES5, which introduced a way to make sure that the indexing call would not return until the document is either visible when searching the index or return an error code. By using ?refresh=wait_for when indexing your data you can be certain that when ES responds, the new data will be indexed.
Elasticsearch 5 has an option to block an indexing request until the next refresh ocurred:
?refresh=wait_for
See: https://www.elastic.co/guide/en/elasticsearch/reference/5.0/docs-refresh.html#docs-refresh
Here is a fragment of code which is what I did in my Angular application to cope with this. In the component:
async doNewEntrySave() {
try {
const resp = await this.client.createRequest(this.doc).toPromise();
this.modeRefreshDelay = true;
setTimeout(() => {
this.modeRefreshDelay = false;
this.refreshPage();
}, 2500);
} catch (err) {
this.error.postError(err);
}
}
In the template:
<div *ngIf="modeRefreshDelay">
<h2>Waiting for update ...</h2>
</div>
I understand this is a quick-and-dirty solution but it illustrates how the user experience should work. Obviously it breaks if the real-world latency turns out to be more than 2.5 seconds. A fancier version would loop until the new record showed up in the page delay (with a limit of course).
Unless you completely redesign ElasticSearch you will always have some latency between the successful index operation and the time when that document shows up in search results.
Data should be available immediately after indexing is complete. Couple of general questions:
Have you checked CPU and RAM to determine whether you are taxing your ES cluster? If so, you may need to beef up your hardware config to account for it. ES loves RAM!
Are you using NAS (network-attached-storage) or virtualized storage like EBS? Elastic recommends not doing so because of the latency. If you can use DAS (direct-attached) and SSD, you'll be in much, much better shape.
To give you an AWS example, moving from m4.xlarge instances to r3.xlarge made HUGE performance improvements for us.

Resources