{"id":23788735,"url":"https://github.com/suppierk/spring-boot-multilevel-cache-starter","last_synced_at":"2025-09-06T07:32:16.349Z","repository":{"id":40506594,"uuid":"392026564","full_name":"SuppieRK/spring-boot-multilevel-cache-starter","owner":"SuppieRK","description":"Spring Boot multi-level caching with Redis and Caffeine","archived":false,"fork":false,"pushed_at":"2024-12-29T03:05:02.000Z","size":245,"stargazers_count":22,"open_issues_count":0,"forks_count":9,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-12-29T03:20:25.301Z","etag":null,"topics":["cache","caching","caffeine-cache","microservices","redis","spring","spring-boot","two-level-cache"],"latest_commit_sha":null,"homepage":"https://github.com/SuppieRK/spring-boot-multilevel-cache-starter","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SuppieRK.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-02T16:51:41.000Z","updated_at":"2024-12-29T03:02:10.000Z","dependencies_parsed_at":"2024-12-12T03:17:19.398Z","dependency_job_id":"a93641fc-c4c1-475a-a422-f97befe45b18","html_url":"https://github.com/SuppieRK/spring-boot-multilevel-cache-starter","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuppieRK%2Fspring-boot-multilevel-cache-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuppieRK%2Fspring-boot-multilevel-cache-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuppieRK%2Fspring-boot-multilevel-cache-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SuppieRK%2Fspring-boot-multilevel-cache-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SuppieRK","download_url":"https://codeload.github.com/SuppieRK/spring-boot-multilevel-cache-starter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232104443,"owners_count":18473163,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cache","caching","caffeine-cache","microservices","redis","spring","spring-boot","two-level-cache"],"created_at":"2025-01-01T16:48:04.509Z","updated_at":"2025-09-06T07:32:16.337Z","avatar_url":"https://github.com/SuppieRK.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Spring Boot multi-level cache starter\n\nOpinionated version of multi-level caching for [Spring Boot](https://spring.io/projects/spring-boot) with [Redis](https://redis.io/) as L2 (remote) cache and [Caffeine](https://github.com/ben-manes/caffeine) as L1 (local) cache with a Circuit Breaker pattern for L2 cache calls.\n\nThis version does not allow setting most of the local cache properties in favor of managing local cache expiry by itself.\n\n[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B20864%2Fgithub.com%2FSuppieRK%2Fspring-boot-multilevel-cache-starter.svg?type=shield\u0026issueType=license)](https://app.fossa.com/projects/custom%2B20864%2Fgithub.com%2FSuppieRK%2Fspring-boot-multilevel-cache-starter?ref=badge_shield\u0026issueType=license)\n\n[![SonarCloud](https://sonarcloud.io/images/project_badges/sonarcloud-orange.svg)](https://sonarcloud.io/summary/overall?id=SuppieRK_spring-boot-multilevel-cache-starter)\n\n## Usage\n### Maven\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.suppierk\u003c/groupId\u003e\n  \u003cartifactId\u003espring-boot-multilevel-cache-starter\u003c/artifactId\u003e\n  \u003cversion\u003e3.5.4.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n### Gradle\n```groovy\nimplementation 'io.github.suppierk:spring-boot-multilevel-cache-starter:3.5.4.0'\n```\n\n## Use cases\n\n### Suitable for\n- Microservices working with immutable cached entities under low latency requirements\n  - The goal is to not only reduce the number of calls to external service but also reduce the number of calls to Redis\n\n### Not a good fit for\n- Mutable cached entities\n- Entities with short time to live (\u003c 5 minutes)\n- Cases when entities in local cache **must** outlive entities in distributed cache\n  - Consider using only local cache instead\n- Cases when all calls to Redis must be synchronized with distributed locks\n\n## Ideas\n\n- Use well-known Spring primitives for implementation\n- Microservices environment needs to fit the requirement of fault tolerance:\n  - Redis calls covered by [Resilience4j Circuit Breaker](https://resilience4j.readme.io/docs/circuitbreaker) which allows falling back to use local cache at the cost of increased latency and more calls to external services.\n- Redis TTL behaves similar to `expireAfterWrite` in Caffeine which allows us to set randomized expiry time for local cache:\n  - This is useful to ensure that local cache entries will expire earlier for a higher chance to hit Redis instead of performing external call.\n  - This also implicitly reduces the load on the Redis by spreading calls to it over time.\n  - In the case of Redis connection errors, randomized expiry and Circuit Breaker will help to mitigate [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).\n- Expiry randomization follows the rule: `(time-to-live / 2) * (1 ± ((expiry-jitter / 100) * RNG(0, 1)))`, for example:\n  - If `spring.cache.multilevel.time-to-live` is `1h`\n  - And `spring.cache.multilevel.local.expiry-jitter` is `50` (percents)\n  - Then entries in local cache will expire in approximately `15-45m`:\n```\n(1h / 2) * (1 ± ((50 / 100) * RNG(0, 1))) -\u003e\n30m * (1 ± MAXRNG(0.5)) -\u003e\n30m * RANGE(0.5, 1.5) -\u003e\n15-45m\n```\n\n## Default configuration\n\n```yaml\nspring:\n  data:\n    redis:\n      host: ${HOST:localhost}\n      port: ${PORT:6379}\n  cache:\n    type: redis\n    \n    # These properties are custom\n    multilevel:\n      # Redis properties\n      time-to-live: 1h\n      use-key-prefix: false\n      key-prefix: \"\"\n      topic: \"cache:multilevel:topic\"\n      # Local Caffeine cache properties\n      local:\n        max-size: 2000\n        expiry-jitter: 50\n        expiration-mode: after-create\n        # other valid values for expiration-mode: after-update, after-read\n      # Resilience4j Circuit Breaker properties for Redis\n      circuit-breaker:\n        failure-rate-threshold: 25\n        slow-call-rate-threshold: 25\n        slow-call-duration-threshold: 250ms\n        sliding-window-type: count_based\n        permitted-number-of-calls-in-half-open-state: 20\n        max-wait-duration-in-half-open-state: 5s\n        sliding-window-size: 40\n        minimum-number-of-calls: 10\n        wait-duration-in-open-state: 2500ms\n```\n\n## Honorable mentions\n\n- [Circuit Breaker Redis Cache by gee4vee](https://github.com/gee4vee/circuit-breaker-redis-cache)\n- [Multilevel cache Spring Boot starter by pig777](https://github.com/pig-mesh/multilevel-cache-spring-boot-starter)\n\n\n## License\n[![FOSSA Status](https://app.fossa.com/api/projects/custom%2B20864%2Fgithub.com%2FSuppieRK%2Fspring-boot-multilevel-cache-starter.svg?type=large\u0026issueType=license)](https://app.fossa.com/projects/custom%2B20864%2Fgithub.com%2FSuppieRK%2Fspring-boot-multilevel-cache-starter?ref=badge_large\u0026issueType=license)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuppierk%2Fspring-boot-multilevel-cache-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsuppierk%2Fspring-boot-multilevel-cache-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsuppierk%2Fspring-boot-multilevel-cache-starter/lists"}