2017-11-01 07:29:38 +00:00
<!DOCTYPE HTML>
< html lang = "" >
< head >
< meta charset = "UTF-8" >
< meta content = "text/html; charset=utf-8" http-equiv = "Content-Type" >
< title > Performance · GitBook< / title >
< meta http-equiv = "X-UA-Compatible" content = "IE=edge" / >
< meta name = "description" content = "" >
< meta name = "generator" content = "GitBook 3.2.3" >
< link rel = "stylesheet" href = "gitbook/style.css" >
2018-09-03 15:58:24 +00:00
< link rel = "stylesheet" href = "gitbook/gitbook-plugin-hints/plugin-hints.css" >
2017-11-01 07:29:38 +00:00
< link rel = "stylesheet" href = "gitbook/gitbook-plugin-highlight/website.css" >
< link rel = "stylesheet" href = "gitbook/gitbook-plugin-search/search.css" >
< link rel = "stylesheet" href = "gitbook/gitbook-plugin-fontsettings/website.css" >
< meta name = "HandheldFriendly" content = "true" / >
< meta name = "viewport" content = "width=device-width, initial-scale=1, user-scalable=no" >
< meta name = "apple-mobile-web-app-capable" content = "yes" >
< meta name = "apple-mobile-web-app-status-bar-style" content = "black" >
< link rel = "apple-touch-icon-precomposed" sizes = "152x152" href = "gitbook/images/apple-touch-icon-precomposed-152.png" >
< link rel = "shortcut icon" href = "gitbook/images/favicon.ico" type = "image/x-icon" >
2018-09-03 15:58:24 +00:00
< link rel = "next" href = "development.html" / >
2017-11-27 06:15:59 +00:00
2017-11-01 07:29:38 +00:00
2018-09-03 15:58:24 +00:00
< link rel = "prev" href = "advanced/shared_routes.html" / >
2017-11-01 07:29:38 +00:00
< / head >
< body >
< div class = "book" >
< div class = "book-summary" >
< div id = "book-search-input" role = "search" >
< input type = "text" placeholder = "Type to search" / >
< / div >
< nav role = "navigation" >
< ul class = "summary" >
2018-09-03 15:58:24 +00:00
< li class = "header" > Introduction< / li >
2017-11-01 07:29:38 +00:00
< li class = "chapter " data-level = "1.1" data-path = "./" >
< a href = "./" >
Introduction
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "header" > Basics< / li >
< li class = "chapter " data-level = "2.1" data-path = "basics/route_syntax.html" >
2017-11-01 07:29:38 +00:00
< a href = "basics/route_syntax.html" >
2017-12-10 16:03:30 +00:00
Route Syntax
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "2.2" data-path = "basics/router.html" >
2017-11-01 07:29:38 +00:00
< a href = "basics/router.html" >
Router
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "2.3" data-path = "basics/path_based_routing.html" >
2017-11-01 07:29:38 +00:00
< a href = "basics/path_based_routing.html" >
Path-based Routing
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "2.4" data-path = "basics/name_based_routing.html" >
2017-11-01 07:29:38 +00:00
< a href = "basics/name_based_routing.html" >
Name-based Routing
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "2.5" data-path = "basics/route_data.html" >
2017-11-01 07:29:38 +00:00
< a href = "basics/route_data.html" >
2017-12-10 16:03:30 +00:00
Route Data
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "2.6" data-path = "basics/route_data_validation.html" >
2017-12-28 09:00:03 +00:00
< a href = "basics/route_data_validation.html" >
Route Data Validation
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "2.7" data-path = "basics/route_conflicts.html" >
2017-11-01 07:29:38 +00:00
< a href = "basics/route_conflicts.html" >
2017-12-10 16:03:30 +00:00
Route Conflicts
2017-11-01 07:29:38 +00:00
< / a >
2019-05-12 18:16:46 +00:00
< / li >
< li class = "chapter " data-level = "2.8" data-path = "basics/error_messages.html" >
< a href = "basics/error_messages.html" >
Error Messages
< / a >
2017-11-01 07:29:38 +00:00
< / li >
2018-09-03 15:58:24 +00:00
< li class = "header" > Coercion< / li >
2017-12-10 16:03:30 +00:00
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "3.1" data-path = "coercion/coercion.html" >
2017-12-10 16:03:30 +00:00
< a href = "coercion/coercion.html" >
Coercion Explained
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "3.2" data-path = "coercion/schema_coercion.html" >
2017-12-10 16:03:30 +00:00
< a href = "coercion/schema_coercion.html" >
Plumatic Schema
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "3.3" data-path = "coercion/clojure_spec_coercion.html" >
2017-12-10 16:03:30 +00:00
< a href = "coercion/clojure_spec_coercion.html" >
Clojure.spec
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "3.4" data-path = "coercion/data_spec_coercion.html" >
2017-12-10 16:03:30 +00:00
< a href = "coercion/data_spec_coercion.html" >
Data-specs
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "header" > Ring< / li >
2017-11-01 07:29:38 +00:00
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "4.1" data-path = "ring/ring.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/ring.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Ring-router
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "4.2" data-path = "ring/reverse_routing.html" >
2018-07-18 10:13:28 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/reverse_routing.html" >
2018-07-18 10:13:28 +00:00
2018-08-25 12:49:36 +00:00
Reverse-routing
2018-07-18 10:13:28 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "4.3" data-path = "ring/default_handler.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/default_handler.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Default handler
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2018-10-30 17:54:38 +00:00
< li class = "chapter " data-level = "4.4" data-path = "ring/slash_handler.html" >
< a href = "ring/slash_handler.html" >
Slash handler
< / a >
< / li >
< li class = "chapter " data-level = "4.5" data-path = "ring/static.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/static.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Static Resources
2017-11-01 07:29:38 +00:00
< / a >
2018-03-15 06:09:15 +00:00
< / li >
2018-10-30 17:54:38 +00:00
< li class = "chapter " data-level = "4.6" data-path = "ring/dynamic_extensions.html" >
2018-03-15 06:09:15 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/dynamic_extensions.html" >
2018-03-15 06:09:15 +00:00
2018-08-25 12:49:36 +00:00
Dynamic Extensions
2018-03-15 06:09:15 +00:00
< / a >
2017-11-01 07:29:38 +00:00
< / li >
2018-10-30 17:54:38 +00:00
< li class = "chapter " data-level = "4.7" data-path = "ring/data_driven_middleware.html" >
2018-08-25 12:49:36 +00:00
< a href = "ring/data_driven_middleware.html" >
Data-driven Middleware
< / a >
2017-11-01 07:29:38 +00:00
< / li >
2018-10-30 17:54:38 +00:00
< li class = "chapter " data-level = "4.8" data-path = "ring/transforming_middleware_chain.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/transforming_middleware_chain.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Transforming Middleware Chain
2017-11-01 07:29:38 +00:00
< / a >
2018-08-25 12:49:36 +00:00
< / li >
2017-11-01 07:29:38 +00:00
2018-10-30 17:54:38 +00:00
< li class = "chapter " data-level = "4.9" data-path = "ring/middleware_registry.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/middleware_registry.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Middleware Registry
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2018-10-30 17:54:38 +00:00
< li class = "chapter " data-level = "4.10" data-path = "ring/default_middleware.html" >
2018-06-14 10:29:02 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/default_middleware.html" >
2018-06-14 10:29:02 +00:00
2018-08-25 12:49:36 +00:00
Default Middleware
2018-06-14 10:29:02 +00:00
< / a >
< / li >
2020-01-17 09:05:35 +00:00
< li class = "chapter " data-level = "4.11" data-path = "ring/content_negotiation.html" >
< a href = "ring/content_negotiation.html" >
Content Negotiation
< / a >
< / li >
< li class = "chapter " data-level = "4.12" data-path = "ring/coercion.html" >
2018-04-25 18:13:54 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/coercion.html" >
2018-04-25 18:13:54 +00:00
2019-02-20 06:29:04 +00:00
Ring Coercion
2018-04-25 18:13:54 +00:00
< / a >
< / li >
2020-01-17 09:05:35 +00:00
< li class = "chapter " data-level = "4.13" data-path = "ring/route_data_validation.html" >
2018-04-25 09:50:40 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/route_data_validation.html" >
2018-04-25 09:50:40 +00:00
2018-08-25 12:49:36 +00:00
Route Data Validation
2018-04-25 09:50:40 +00:00
< / a >
< / li >
2020-01-17 09:05:35 +00:00
< li class = "chapter " data-level = "4.14" data-path = "ring/compiling_middleware.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/compiling_middleware.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Compiling Middleware
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2020-01-17 09:05:35 +00:00
< li class = "chapter " data-level = "4.15" data-path = "ring/swagger.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
< a href = "ring/swagger.html" >
2017-11-01 07:29:38 +00:00
2018-08-25 12:49:36 +00:00
Swagger Support
2017-11-01 07:29:38 +00:00
< / a >
2019-01-30 14:32:00 +00:00
< / li >
2020-01-17 09:05:35 +00:00
< li class = "chapter " data-level = "4.16" data-path = "ring/RESTful_form_methods.html" >
2019-01-30 14:32:00 +00:00
2019-01-30 14:34:15 +00:00
< a href = "ring/RESTful_form_methods.html" >
2019-01-30 14:32:00 +00:00
RESTful form methods
< / a >
2017-11-01 07:29:38 +00:00
< / li >
2018-08-25 12:49:36 +00:00
2018-09-03 15:58:24 +00:00
2018-09-08 07:54:15 +00:00
< li class = "header" > HTTP< / li >
2018-09-03 15:58:24 +00:00
2018-08-22 18:52:18 +00:00
2018-09-08 07:54:15 +00:00
< li class = "chapter " data-level = "5.1" data-path = "http/interceptors.html" >
2018-07-28 09:08:17 +00:00
2018-09-08 07:54:15 +00:00
< a href = "http/interceptors.html" >
2018-07-28 09:08:17 +00:00
2018-09-08 07:54:15 +00:00
Interceptors
2018-07-28 09:08:17 +00:00
< / a >
< / li >
2018-09-08 07:54:15 +00:00
< li class = "chapter " data-level = "5.2" data-path = "http/pedestal.html" >
2018-08-03 07:10:16 +00:00
2018-09-08 07:54:15 +00:00
< a href = "http/pedestal.html" >
2018-08-03 07:10:16 +00:00
2018-09-08 07:54:15 +00:00
Pedestal
2018-08-03 07:10:16 +00:00
< / a >
< / li >
2018-09-08 07:54:15 +00:00
< li class = "chapter " data-level = "5.3" data-path = "http/sieppari.html" >
2017-11-01 07:29:38 +00:00
2018-09-08 07:54:15 +00:00
< a href = "http/sieppari.html" >
Sieppari
< / a >
< / li >
< li class = "chapter " data-level = "5.4" data-path = "http/default_interceptors.html" >
< a href = "http/default_interceptors.html" >
2017-11-01 07:29:38 +00:00
2018-09-08 07:54:15 +00:00
Default Interceptors
2017-11-01 07:29:38 +00:00
< / a >
2018-12-30 15:16:28 +00:00
< / li >
< li class = "chapter " data-level = "5.5" data-path = "http/transforming_interceptor_chain.html" >
< a href = "http/transforming_interceptor_chain.html" >
Transforming Interceptor Chain
< / a >
2017-11-01 07:29:38 +00:00
< / li >
2017-12-29 10:06:19 +00:00
2018-09-03 15:58:24 +00:00
2018-09-08 07:54:15 +00:00
< li class = "header" > Frontend< / li >
2018-09-03 15:58:24 +00:00
2018-09-08 07:54:15 +00:00
< li class = "chapter " data-level = "6.1" data-path = "frontend/basics.html" >
2017-11-01 07:29:38 +00:00
2018-09-08 07:54:15 +00:00
< a href = "frontend/basics.html" >
2017-11-01 07:29:38 +00:00
2018-09-08 07:54:15 +00:00
Basics
< / a >
< / li >
< li class = "chapter " data-level = "6.2" data-path = "frontend/browser.html" >
< a href = "frontend/browser.html" >
Browser integration
< / a >
< / li >
< li class = "chapter " data-level = "6.3" data-path = "frontend/controllers.html" >
< a href = "frontend/controllers.html" >
Controllers
2017-11-01 07:29:38 +00:00
< / a >
2018-05-14 13:54:28 +00:00
< / li >
2018-08-25 12:49:36 +00:00
2018-09-03 15:58:24 +00:00
< li class = "header" > Advanced< / li >
< li class = "chapter " data-level = "7.1" data-path = "advanced/configuring_routers.html" >
2018-08-25 12:49:36 +00:00
2018-09-03 15:58:24 +00:00
< a href = "advanced/configuring_routers.html" >
2018-05-14 13:54:28 +00:00
2018-09-03 15:58:24 +00:00
Configuring Routers
2018-08-25 12:49:36 +00:00
< / a >
2018-09-03 15:58:24 +00:00
< / li >
2018-08-25 12:49:36 +00:00
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "7.2" data-path = "advanced/composing_routers.html" >
2018-08-25 12:49:36 +00:00
2018-09-03 15:58:24 +00:00
< a href = "advanced/composing_routers.html" >
2018-08-25 12:49:36 +00:00
2018-09-03 15:58:24 +00:00
Composing Routers
2018-05-14 13:54:28 +00:00
< / a >
2017-11-01 07:29:38 +00:00
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "7.3" data-path = "advanced/different_routers.html" >
2017-11-01 07:29:38 +00:00
2018-09-03 15:58:24 +00:00
< a href = "advanced/different_routers.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
Different Routers
2018-07-18 10:13:28 +00:00
< / a >
2018-09-03 15:58:24 +00:00
< / li >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "7.4" data-path = "advanced/route_validation.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
< a href = "advanced/route_validation.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
Route Validation
2018-07-18 10:13:28 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "7.5" data-path = "advanced/dev_workflow.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
< a href = "advanced/dev_workflow.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
Dev Workflow
2018-07-18 10:13:28 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "7.6" data-path = "advanced/shared_routes.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
< a href = "advanced/shared_routes.html" >
2018-07-18 10:13:28 +00:00
2018-09-03 15:58:24 +00:00
Shared Routes
2018-07-18 10:13:28 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "header" > Misc< / li >
< li class = "chapter active" data-level = "8.1" data-path = "performance.html" >
2017-11-01 07:29:38 +00:00
2018-02-11 19:36:11 +00:00
< a href = "performance.html" >
2017-11-01 07:29:38 +00:00
2018-02-11 19:36:11 +00:00
Performance
2017-11-01 07:29:38 +00:00
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "8.2" data-path = "development.html" >
2018-05-20 16:52:28 +00:00
< a href = "development.html" >
Development Instructions
< / a >
< / li >
2018-09-03 15:58:24 +00:00
< li class = "chapter " data-level = "8.3" data-path = "faq.html" >
2018-02-02 12:49:20 +00:00
< a href = "faq.html" >
FAQ
< / a >
2017-11-01 07:29:38 +00:00
< / li >
< li class = "divider" > < / li >
< li >
< a href = "https://www.gitbook.com" target = "blank" class = "gitbook-link" >
Published with GitBook
< / a >
< / li >
< / ul >
< / nav >
< / div >
< div class = "book-body" >
< div class = "body-inner" >
< div class = "book-header" role = "navigation" >
<!-- Title -->
< h1 >
< i class = "fa fa-circle-o-notch fa-spin" > < / i >
< a href = "." > Performance< / a >
< / h1 >
< / div >
< div class = "page-wrapper" tabindex = "-1" role = "main" >
< div class = "page-inner" >
< div id = "book-search-results" >
< div class = "search-noresults" >
< section class = "normal markdown-section" >
< h1 id = "performance" > Performance< / h1 >
2019-02-28 10:23:11 +00:00
< p > Reitit tries to be really, really fast.< / p >
2018-08-22 18:56:15 +00:00
< p > < img src = "images/opensensors.png" alt = "Opensensors perf test" > < / p >
2017-11-01 07:29:38 +00:00
< h3 id = "rationale" > Rationale< / h3 >
< ul >
2018-02-11 19:36:11 +00:00
< li > Multiple routing algorithms, chosen based on the route tree< / li >
2017-11-01 07:29:38 +00:00
< li > Route flattening and re-ordering< / li >
2018-02-11 19:36:11 +00:00
< li > Managed mutability over immutability< / li >
2019-02-28 10:23:11 +00:00
< li > Precompute/compile as much as possible (matches, middleware, interceptors, routes, path-parameter sets)< / li >
2017-11-01 07:29:38 +00:00
< li > Use abstractions that enable JVM optimizations< / li >
< li > Use small functions to enable JVM Inlining< / li >
2019-02-28 10:23:11 +00:00
< li > Use Java where needed< / li >
2018-02-11 19:36:11 +00:00
< li > Protocols over Multimethods< / li >
2017-11-01 07:29:38 +00:00
< li > Records over Maps< / li >
< li > Always be measuring< / li >
< li > Don' t trust the (micro-)benchmarks< / li >
< / ul >
2017-11-01 16:58:03 +00:00
< h3 id = "does-routing-performance-matter" > Does routing performance matter?< / h3 >
2017-11-13 05:57:11 +00:00
< p > Well, it depends. With small route trees, it might not. But, with large (real-life) route trees, difference between the fastest and the slowest tested libs can be two or three orders of magnitude. For busy sites it actually matters if you routing request takes 100 ns or 100 µ s. A lot.< / p >
2019-10-08 07:26:54 +00:00
< h3 id = "techempower-web-framework-benchmarks" > TechEmpower Web Framework Benchmarks< / h3 >
< p > Reitit + < a href = "https://github.com/metosin/jsonista" target = "_blank" > jsonista< / a > + < a href = "https://github.com/metosin/pohjavirta" target = "_blank" > pohjavirta< / a > is one of the fastest JSON api stacks in the tests. See full results < a href = "https://www.techempower.com/benchmarks/#section=test&runid=42f65a64-69b2-400d-b24e-20ecec9848bc&hw=ph&test=json" target = "_blank" > here< / a > .< / p >
< p > < img src = "images/tfb_json.png" alt = "Tech" > < / p >
2017-11-13 05:57:11 +00:00
< h3 id = "tests" > Tests< / h3 >
< p > All perf tests are found in < a href = "https://github.com/metosin/reitit/tree/master/perf-test/clj/reitit" target = "_blank" > the repo< / a > and have been run with the following setup:< / p >
< pre > < code > ;;
;; start repl with `lein perf repl`
;; perf measured with the following setup:
;;
;; Model Name: MacBook Pro
;; Model Identifier: MacBookPro11,3
;; Processor Name: Intel Core i7
;; Processor Speed: 2,5 GHz
;; Number of Processors: 1
;; Total Number of Cores: 4
;; L2 Cache (per Core): 256 KB
;; L3 Cache: 6 MB
;; Memory: 16 GB
;;
< / code > < / pre > < p > < strong > NOTE:< / strong > Tests are not scientific proof and may contain errors. You should always run the perf tests with your own (real-life) routing tables to get more accurate results for your use case. Also, if you have idea how to test things better, please let us know.< / p >
< h3 id = "simple-example" > Simple Example< / h3 >
< p > The routing sample taken from < a href = "https://github.com/funcool/bide" target = "_blank" > bide< / a > README:< / p >
2017-11-01 07:29:38 +00:00
< pre > < code class = "lang-clj" > (< span class = "hljs-name" > require< / span > ' [reitit.core < span class = "hljs-symbol" > :as< / span > r])
(< span class = "hljs-name" > require< / span > ' [criterium.core < span class = "hljs-symbol" > :as< / span > cc])
(< span class = "hljs-name" > < span class = "hljs-builtin-name" > def< / span > < / span > routes
(< span class = "hljs-name" > r/router< / span >
[[< span class = "hljs-string" > " /auth/login" < / span > < span class = "hljs-symbol" > :auth/login< / span > ]
[< span class = "hljs-string" > " /auth/recovery/token/:token" < / span > < span class = "hljs-symbol" > :auth/recovery< / span > ]
[< span class = "hljs-string" > " /workspace/:project/:page" < / span > < span class = "hljs-symbol" > :workspace/page< / span > ]]))
2017-11-13 05:57:11 +00:00
< span class = "hljs-comment" > ;; Execution time mean (per 1000) : 3.2 µ s -> 312M ops/sec< / span >
2017-11-01 07:29:38 +00:00
(< span class = "hljs-name" > cc/quick-bench< / span >
(< span class = "hljs-name" > < span class = "hljs-builtin-name" > dotimes< / span > < / span > [_ < span class = "hljs-number" > 1000< / span > ]
(< span class = "hljs-name" > r/match-by-path< / span > routes < span class = "hljs-string" > " /auth/login" < / span > )))
2019-02-28 10:23:11 +00:00
< span class = "hljs-comment" > ;; Execution time mean (per 1000): 115 µ s -> 8.7M ops/sec< / span >
2017-11-01 07:29:38 +00:00
(< span class = "hljs-name" > cc/quick-bench< / span >
(< span class = "hljs-name" > < span class = "hljs-builtin-name" > dotimes< / span > < / span > [_ < span class = "hljs-number" > 1000< / span > ]
(< span class = "hljs-name" > r/match-by-path< / span > routes < span class = "hljs-string" > " /workspace/1/1" < / span > )))
< / code > < / pre >
2019-02-28 10:23:11 +00:00
< p > Based on the < a href = "https://github.com/metosin/reitit/tree/master/perf-test/clj/reitit/perf/bide_perf_test.clj" target = "_blank" > perf tests< / a > , the first (static path) lookup is 300-500x faster and the second (wildcard path) lookup is 18-110x faster that the other tested routing libs (Ataraxy, Bidi, Compojure and Pedestal).< / p >
2017-11-13 05:57:11 +00:00
< p > But, the example is too simple for any real benchmark. Also, some of the libraries always match on the < code > :request-method< / code > too and by doing so, do more work than just match by path. Compojure does most work also by invoking the handler.< / p >
< p > So, we need to test something more realistic.< / p >
< h3 id = "restful-apis" > RESTful apis< / h3 >
< p > To get better view on the real life routing performance, there is < a href = "https://github.com/metosin/reitit/blob/master/perf-test/clj/reitit/opensensors_perf_test.clj" target = "_blank" > test< / a > 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 < a href = "https://opensensors.io/" target = "_blank" > OpenSensors< / a > swagger definitions.< / p >
2019-02-28 10:23:11 +00:00
< p > Thanks to the snappy < a href = "https://github.com/metosin/reitit/blob/master/modules/reitit-core/java-src/reitit/Trie.java" target = "_blank" > Wildcard Trie< / a > (a modification of < a href = "https://en.wikipedia.org/wiki/Radix_tree" target = "_blank" > Radix Tree< / a > ), < code > reitit-ring< / code > is fastest here. < a href = "https://github.com/kumarshantanu/calfpath" target = "_blank" > Calfpath< / a > and < a href = "https://github.com/pedestal/pedestal" target = "_blank" > Pedestal< / a > are also quite fast.< / p >
2018-12-30 15:32:43 +00:00
< p > < img src = "images/opensensors.png" alt = "Opensensors perf" > < / p >
2017-11-13 05:57:11 +00:00
< h3 id = "cqrs-apis" > CQRS apis< / h3 >
2019-01-16 07:37:33 +00:00
< p > Another real-life < a href = "https://github.com/metosin/reitit/blob/master/perf-test/clj/reitit/lupapiste_perf_test.clj" target = "_blank" > test scenario< / a > is a < a href = "https://martinfowler.com/bliki/CQRS.html" target = "_blank" > CQRS< / a > style route tree, where all the paths are static, e.g. < code > /api/command/add-order< / code > . The 300 route definitions are pulled out from < a href = "https://github.com/lupapiste/lupapiste" target = "_blank" > Lupapiste< / a > .< / p >
2018-02-11 19:36:11 +00:00
< p > Both < code > reitit-ring< / code > and Pedestal shine in this test, thanks to the fast lookup-routers. On average, they are < strong > two< / strong > and on best case, < strong > three orders of magnitude faster< / strong > than the other tested libs. Ataraxy failed this test on < code > Method code too large!< / code > error.< / p >
2018-12-30 15:32:43 +00:00
< p > < img src = "images/lupapiste.png" alt = "lupapiste perf" > < / p >
2018-02-11 19:36:11 +00:00
< p > < strong > NOTE< / strong > : in real life, there are usually always also wild-card routes present. In this case, Pedestal would fallback from lookup-router to the prefix-tree router, which is order of magnitude slower (30x in this test). Reitit would handle this nicely thanks to it' s < code > :mixed-router< / code > : all static routes would still be served with < code > :lookup-router< / code > , just the wildcard routes with < code > :segment-tree< / code > . The performance would not notably degrade.< / p >
2019-02-28 10:23:11 +00:00
< h3 id = "path-conflicts" > Path conflicts< / h3 >
< p > < strong > TODO< / strong > < / p >
2017-11-13 05:57:11 +00:00
< h3 id = "why-measure" > Why measure?< / h3 >
2018-02-11 19:36:11 +00:00
< p > The reitit routing perf is measured to get an internal baseline to optimize against. We also want to ensure that new features don' t regress the performance. Perf tests should be run in a stable CI environment. Help welcome!< / p >
2017-11-13 05:57:11 +00:00
< h3 id = "looking-out-of-the-box" > Looking out of the box< / h3 >
2019-02-28 10:23:11 +00:00
< p > A quick poke to < a href = "https://github.com/julienschmidt/go-http-routing-benchmark" target = "_blank" > the fast routers in Go< / a > indicates that reitit is less 50% slower than the fastest routers in Go. Which is kinda awesome.< / p >
2019-01-16 07:37:33 +00:00
< h3 id = "faster" > Faster!< / h3 >
< p > By default, < code > reitit.ring/ring-router< / code > , < code > reitit.http/ring-router< / code > and < code > reitit.http/routing-interceptor< / code > inject both < code > Match< / code > and < code > Router< / code > into the request. You can remove the injections setting options < code > :inject-match?< / code > and < code > :inject-router?< / code > to < code > false< / code > . This saves some tens of nanos (with the hw described above).< / p >
< pre > < code class = "lang-clj" > (< span class = "hljs-name" > require< / span > ' [reitit.ring < span class = "hljs-symbol" > :as< / span > ring])
(< span class = "hljs-name" > require< / span > ' [criterium.core < span class = "hljs-symbol" > :as< / span > cc])
(< span class = "hljs-name" > < span class = "hljs-builtin-name" > defn< / span > < / span > create [options]
(< span class = "hljs-name" > ring/ring-handler< / span >
(< span class = "hljs-name" > ring/router< / span >
[< span class = "hljs-string" > " /ping" < / span > (< span class = "hljs-name" > < span class = "hljs-builtin-name" > constantly< / span > < / span > {< span class = "hljs-symbol" > :status< / span > < span class = "hljs-number" > 200< / span > , < span class = "hljs-symbol" > :body< / span > < span class = "hljs-string" > " ok" < / span > })])
(< span class = "hljs-name" > ring/create-default-handler< / span > )
options))
< span class = "hljs-comment" > ;; 130ns< / span >
(< span class = "hljs-name" > < span class = "hljs-builtin-name" > let< / span > < / span > [app (< span class = "hljs-name" > create< / span > < span class = "hljs-literal" > nil< / span > )]
(< span class = "hljs-name" > cc/quick-bench< / span >
(< span class = "hljs-name" > app< / span > {< span class = "hljs-symbol" > :request-method< / span > < span class = "hljs-symbol" > :get< / span > , < span class = "hljs-symbol" > :uri< / span > < span class = "hljs-string" > " /ping" < / span > })))
< span class = "hljs-comment" > ;; 80ns< / span >
(< span class = "hljs-name" > < span class = "hljs-builtin-name" > let< / span > < / span > [app (< span class = "hljs-name" > create< / span > {< span class = "hljs-symbol" > :inject-router?< / span > < span class = "hljs-literal" > false< / span > , < span class = "hljs-symbol" > :inject-match?< / span > < span class = "hljs-literal" > false< / span > })]
(< span class = "hljs-name" > cc/quick-bench< / span >
(< span class = "hljs-name" > app< / span > {< span class = "hljs-symbol" > :request-method< / span > < span class = "hljs-symbol" > :get< / span > , < span class = "hljs-symbol" > :uri< / span > < span class = "hljs-string" > " /ping" < / span > })))
< / code > < / pre >
< p > < strong > NOTE< / strong > : Without < code > Router< / code > , you can' t to do < a href = "ring/reverse_routing.html" > reverse routing< / a > and without < code > Match< / code > you can' t write < a href = "ring/dynamic_extensions.html" > dynamic extensions< / a > .< / p >
2017-11-13 05:57:11 +00:00
< h3 id = "performance-tips" > Performance tips< / h3 >
2017-11-11 15:38:31 +00:00
< p > Few things that have an effect on performance:< / p >
< ul >
< li > Wildcard-routes are an order of magnitude slower than static routes< / li >
2019-01-16 07:37:33 +00:00
< li > Conflicting routes are served with LinearRouter, which is the slowest implementation.< / li >
< li > 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. < / li >
< li > Move computation from request processing time into creation time, using by compiling < a href = "ring/compiling_middleware.html" > middleware< / a > , < a href = "http/interceptors.html" > interceptors< / a > and < a href = "advanced/configuring_routers.html" > route data< / a > .< ul >
2017-11-13 05:57:11 +00:00
< li > Unmounted middleware (or interceptor) is infinitely faster than a mounted one effectively doing nothing.< / li >
< / ul >
< / li >
2017-11-11 15:38:31 +00:00
< / ul >
2017-11-01 07:29:38 +00:00
< / section >
< / div >
< div class = "search-results" >
< div class = "has-results" >
< h1 class = "search-results-title" > < span class = 'search-results-count' > < / span > results matching "< span class = 'search-query' > < / span > "< / h1 >
< ul class = "search-results-list" > < / ul >
< / div >
< div class = "no-results" >
< h1 class = "search-results-title" > No results matching "< span class = 'search-query' > < / span > "< / h1 >
< / div >
< / div >
< / div >
< / div >
< / div >
< / div >
2018-09-03 15:58:24 +00:00
< a href = "advanced/shared_routes.html" class = "navigation navigation-prev " aria-label = "Previous page: Shared Routes" >
2017-11-01 07:29:38 +00:00
< i class = "fa fa-angle-left" > < / i >
< / a >
2018-09-03 15:58:24 +00:00
< a href = "development.html" class = "navigation navigation-next " aria-label = "Next page: Development Instructions" >
2017-11-27 06:15:59 +00:00
< i class = "fa fa-angle-right" > < / i >
< / a >
2017-11-01 07:29:38 +00:00
< / div >
< script >
var gitbook = gitbook || [];
gitbook.push(function() {
2020-02-03 10:53:56 +00:00
gitbook.page.hasChanged({"page":{"title":"Performance","level":"8.1","depth":1,"next":{"title":"Development Instructions","level":"8.2","depth":1,"path":"development.md","ref":"development.md","articles":[]},"previous":{"title":"Shared Routes","level":"7.6","depth":1,"path":"advanced/shared_routes.md","ref":"advanced/shared_routes.md","articles":[]},"dir":"ltr"},"config":{"plugins":["hints","editlink","github","highlight"],"root":"doc","styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"pluginsConfig":{"github":{"url":"https://github.com/metosin/reitit"},"editlink":{"label":"Edit This Page","multilingual":false,"base":"https://github.com/metosin/reitit/tree/master/doc"},"search":{},"hints":{"danger":"fa fa-exclamation-circle","info":"fa fa-info-circle","tip":"fa fa-mortar-board","working":"fa fa-wrench"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"fontsettings":{"theme":"white","family":"sans","size":2},"highlight":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"theme":"default","pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"variables":{},"gitbook":"*"},"file":{"path":"performance.md","mtime":"2020-02-03T10:53:25.275Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2020-02-03T10:53:51.888Z"},"basePath":".","book":{"language":""}});
2017-11-01 07:29:38 +00:00
});
< / script >
< / div >
< script src = "gitbook/gitbook.js" > < / script >
< script src = "gitbook/theme.js" > < / script >
< script src = "gitbook/gitbook-plugin-editlink/plugin.js" > < / script >
< script src = "gitbook/gitbook-plugin-github/plugin.js" > < / script >
< script src = "gitbook/gitbook-plugin-search/search-engine.js" > < / script >
< script src = "gitbook/gitbook-plugin-search/search.js" > < / script >
< script src = "gitbook/gitbook-plugin-lunr/lunr.min.js" > < / script >
< script src = "gitbook/gitbook-plugin-lunr/search-lunr.js" > < / script >
< script src = "gitbook/gitbook-plugin-sharing/buttons.js" > < / script >
< script src = "gitbook/gitbook-plugin-fontsettings/fontsettings.js" > < / script >
< / body >
< / html >