-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[TT-5545] issue when retrieving a list of keys attached to an API - alternative solution #7651
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
base: master
Are you sure you want to change the base?
Conversation
… api - alternative solution
|
API Changes --- prev.txt 2025-12-19 09:26:47.587337275 +0000
+++ current.txt 2025-12-19 09:26:37.784371522 +0000
@@ -9829,6 +9829,8 @@
SessionDetail returns the session detail using the storage engine (either in
memory or Redis)
+func (b *DefaultSessionManager) SessionDetailBulk(orgID string, keyNames []string, hashed bool) (map[string]user.SessionState, error)
+
func (b *DefaultSessionManager) Sessions(filter string) []string
Sessions returns all sessions in the key store that match a filter key (a
prefix)
@@ -10771,10 +10773,12 @@
func (l *LDAPStorageHandler) GetListRange(keyName string, from, to int64) ([]string, error)
-func (r *LDAPStorageHandler) GetMultiKey(keyNames []string) ([]string, error)
+func (r *LDAPStorageHandler) GetMultiKey(_ []string) ([]string, error)
func (l *LDAPStorageHandler) GetRawKey(filter string) (string, error)
+func (l *LDAPStorageHandler) GetRawMultiKey(keys []string) ([]string, error)
+
func (l *LDAPStorageHandler) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{})
func (l LDAPStorageHandler) GetSet(keyName string) (map[string]string, error)
@@ -11264,6 +11268,8 @@
func (r *RPCStorageHandler) GetRawKey(keyName string) (string, error)
+func (r *RPCStorageHandler) GetRawMultiKey(keys []string) ([]string, error)
+
func (r *RPCStorageHandler) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{})
func (r RPCStorageHandler) GetSet(keyName string) (map[string]string, error)
@@ -11827,6 +11833,7 @@
UpdateSession(keyName string, session *user.SessionState, resetTTLTo int64, hashed bool) error
RemoveSession(orgID string, keyName string, hashed bool) bool
SessionDetail(orgID string, keyName string, hashed bool) (user.SessionState, bool)
+ SessionDetailBulk(orgID string, keyNames []string, hashed bool) (map[string]user.SessionState, error)
KeyExpired(newSession *user.SessionState) bool
Sessions(filter string) []string
ResetQuota(string, *user.SessionState, bool)
@@ -13382,6 +13389,10 @@
the retrieval was successful. Currently, this method is not implemented and
will cause a panic if invoked.
+func (s *DummyStorage) GetRawMultiKey(keys []string) ([]string, error)
+ GetRawMultiKey retrieves multiple values from the DummyStorage. Since
+ DummyStorage is an in-memory map, we just delegate to GetMultiKey.
+
func (s *DummyStorage) GetRollingWindow(string, int64, bool) (int, []interface{})
GetRollingWindow retrieves data for a specified rolling window; currently
not implemented.
@@ -13434,6 +13445,7 @@
type Handler interface {
GetKey(string) (string, error) // Returned string is expected to be a JSON object (user.SessionState)
GetMultiKey([]string) ([]string, error)
+ GetRawMultiKey([]string) ([]string, error)
GetRawKey(string) (string, error)
SetKey(string, string, int64) error // Second input string is expected to be a JSON object (user.SessionState)
SetRawKey(string, string, int64) error
@@ -13521,6 +13533,12 @@
func (m MdcbStorage) GetRawKey(string) (string, error)
+func (m MdcbStorage) GetRawMultiKey(keys []string) ([]string, error)
+ GetRawMultiKey retrieves multiple values from the MdcbStorage based on a
+ slice of keys. Since MdcbStorage is a wrapper that manages fallback logic
+ between local and RPC layers, this method delegates to GetMultiKey to avoid
+ duplicating that fallback logic.
+
func (m MdcbStorage) GetRollingWindow(key string, per int64, pipeline bool) (int, []interface{})
func (m MdcbStorage) GetSet(key string) (map[string]string, error)
@@ -13633,6 +13651,9 @@
func (r *RedisCluster) GetRawKey(keyName string) (string, error)
+func (r *RedisCluster) GetRawMultiKey(keys []string) ([]string, error)
+ GetRawMultiKey retrieves multiple values using a Pipeline.
+
func (r *RedisCluster) GetRollingWindow(keyName string, per int64, pipeline bool) (int, []interface{})
func (r *RedisCluster) GetSet(keyName string) (map[string]string, error)
@@ -13846,6 +13867,9 @@
func (m *MockHandler) GetRawKey(arg0 string) (string, error)
GetRawKey mocks base method.
+func (m *MockHandler) GetRawMultiKey(arg0 []string) ([]string, error)
+ GetRawMultiKey mocks base method.
+
func (m *MockHandler) GetRollingWindow(key string, per int64, pipeline bool) (int, []any)
GetRollingWindow mocks base method.
@@ -13951,6 +13975,9 @@
func (mr *MockHandlerMockRecorder) GetRawKey(arg0 any) *gomock.Call
GetRawKey indicates an expected call of GetRawKey.
+func (mr *MockHandlerMockRecorder) GetRawMultiKey(arg0 any) *gomock.Call
+ GetRawMultiKey indicates an expected call of GetRawMultiKey.
+
func (mr *MockHandlerMockRecorder) GetRollingWindow(key, per, pipeline any) *gomock.Call
GetRollingWindow indicates an expected call of GetRollingWindow.
|
|
This pull request addresses a critical performance issue (TT-5545) where retrieving a list of API keys filtered by an API ID caused excessive memory consumption and timeouts. The previous implementation loaded all session objects into memory before filtering. This PR refactors the logic to be highly memory-efficient and scalable by first fetching all key identifiers and then processing them in manageable batches. Files Changed AnalysisThe changes span 11 files and introduce a new bulk-processing workflow across the API, authentication, and storage layers:
Architecture & Impact Assessment
Key Filtering FlowsequenceDiagram
participant Client
participant GatewayAPI
participant SessionManager
participant Storage
Client->>GatewayAPI: GET /tyk/keys?api_id=some-api
GatewayAPI->>SessionManager: Sessions(filter) # Get all key IDs
SessionManager-->>GatewayAPI: [key1, key2, ..., keyN]
loop For each batch of 1000 keys
GatewayAPI->>SessionManager: SessionDetailBulk(ctx, batch_keys)
SessionManager->>Storage: GetRawMultiKey(batch_keys)
Storage-->>SessionManager: {key_data_1, key_data_2, ...}
SessionManager-->>GatewayAPI: map[key]SessionState
GatewayAPI->>GatewayAPI: Filter sessions in batch by api_id
end
GatewayAPI-->>Client: 200 OK [filtered_key1, ...]
Scope Discovery & Context ExpansionThe modification of the
The introduction of Metadata
Powered by Visor from Probelabs Last updated: 2025-12-19T09:34:52.851Z | Triggered by: pr_updated | Commit: b219123 💡 TIP: You can chat with Visor using |
Security Issues (1)
Architecture Issues (1)
Performance Issues (4)
Quality Issues (3)
Powered by Visor from Probelabs Last updated: 2025-12-19T09:34:55.614Z | Triggered by: pr_updated | Commit: b219123 💡 TIP: You can chat with Visor using |
… api - fix linter
… api - visor comments
|
… api - visor comments


Description
Related Issue
Motivation and Context
How This Has Been Tested
Screenshots (if appropriate)
Types of changes
Checklist
Ticket Details
TT-5545
Generated at: 2025-12-19 09:26:09