mirror of
https://github.com/metosin/reitit.git
synced 2025-12-17 00:11:11 +00:00
Calfpath-data
This commit is contained in:
parent
ffc6ba8053
commit
4c722d628e
3 changed files with 78 additions and 10 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 36 KiB |
|
|
@ -1,6 +1,6 @@
|
||||||
# Performance
|
# Performance
|
||||||
|
|
||||||
Reitit tries to be both great in features and be really, really fast. Originally the routing was ported from [Pedestal](http://pedestal.io/), but has been mostly rewritten.
|
Besides having great features, the goal of reitit is to be really, really fast. The routing was originally exported from Pedestal, but since rewritten.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -63,13 +63,13 @@ The routing sample taken from [bide](https://github.com/funcool/bide) README:
|
||||||
(dotimes [_ 1000]
|
(dotimes [_ 1000]
|
||||||
(r/match-by-path routes "/auth/login")))
|
(r/match-by-path routes "/auth/login")))
|
||||||
|
|
||||||
;; Execution time mean (per 1000): 530 µs -> 1.9M ops/sec
|
;; Execution time mean (per 1000): 315 µs -> 3.2M ops/sec
|
||||||
(cc/quick-bench
|
(cc/quick-bench
|
||||||
(dotimes [_ 1000]
|
(dotimes [_ 1000]
|
||||||
(r/match-by-path routes "/workspace/1/1")))
|
(r/match-by-path routes "/workspace/1/1")))
|
||||||
```
|
```
|
||||||
|
|
||||||
Based on the [perf tests](https://github.com/metosin/reitit/tree/master/perf-test/clj/reitit/perf/bide_perf_test.clj), the first (static path) lookup is 300-500x faster and the second (wildcard path) lookup is 4-24x faster that the other tested routing libs (Ataraxy, Bidi, Compojure and Pedestal).
|
Based on the [perf tests](https://github.com/metosin/reitit/tree/master/perf-test/clj/reitit/perf/bide_perf_test.clj), the first (static path) lookup is 300-500x faster and the second (wildcard path) lookup is 6-40x faster that the other tested routing libs (Ataraxy, Bidi, Compojure and Pedestal).
|
||||||
|
|
||||||
But, the example is too simple for any real benchmark. Also, some of the libraries always match on the `:request-method` too and by doing so, do more work than just match by path. Compojure does most work also by invoking the handler.
|
But, the example is too simple for any real benchmark. Also, some of the libraries always match on the `:request-method` too and by doing so, do more work than just match by path. Compojure does most work also by invoking the handler.
|
||||||
|
|
||||||
|
|
@ -79,7 +79,7 @@ So, we need to test something more realistic.
|
||||||
|
|
||||||
To get better view on the real life routing performance, there is [test](https://github.com/metosin/reitit/blob/master/perf-test/clj/reitit/opensensors_perf_test.clj) of a mid-size rest(ish) http api with 50+ routes, having a lot of path parameters. The route definitions are pulled off from the [OpenSensors](https://opensensors.io/) swagger definitions.
|
To get better view on the real life routing performance, there is [test](https://github.com/metosin/reitit/blob/master/perf-test/clj/reitit/opensensors_perf_test.clj) of a mid-size rest(ish) http api with 50+ routes, having a lot of path parameters. The route definitions are pulled off from the [OpenSensors](https://opensensors.io/) swagger definitions.
|
||||||
|
|
||||||
Thanks to the snappy new [segment-tree](https://github.com/metosin/reitit/blob/master/modules/reitit-core/src/reitit/segment.cljc) algorithm, `reitit-ring` is fastest here. Pedestal is also fast with it's [prefix-tree](https://en.wikipedia.org/wiki/Radix_tree) implementation.
|
Thanks to the snappy [SegmentTrie](https://github.com/metosin/reitit/blob/master/modules/reitit-core/java-src/reitit/SegmentTrie.java) (a modification of [Radix tree](https://en.wikipedia.org/wiki/Radix_tree)), `reitit-ring` is fastest here. [Calfpath](https://github.com/kumarshantanu/calfpath) and [Pedestal](https://github.com/pedestal/pedestal) are also quite fast.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
@ -99,13 +99,14 @@ The reitit routing perf is measured to get an internal baseline to optimize agai
|
||||||
|
|
||||||
### Looking out of the box
|
### Looking out of the box
|
||||||
|
|
||||||
A quick poke to [routers in Go](https://github.com/julienschmidt/go-http-routing-benchmark) indicates that the reitit is only few times slower than the fastest routers in Go. Which is really awesome (if true).
|
A quick poke to [routers in Go](https://github.com/julienschmidt/go-http-routing-benchmark) indicates that the reitit is only few times slower than the fastest routers in Go. Which is kinda awesome.
|
||||||
|
|
||||||
### Performance tips
|
### Performance tips
|
||||||
|
|
||||||
Few things that have an effect on performance:
|
Few things that have an effect on performance:
|
||||||
|
|
||||||
* Wildcard-routes are an order of magnitude slower than static routes
|
* Wildcard-routes are an order of magnitude slower than static routes
|
||||||
* It's ok to mix non-wildcard and wildcard routes in a same routing tree as long as you don't disable the [conflict resolution](basics/route_conflicts.md) => if no conflicting routes are found, a `:mixed-router` can be created, which internally has a fast static path router and a separate wildcard-router. So, the static paths are still fast.
|
* Conflicting routes are served with LinearRouter, which is the slowest implementation.
|
||||||
|
* It's ok to mix non-wildcard, wildcard or even conflicting routes in a same routing tree. Reitit will create an hierarchy of routers to serve all the routes with best possible implementation.
|
||||||
* Move computation from request processing time into creation time, using by compiling [middleware](ring/compiling_middleware.md) & [route data](advanced/configuring_routers.md).
|
* Move computation from request processing time into creation time, using by compiling [middleware](ring/compiling_middleware.md) & [route data](advanced/configuring_routers.md).
|
||||||
* Unmounted middleware (or interceptor) is infinitely faster than a mounted one effectively doing nothing.
|
* Unmounted middleware (or interceptor) is infinitely faster than a mounted one effectively doing nothing.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
[ataraxy.core :as ataraxy]
|
[ataraxy.core :as ataraxy]
|
||||||
[compojure.core :refer [routes context ANY]]
|
[compojure.core :refer [routes context ANY]]
|
||||||
[calfpath.core :as cp]
|
[calfpath.core :as cp]
|
||||||
|
[calfpath.route :as cr]
|
||||||
|
|
||||||
[io.pedestal.http.route.definition.table :as table]
|
[io.pedestal.http.route.definition.table :as table]
|
||||||
[io.pedestal.http.route.map-tree :as map-tree]
|
[io.pedestal.http.route.map-tree :as map-tree]
|
||||||
|
|
@ -367,7 +368,7 @@
|
||||||
["/v1/users/:user-id/bookmarks" :get handler :route-name :test/route56]
|
["/v1/users/:user-id/bookmarks" :get handler :route-name :test/route56]
|
||||||
["/v1/orgs/:org-id/topics" :get handler :route-name :test/route57]])))
|
["/v1/orgs/:org-id/topics" :get handler :route-name :test/route57]])))
|
||||||
|
|
||||||
(defn opensensors-calfpath-handler [request]
|
(defn opensensors-calfpath-macro-handler [request]
|
||||||
(cp/->uri
|
(cp/->uri
|
||||||
request
|
request
|
||||||
"/v2/whoami" [] (cp/->get request (handler request) nil)
|
"/v2/whoami" [] (cp/->get request (handler request) nil)
|
||||||
|
|
@ -429,6 +430,68 @@
|
||||||
"/v1/orgs/:org-id/topics" [] (cp/->get request (handler request) nil)
|
"/v1/orgs/:org-id/topics" [] (cp/->get request (handler request) nil)
|
||||||
nil))
|
nil))
|
||||||
|
|
||||||
|
(def opensensors-calfpath-routes
|
||||||
|
[{:uri "/v2/whoami" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/users/:user-id/datasets" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/public/projects/:project-id/datasets" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/public/topics/:topic" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/orgs/:org-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/search/topics/:term" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/invitations" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/devices/:batch/:type" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/topics" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/bookmarks/followers" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/datasets/:dataset-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/usage-stats" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/devices/:client-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/messages/user/:user-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/devices" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/public/users/:user-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/errors" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/public/orgs/:org-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/invitations" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/public/messages/dataset/bulk" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/devices/bulk" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/device-errors" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/login" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/usage-stats" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/users/:user-id/devices" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/claim-device/:client-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/public/projects/:project-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/public/datasets/:dataset-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/users/:user-id/topics/bulk" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/messages/device/:client-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/owned-orgs" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/topics/:topic" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/bookmark/:topic" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/members/:user-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/devices/:client-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/devices" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/members" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/members/invitation-data/:user-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/orgs/:org-id/topics" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/whoami" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/api-key" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/schemas" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/users/:user-id/topics" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/confirm-membership/:token" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/topics/:topic" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/messages/topic/:topic" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/devices/:client-id/reset-password" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/topics" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/login" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/orgs" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v2/public/messages/dataset/:dataset-id" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/topics" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/users/:user-id/bookmarks" :nested [{:method :get, :handler handler}]}
|
||||||
|
{:uri "/v1/orgs/:org-id/topics" :nested [{:method :get, :handler handler}]}])
|
||||||
|
|
||||||
|
(def opensensors-calfpath-data-handler
|
||||||
|
(partial cr/dispatch (cr/compile-routes opensensors-calfpath-routes {:show-uris-400? false})))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(pedestal/find-route
|
(pedestal/find-route
|
||||||
(map-tree/router
|
(map-tree/router
|
||||||
|
|
@ -487,7 +550,8 @@
|
||||||
reitit-ring-f (ring/ring-handler (ring/router opensensors-routes))
|
reitit-ring-f (ring/ring-handler (ring/router opensensors-routes))
|
||||||
reitit-ring-fast-f (ring/ring-handler (ring/router opensensors-routes) nil {:inject-router? false, :inject-match? false})
|
reitit-ring-fast-f (ring/ring-handler (ring/router opensensors-routes) nil {:inject-router? false, :inject-match? false})
|
||||||
bidi-f #(bidi/match-route opensensors-bidi-routes (:uri %))
|
bidi-f #(bidi/match-route opensensors-bidi-routes (:uri %))
|
||||||
calfpath-f opensensors-calfpath-handler
|
calfpath-macros-f opensensors-calfpath-macro-handler
|
||||||
|
calfpath-data-f opensensors-calfpath-data-handler
|
||||||
ataraxy-f (partial ataraxy/matches opensensors-ataraxy-routes)
|
ataraxy-f (partial ataraxy/matches opensensors-ataraxy-routes)
|
||||||
compojure-f opensensors-compojure-routes
|
compojure-f opensensors-compojure-routes
|
||||||
pedestal-f (partial pedestal/find-route opensensors-pedestal-routes)
|
pedestal-f (partial pedestal/find-route opensensors-pedestal-routes)
|
||||||
|
|
@ -513,11 +577,14 @@
|
||||||
;; 385ns (java-segment-router, no injects)
|
;; 385ns (java-segment-router, no injects)
|
||||||
(b! "reitit-ring-fast" reitit-ring-fast-f)
|
(b! "reitit-ring-fast" reitit-ring-fast-f)
|
||||||
|
|
||||||
|
;; 2258ns
|
||||||
|
(b! "calfpath-data" calfpath-data-f)
|
||||||
|
|
||||||
;; 2821ns
|
;; 2821ns
|
||||||
(b! "pedestal" pedestal-f)
|
(b! "pedestal" pedestal-f)
|
||||||
|
|
||||||
;; 4364ns (macros)
|
;; 4364ns
|
||||||
(b! "calfpath" calfpath-f)
|
(b! "calfpath-macros" calfpath-macros-f)
|
||||||
|
|
||||||
;; 11615ns
|
;; 11615ns
|
||||||
(b! "compojure" compojure-f)
|
(b! "compojure" compojure-f)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue