Hi,
I'm building a web service with Actix and I'm having trouble to figure out what is the most efficient between serbing the same data from a static file with actix_files::Files or from a REST route with actix_web::get("/url") -> HttpResponse.
Currently I load data at server start, then I build some html views that I keep in memory as Strings and serve through a REST GET web service. But I wonder if it would be a better idea to write actual html files and serve them as static files.
My observation seems to show that static files are served faster, but I'm a little confused about that because I thought that serving static files require to do an IO operation for each request, so I would believe that serving data from memory through a REST service would be faster.
I can't know where the truth is. I'm curious about any suggestion.
Im not really familiar with actix files api, but i suppose your file need to be served in response to GET request no matter what you choose, since thats what the browser will send.
Secondly, actix is a fast webserver - so no matter what you choose i dont think it will be slow due to the server. Ask yourself if your usecase really require this level optimization and tryout and profile a minimal implementation of both approaches? If you dont need it - choose the one that is easy to understand and maintain
Lastly I dont think serving a rendered html page will be very RESTish, so if that's a critera, perhaps consider using a frontend framework to render the page and only send the actual data?
Like you said, I don't know if I really "need" to consider that optimisation level. My question is maybe be more for curiosity sake.
Currently I load data from json at server start and I build a full website from it, html documents etc.
As I get everything built in memory at some point, and again like you said, pages will be served as responses to GET requests anyway, it seemed to me more logical to just keep in memory my Strings and serve them implementing a GET Responder service, because write them in a static memory location and then re-read them for each request with the actix Files facility looked like an unnecessary extra operation.
But, when I have a look to the brower's network console, I can see that,with cache disabled, the GET request to load my html document ( served by the actix_web::get service) is benchmarked around 60ms, while the static files like js css etc, are aroud 2ms, and in all cases payload size is around 500 bytes. That's a big difference and I can't explain it with my current knowledge...
Iteresting. Im afraid I dont got any simple answer for you. Profiling and timing the rendering logic and data lookup functions could perhaps give some clues to what it is thats taking time, and if its dependant on your implementation or the framework code.
I didn't think of the OS cache, that could be the "why".
The service that serves the html page is written like this
#[get("/{pth:.*}")]
pub async fn page(
website: web::Data<std::sync::Mutex<WebSite>>,
pth: web::Path<PathBuf>,
) -> impl Responder {
let website = website.lock().unwrap();
let pth = pth.into_inner();
match website.get_page_by_url(&pth) {
Some(page) => HttpResponse::Ok().body(page.html.to_string()),
None => HttpResponse::NotFound().body(format!("Not found {}", pth.display())),
}
}
And the Website struct current implementation is as follows (sorry I copied the whole module here but I guess cut it in part wouldn't make much sense...
The Mutex might explain part of the difference too. You're also doing a couple allocations that I don't think the files version needs, though that shouldn't matter TOO much
The reason of having chosen a Mutex based implementation is because I want this package to be a pure standalone binary, so no database. And it's basically a CMS so the website structure is fully mutable...
Anyway yes I guess that the addition of those little operations make that difference.
Also I'm not very experienced and I guess this could be done better .
If you're rendering the templates before the server starts it should be possible to just use an Arc and not a Mutex, though other things might make that harder.
At a minimum you probably want RwLock instead of Mutex, since multiple requests could need to retrieve a page at the same time. As long as they don't need to modify the pages in the HashMap there's no reason for them to need exclusive access.
Well the Website can actually be modified during the life of the server running session (so the pages ressources would be rebuilt at this moment), so I think I can't handle it it with just an Arc, and I didn't succeed in give a kind of readonly access to the website pages when mutation is not in question.