-
Notifications
You must be signed in to change notification settings - Fork 5.5k
filter: add HazelcastHttpCache #10536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 7 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
3ff732d
Add HazelcastHttpCache
enozcan c39db10
Secure body key uniqueness and set defaults.
enozcan f359a8e
Use Envoy's random for versioning.
enozcan d6f2568
Handle all connection failures. Use parameterized test for common ones.
enozcan 8630701
Add local cache to use during tests.
enozcan 2232761
Add plugin doc and fix spell check.
enozcan 8ca71fc
Fix code format & clean up.
enozcan a3a1af4
Fix clang_tidy errors.
enozcan 31c0b3c
Apply upstream changes
enozcan cabb409
Disable PartitionAware for body entries.
enozcan fc5c3ee
Merge branch 'master' into hazelcast_http_cache
enozcan 7334709
Fix format and revert LookupRequest changes back.
enozcan 839c418
Add serialization tests.
enozcan 2576ebc
Move remote calls to cache accessors.
enozcan fde9e19
Change key serialization from UTF to byte array.
enozcan 104f8e0
Update plugin doc.
enozcan 1f152b5
Fix asan errors other than bitswap.
enozcan 3ebb754
Add header eviction listener.
enozcan 7665fa0
Allow overriding cached responses.
enozcan c2801f4
Add Bits.h patch for ubsan fix.
enozcan 9172525
Fix clang warns.
enozcan bb9ce1e
Cover remote calls over offline client.
enozcan ce6651b
tsan fix
enozcan 8e3129a
Address reviews.
enozcan 570e362
Use max_body_bytes from CacheConfig.
enozcan 66a1f01
Use core.SocketAddress for member address.
enozcan 0acc4d1
Fix format.
enozcan d3b0cf5
Fix Windows lib name.
enozcan d40185f
Merge branch 'master' into hazelcast_http_cache
enozcan eb50942
Fix format.
enozcan 7413c54
Remove accessor cast and move logs to accessor.
enozcan a1167a1
Pass accessor via cache::start
enozcan 639bfbb
Revert back to unit64 max body bytes.
enozcan ab2f3fd
Add tests.
enozcan 49ca85b
Add Windows build defines.
enozcan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- CMakeLists.txt 2020-02-27 11:35:35.000000000 +0300 | ||
| +++ CMakeLists.txt 2020-02-27 11:37:15.000000000 +0300 | ||
| @@ -279,3 +279,9 @@ | ||
| ADD_SUBDIRECTORY(examples) | ||
| message(STATUS "Configured to build the examples.") | ||
| ENDIF(HZ_BUILD_EXAMPLES) | ||
| +INSTALL(TARGETS ${HZ_LIB_NAME} DESTINATION lib) | ||
| +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/hazelcast/generated-sources/include/hazelcast DESTINATION include FILES_MATCHING PATTERN "*.h") | ||
| +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/hazelcast/include/hazelcast DESTINATION include FILES_MATCHING PATTERN "*.h" PATTERN "*.inl") | ||
| +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/external/release_include/boost DESTINATION include FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h") | ||
| +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/external/release_include/easylogging++ DESTINATION include FILES_MATCHING PATTERN "*.h") | ||
| +INSTALL(DIRECTORY ${PROJECT_SOURCE_DIR}/external/include/asio/asio/include/asio DESTINATION include FILES_MATCHING PATTERN "*.hpp") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
186 changes: 186 additions & 0 deletions
186
source/docs/filters/http/cache/hazelcast_cache_plugin.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| ### Hazelcast Http Cache Plugin | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see the docs here for the filter are kind of |
||
| Work in Progress--Cache filter has not implemented features. The corresponding ones are not ready for the plugin too. | ||
|
|
||
| Hazelcast Http Cache provides a pluggable storage implementation backed by Hazelcast In Memory Data Grid for the http | ||
| cache filter. Using Hazelcast C++ client, the plugin does not store any http response locally but in a distributed map | ||
| provided by Hazelcast cluster. To enable the cache plugin, the network configuration belongs to a cluster to be | ||
|
enozcan marked this conversation as resolved.
Outdated
|
||
| connected must be set on the cache plugin configuration. | ||
|
|
||
| ## Offered cache modes | ||
| The plugin comes with two modes: | ||
|
|
||
| - **Unified** | ||
| A cached http response is stored as a single entry in the cache. On a range http request, regardless of the requested | ||
| range, the whole response body is fetched from the cache and then only the desired bytes are served along with the | ||
| headers and trailers (if any). This mode is handy where response body sizes are reasonably large (up to 10 KB), or | ||
|
enozcan marked this conversation as resolved.
Outdated
|
||
| range requests are not frequent, or they are not allowed at all. | ||
|
|
||
| - **Divided** | ||
| A cached http response is stored as multiple entries in the cache. Two separate maps are used to store a single | ||
| response. In one of them, response headers, body size, and trailers (if any) are stored. In the other one, the | ||
| corresponding response body is stored in multiple entries each of which has a certain size configured via `partition | ||
| size` in the plugin configuration. That is, for a response of size 50 KB, if the configured partition size is 20 KB, | ||
| then three different entries will be created to store the body of this response: | ||
| - Body<1> : 0 - 19 KB | ||
| - Body<2> : 20 - 39 KB | ||
| - Body<3> : 40 - 50 KB | ||
|
|
||
| On a range request, not the whole body for a response but only the necessary partitions are fetched from the | ||
| cache. This option helps to serve range requests faster and in a stream-like fashion but comes with a cost. Every | ||
| body entry has its own fixed memory cost and hence partitioned entries need larger memory than the actual body | ||
| size. Also, to keep these partitioned cache entries even, extra operations - not necessarily asynchronous, might | ||
| be needed (i.e. cleaning up a malformed body sequence, recovery from a mismatch between body and header, etc.). | ||
|
|
||
| ## Connecting to a Hazelcast cluster | ||
| **NOTE:** The plugin uses the client with version 3.12.1 and hence it is not yet compatible with Hazelcast 4.x. | ||
| Hazelcast version 3.12.x is recommended for the server-side. | ||
|
|
||
| Before starting the cache plugin, there must be a running Hazelcast cluster. Hazelcast instances might be started | ||
| as a sidecar to Envoy, form up a cluster using Hazelcast Kubernetes plugin, etc. The only information the plugin needs | ||
| will be the addresses and ports of the cluster members and the group information of the cluster. Providing the address | ||
| of only one member in the cluster will be enough for the connection but using more than one is recommended. | ||
|
|
||
| Related links: [Hazelcast Docker Hub](https://hub.docker.com/r/hazelcast/hazelcast/), [Hazelcast Kubernetes Plugin] | ||
| (https://github.com/hazelcast/hazelcast-kubernetes) | ||
|
|
||
| ## Configuring Hazelcast cluster for the cache | ||
| Eviction, maximum size, and other related properties for the cache must be configured on the server-side | ||
| via programmatic configuration or `hazelcast.xml`. | ||
|
|
||
| - **Unified Mode** | ||
|
|
||
| ```xml | ||
| <!-- use wildcard for the map name to configure the cache since the full name is determined by the plugin --> | ||
| <map name="<app_prefix>*uni"> | ||
|
|
||
| <!-- | ||
|
|
||
| Customizable http cache configurations. | ||
| For instance, for the configuration below: | ||
|
|
||
| - 25% of the http responses will be evicted according to LRU policy when the map size hits 1000. | ||
| - Each http responses will live at most 180 seconds in the cache. | ||
| - If an http responses is not called for the last 90 seconds, it will be evicted immediately regardless of the TTL. | ||
|
|
||
| --> | ||
| <max-size policy="PER_NODE">1000</max-size> | ||
| <eviction-percentage>25</eviction-percentage> | ||
| <eviction-policy>LRU</eviction-policy> | ||
| <time-to-live-seconds>180</time-to-live-seconds> | ||
| <max-idle-seconds>90</max-idle-seconds> | ||
|
|
||
| <!-- | ||
|
|
||
| For more configuration options, see Hazelcast doc: | ||
|
|
||
| https://docs.hazelcast.org/docs/3.12.6/manual/html-single/index.html#map | ||
|
|
||
| OBJECT in-memory format will not have any advantage but extra serialization cost here. Setting it to | ||
| BINARY is the best fit for the plugin. The two configurations below are also the default values. | ||
|
|
||
| --> | ||
| <in-memory-format>BINARY</in-memory-format> | ||
| <statistics-enabled>true</statistics-enabled> | ||
| </map> | ||
| ``` | ||
|
|
||
| - **Divided Mode** | ||
|
|
||
| ```xml | ||
| <!-- use wildcard for the map name to configure the cache since the full name is determined by the plugin.default --> | ||
| <map name="<app_prefix>*div"> | ||
|
|
||
| <!-- | ||
|
|
||
| Customizable http cache configurations for header map. The properties below will determine the | ||
| characteristics of the http cache, not only response headers cache. | ||
|
|
||
| For instance, for the configuration below: | ||
|
|
||
| - 25% of the http responses will be evicted according to LRU policy when the map size hits 100. | ||
| - Each http responses will live at most 180 seconds in the cache. | ||
|
|
||
| NOTE: Although works fine, divided mode is not optimized for idle-time based eviction. | ||
|
|
||
| --> | ||
| <max-size policy="PER_NODE">100</max-size> | ||
| <eviction-percentage>25</eviction-percentage> | ||
| <eviction-policy>LRU</eviction-policy> | ||
| <time-to-live-seconds>180</time-to-live-seconds> | ||
|
|
||
| <!-- | ||
|
|
||
| For more configuration options, see Hazelcast doc: | ||
|
|
||
| https://docs.hazelcast.org/docs/3.12.6/manual/html-single/index.html#map | ||
|
|
||
| OBJECT in-memory format will not have any advantage but extra serialization cost here. Setting it to | ||
| BINARY is the best fit for the plugin. The two configurations below are also the default values. | ||
|
|
||
| --> | ||
| <in-memory-format>BINARY</in-memory-format> | ||
| <statistics-enabled>true</statistics-enabled> | ||
| </map> | ||
|
|
||
| <map name="<app_prefix>*body"> | ||
|
|
||
| <!-- | ||
|
|
||
| Customizable http cache configurations for body map. | ||
|
|
||
| Do not set the cache configuration here. Instead, configure `<app_prefix>*div` first and set | ||
| the properties here accordingly. | ||
|
|
||
| - Do not use max-size configuration here. They will be evicted according to TTL when their header is evicted. | ||
| Instead, the max size is (indirectly) ensured with max allowed body size configuration along with the partition | ||
| size. | ||
| - Use the same eviction configuration with the header map. | ||
| - Keep TTL slightly longer than the header map (i.e. 15 seconds). | ||
|
|
||
| NOTE: Although works fine, divided mode is not optimized for idle-time based eviction. | ||
|
|
||
| --> | ||
| <max-size policy="PER_NODE">0</max-size> | ||
| <eviction-percentage>25</eviction-percentage> | ||
| <eviction-policy>LRU</eviction-policy> | ||
| <time-to-live-seconds>195</time-to-live-seconds> | ||
|
|
||
| <!-- | ||
|
|
||
| OBJECT in-memory format will not have any advantage but extra serialization cost here. Setting it to | ||
| BINARY is the best fit for the plugin. The two configurations below are also the default values. | ||
|
|
||
| Statistics of this map will not have meaningful information about the cache and can be disabled if not needed. | ||
| However, it might be useful to observe how the configured `partition_size` fits for the cached responses. | ||
|
|
||
| --> | ||
| <in-memory-format>BINARY</in-memory-format> | ||
| <statistics-enabled>false</statistics-enabled> | ||
| </map> | ||
| ``` | ||
|
|
||
| When one of the clients connected to the cluster loses its connection, if the client has acquired the lock for a | ||
| key, this will cause this key to be unusable. To prevent such a scenario in a possible connection failure, the | ||
| maximum time limit for the locks should be set on the server-side (not necessarily to be 60 seconds). The default | ||
| value for this property is `Long.MAX`. Hence, if it is not set, on a connection failure a locked key will | ||
| be unusable permanently: | ||
| ```xml | ||
| <properties> | ||
| ... | ||
| <!-- required for both of the cache modes --> | ||
| <property name="hazelcast.lock.max.lease.time.seconds">60</property> | ||
| ... | ||
| </properties> | ||
| ``` | ||
| **NOTE**: Setting this property will affect not only the http cache but all other data structures in the cluster. | ||
|
|
||
| ## Statistics | ||
| Cache statistics are not collected locally. Instead, cluster-wide statistics should be observed on Hazelcast | ||
| Management Center. When the cache plugin starts, one of the very first logs will be saying the map name used for | ||
| the cache. The statistics can be observed with that name under the `maps` section on the management center. | ||
|
|
||
| ## Using a single cache for multiple filters | ||
| Each distributed map in a Hazelcast cluster is differentiated by its name for the same key and value types. Thus, | ||
| all the plugins connected to the same cluster will use the same map for responses only if they have the same cache | ||
| mode and the app prefix (and the same partition size for divided mode) in the plugin configuration. The filters | ||
| configured with the same partition size and cache mode but different prefixes will create two different http caches. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
source/extensions/filters/http/cache/hazelcast_http_cache/BUILD
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| licenses(["notice"]) # Apache 2 | ||
|
|
||
| load( | ||
| "//bazel:envoy_build_system.bzl", | ||
| "envoy_cc_extension", | ||
| "envoy_package", | ||
| "envoy_proto_library", | ||
| ) | ||
|
|
||
| envoy_package() | ||
|
|
||
| envoy_cc_extension( | ||
| name = "hazelcast_http_cache_lib", | ||
| srcs = [ | ||
| "hazelcast_cache_entry.cc", | ||
| "hazelcast_context.cc", | ||
| "hazelcast_http_cache_impl.cc", | ||
| ], | ||
| hdrs = [ | ||
| "hazelcast_cache.h", | ||
| "hazelcast_cache_entry.h", | ||
| "hazelcast_context.h", | ||
| "hazelcast_http_cache_impl.h", | ||
| "util.h", | ||
| ], | ||
| external_deps = ["hazelcast_cpp_client"], | ||
| security_posture = "robust_to_untrusted_downstream_and_upstream", | ||
| status = "wip", | ||
| deps = [ | ||
| ":config_cc_proto", | ||
| "//include/envoy/registry", | ||
| "//source/common/buffer:buffer_lib", | ||
| "//source/common/common:logger_lib", | ||
| "//source/common/http:header_map_lib", | ||
| "//source/common/runtime:runtime_lib", | ||
| "//source/extensions/filters/http/cache:http_cache_lib", | ||
| ], | ||
| ) | ||
|
|
||
| envoy_proto_library( | ||
| name = "config", | ||
| srcs = ["config.proto"], | ||
| ) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to update submodules before building the external dependency?