ywxzm03 opened a new pull request, #3611:
URL: https://github.com/apache/dubbo-go/pull/3611
**What this PR does**:
This PR adds a read-through cache for the ZooKeeper Config Center to reduce
repeated ZooKeeper reads from `GetProperties` and `GetInternalProperty`. The
existing `CacheListener` updates or invalidates the cache when configuration
change events are received.
Main changes:
1. Add a configuration cache. Cache keys use the full ZooKeeper path,
including the group and namespace.
2. Add the `config-center.cache-ttl` configuration:
- The default value is `30s`;
- Setting it to `0` disables the cache;
- Negative values and invalid duration formats are rejected.
3. Distinguish between:
- An existing node with empty content;
- A node that does not exist.
4. Read from ZooKeeper on a cache miss, selecting the read method based on
the watch state:
- Use ordinary `Get` when the watch is active;
- Use `GetW` to read the data and register a data watch when the watch is
inactive;
- Use `ExistsW` to watch for node creation when the node does not exist.
5. Let `CacheListener` update the cache when add, update, and delete events
are received:
- Add/update events write the latest content to the cache and refresh the
TTL;
- Delete events cache the node as absent and refresh the TTL.
6. Add an `active` state to track whether the watch for a specific
configuration path is still valid, preventing duplicate watch registration
during TTL refreshes.
7. Clear the configuration cache and reset all watch states to inactive
after a ZooKeeper reconnect. A generation counter prevents reads already in
progress and old watch events from repopulating the cache after reconnection.
8. Fix group/option path handling in `AddListener` and `RemoveListener so
that the read path, listener path, and listener removal path remain consistent.
9. Preserve the existing Base64 configuration behavior. Base64 decoding is
still performed when a value is read from the cache.
This PR also adds tests covering cache behavior, TTL, watch-based updates,
deletion, reconnect handling, generation isolation, and Base64 reads.
**Design options**:
This PR evaluated the following three approaches:
1. TTL-only caching
Advantages:
- Simple to implement;
- Does not require maintaining watch state for individual configuration
paths;
- TTL limits the maximum cache lifetime.
Disadvantages:
- Configuration changes are not reflected in the cache immediately;
- Old values may be returned until the TTL expires;
- ZooKeeper still needs to be accessed periodically;
- It cannot make use of the existing `CacheListener` change notifications.
2. Watch-driven caching only
Advantages:
- Cache updates can be applied promptly after configuration changes;
- Under normal conditions, repeated ZooKeeper reads can be minimized.
Disadvantages:
- ZooKeeper watches are one-shot and must be continuously re-registered;
- Watch registration failures, event content read-back failures, and
reconnect scenarios are more complex;
- If an event is missed or the watch state becomes unreliable, stale
values may remain in the cache for an indefinite period;
- Node absence, node creation, deletion, and rapid recreation must all be
handled.
3. TTL plus watch-driven caching
Advantages:
- Normal configuration changes update the cache promptly through watch
events;
- TTL provides a fallback when watch registration fails, event content
read-back fails, or the client reconnects;
- Ordinary `Get` is used when the watch is active, avoiding duplicate
watch registration;
- `GetW`/`ExistsW` are used to re-establish the watch when it is inactive;
- It is more responsive than the TTL-only approach and more resilient
than the watch-only approach.
Disadvantages:
- The implementation needs to maintain both cache TTLs and per-path watch
state;
- Watch consumption, reconnects, and concurrent reads require additional
lifecycle handling;
- The implementation is more complex than the TTL-only approach.
The TTL plus watch-driven approach was selected because it satisfies all of
the following goals:
- Reduce repeated ZooKeeper reads;
- Reflect configuration changes in the cache promptly;
- Fall back to ZooKeeper through TTL when the watch becomes invalid or fails;
- Reduce the risk of stale cache data after reconnects or event-processing
failures.
**`active` state design**:
ZooKeeper watches are one-shot. After a configuration change is received,
the existing watch is consumed. The cache therefore needs to know whether a
valid watch still exists for each concrete configuration path.
- `active=true`: The path has a valid watch. When the TTL expires, ordinary
`Get` is used to refresh the content without registering another watch.
- `active=false`: The path does not have a valid watch. When the TTL
expires, `GetW` is used to read the content and register a new data watch. If
the node does not exist, `ExistsW` is used to watch for its creation.
This state prevents duplicate watch registration during TTL refreshes and
ensures that watches are re-established after they are consumed.
**Reconnect handling**:
After a ZooKeeper reconnect, the cache content and local watch state
established before the reconnect can no longer be treated as reliable. The
reconnect callback therefore:
1. Clears all configuration cache entries;
2. Resets all concrete-path watch states to inactive;
3. Increments the generation counter;
4. Discards reads that started before the reconnect and old watch events,
preventing old data from being written back into the cache after the reconnect.
The next configuration read after reconnecting accesses ZooKeeper again and
re-establishes the watch based on the current node state.
**Which issue(s) this PR fixes**:
Fixes #3572
**Does this PR introduce a user-facing change?**:
```
None
```
This PR adds the following user-configurable option:
```text
config-center.cache-ttl
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]