Skip to content
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

feat: Redis as (distributed) cache #999

Merged
merged 107 commits into from
Mar 11, 2024
Merged

Conversation

tk-innoq
Copy link
Contributor

@tk-innoq tk-innoq commented Nov 6, 2023

Related issue(s)

closes #17

Checklist

  • I agree to follow this project's Code of Conduct.
  • I have read, and I am following this repository's Contributing Guidelines.
  • I have read the Security Policy.
  • I have referenced an issue describing the bug/feature request.
  • I have added tests that prove the correctness of my implementation.
  • I have updated the documentation.

Description

Before this PR, there was just the in-memory cache. This PR makes cache configurable by introducing a cache property on the top level of heimdall configuration, like shown below:

cache:
  type: in-memory # or noop, redis, redis-cluster, or redis-sentinel
  config: # depends on the type
    # type specific configuration goes here

As also shown in the snipped above, there are a couple of cache types one can now configure:

  • noop - Caching is disabled completely. That means any cache settings on mechanism level do not have any effect. No configuration is supported for this type.
  • in-memory - This is the default setting, which implements the behavior used by heimdall so far. No configuration is supported for this type.
  • redis - A Redis single instance can be used as a cache store. Configuration is required (see below).
  • redis-cluster - A Redis cluster can be used as a distributed cache store. Configuration is required (see below).
  • redis-sentinel - A Redis sentinel can be used as a distributed cache store. Configuration is required (see below)

Common configuration options for all redis cache types

# Optional credentials to connect to Redis. Either 'path' or 'username` and `password` can be used.
credentials:
  # Optional path to the credentials file
  path: /path/to/credentials/file
  # Optional username to use to connect to the Redis DB/Cluster
  username: foo
  # Mandatory password to use to connect to the Redis DB/Cluster
  password: foobar

# Alternatively to specifying a map for the credentials property,
# one can reference a file with credentals: /path/to/file with username
# and password configured. This way you can rotate these settings
# without the need to restart heimdall.

# Optional configuration for the client cache to reduce roundtrip time
client_cache:
  # Whether the client cache should be disabled. Defaults to false
  disabled: false
  # Specifies the maximum TTL on the client side for all used keys. 
  # If the key's TTL on the server is smaller than the client side TTL, 
  # the client side TTL will be capped.
  ttl: 5m
  # Optional client side cache size that bind to each TCP connection
  # to a single redis instance. Defaults to 128MB
  size_per_connection: 128MB 
  
# Optional connection buffer limits
buffer_limit: 
  # Read size for each connection. Defaults to 0.5MB
  read: 1MB 
  # Write size for each connection. Defaults to 0.5MB 
  write: 1MB
  
# Optional connection time outs
timeout:
  # The write timeout for connections. Defaults to 150s
  write: 150s

# Optional data flush delay. When greater than zero, pauses pipeline write loop
# for some time (not larger than max_flush_delay)  after each flushing of data to
# the connection. This gives pipeline a chance to collect more commands to 
# send to Redis. Adding this delay increases latency, reduces throughput, but in
# most cases may significantly reduce application and Redis CPU utilization due
# to less executed system calls. By default, the data is flushed to the connection
# without extra delays. Depending on network latency and application-specific
# conditions the value of max_flush_delay may vary, something like 20 µs should
# not affect latency/throughput a lot but still produce notable CPU usage
# reduction under load. Defaults to 0s
max_flush_delay: 20us # 20µs

# Optional TLS configuration. TLS is enabled by default
# The system trust store is used to verify the TLS server certificates
tls:
  # Disables TLS. Defaults to false
  disabled: false

  # Further properties as already known from service configurations. All are optional
  # If client authentication is required, configure the key_store
  key_store:
    path: /path/to/keystore/file.pem
    password: VerySecret!
  # Which key/certificate to use from the key store. If not set, the first one is taken
  key_id: foo
  # Min TLS version. Defaults to TLS1.3
  min_version: TLS1.2
  # Which cipher suites to use with TLS1.2 (all supported cipher suites are shown below)
  cipher_suites:
    - "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
    - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
    - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
    - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
    - "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
    - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
    - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
    - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"

Additional configuration properties per redis type:

  • redis:
    # Mandatory Redis instance address to connect to.
    address: foo:12345
    # Optional Redis DB ID to use. Defaults to 0
    db: 0
  • redis-cluster:
    # Mandatory list of Redis nodes to connect to
    nodes:
      - foo:1234
      - bar:1234
  • redis-sentinel:
    # Optional Redis DB ID to use. Defaults to 0
    db: 0
    # Mandatory sentinel master set name
    master: whatever
    # Mandatory list of Redis nodes to connect to
    nodes:
      - foo:1234
      - bar:1234

Additional Information

  • If Redis (Standalone/Cluster/sentinel) is not available at start up, heimdall will refuse to start. At run time however, only warnings will be emitted if communication to Redis is not possible, but the functionality will be preserved with, depending on your rules, some performance degradation. Corresponding metrics are exposed as well.

  • Same credentials and TLS settings are used for sentinel and master nodes connections if sentinel is configured.

  • Values to be cached may contain highly sensible information. For that reason, TLS is enabled by default (see configuration options above). You should however also ensure your Redis setup has data encryption configured as well.

  • As shown in the configuration snippet above, this PR implements support for short living DB credentials. To make use of that, configure a valid path to the corresponding yaml/json file with username and password managed externally.
    Example:

    # Redis cache config
    credentials: 
     path: /path/to/credentials.yaml

    And the contents of the credentials.yaml from above would look like

    username: foo
    password: foobar

    In addition, you have to allow reloading of externally managed secrets by setting secrets_reload_enabled to true on the top level of heimdall configuration.
    Example:

    serve:
      # your serve settings
    
    cache:
      # your cache settings (see above)
    
    secrets_reload_enabled: true

the below lines are for release please to clean up the changelog as this dependency is either new in this release, not used any more, or there are new commits with more recent versions

BEGIN_COMMIT_OVERRIDE
feat: Redis as (distributed) cache (#999) by @tk-innoq
END_COMMIT_OVERRIDE

@tk-innoq tk-innoq changed the title wip: feat: Implement Redis cache feat: Implement Redis cache Nov 6, 2023
@tk-innoq
Copy link
Contributor Author

tk-innoq commented Nov 6, 2023

Relates to: #17

@tk-innoq tk-innoq closed this Nov 6, 2023
@tk-innoq tk-innoq reopened this Nov 6, 2023
internal/cache/module.go Fixed Show resolved Hide resolved
@dadrus
Copy link
Owner

dadrus commented Nov 6, 2023

@tk-innoq: Thank you very much for the PR. Would you please fix the style and test issues? I'll take a closer look at the PR as soon as this is done.

Copy link

codecov bot commented Nov 6, 2023

Codecov Report

Attention: Patch coverage is 90.27778% with 28 lines in your changes are missing coverage. Please review.

Project coverage is 89.21%. Comparing base (4449cb7) to head (89420ed).
Report is 1 commits behind head on main.

Files Patch % Lines
internal/watcher/watcher_impl.go 77.77% 7 Missing and 3 partials ⚠️
internal/watcher/module.go 33.33% 3 Missing and 1 partial ⚠️
internal/cache/redis/config_decoder.go 86.95% 2 Missing and 1 partial ⚠️
internal/watcher/noop_watcher.go 0.00% 3 Missing ⚠️
internal/cache/factory_registry.go 86.66% 1 Missing and 1 partial ⚠️
internal/cache/memory/cache.go 75.00% 2 Missing ⚠️
internal/cache/module/module.go 77.77% 2 Missing ⚠️
internal/cache/noop/cache.go 50.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #999      +/-   ##
==========================================
+ Coverage   89.13%   89.21%   +0.07%     
==========================================
  Files         254      266      +12     
  Lines        8504     8771     +267     
==========================================
+ Hits         7580     7825     +245     
- Misses        683      699      +16     
- Partials      241      247       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@dadrus dadrus changed the title feat: Implement Redis cache wip: Implement Redis cache Nov 14, 2023
@dadrus
Copy link
Owner

dadrus commented Mar 1, 2024

The PR is complete from functionality point of view. Waiting for finalization of #1075 to add the new cache related content to

@dadrus dadrus changed the title wip: Implement Redis cache feat: Redis as (distributed) cache Mar 1, 2024
@dadrus dadrus merged commit 2f9ba81 into dadrus:main Mar 11, 2024
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement support for Radis as an alternative to the available in-memory cache
2 participants