describe
To put it bluntly, the technology selection is to place a bet, betting that it is easy to use, reliable and can support the business. But the reality is: the new framework is trapped, the new library is unstable, and the performance does not meet the standards... If the architecture does not leave a "return channel" at this time, then it will have to bite the bullet and reconstruct it, wasting time, resources, and manpower.
So we don't talk about how to choose, but talk about"How can I save it if I choose the wrong one?"。
Question answers (core idea)
Interface abstraction: All new functions are isolated through a unified interface, which is easy to replace.
Feature Toggle: Both new and old functions are reserved, and which one is enabled is controlled through the switch.
Grayscale online: Only allow some users to use the new implementation and observe stability.
Technical pilot: First test the edge function and then promote it after success.
Question solution code analysis
We use a common scenario:Cache module replacementFor example, suppose you are now switching from local cache to Redis cache, but are not sure about stability.
Step 1: Abstract cache interface
from abc import ABC, abstractmethod class CacheService(ABC): @abstractmethod def get(self, key): pass @abstractmethod def set(self, key, value): pass
Step 2: Implement two versions
class FileCache(CacheService): def __init__(self): = {} def get(self, key): return (key) def set(self, key, value): [key] = value class RedisCache(CacheService): def __init__(self): = {} def get(self, key): print("Access Redis") return (key) def set(self, key, value): print("Write Redis") [key] = value
Step 3: Switch to implement according to FeatureFlag
import random class FeatureFlags: @staticmethod def use_redis(): # Simulated grayscale release (50% of users use Redis) return () < 0.5 def get_cache_service() -> CacheService: if FeatureFlags.use_redis(): return RedisCache() else: return FileCache()
Step 4: Use the interface for business code, no sense switching
def process_user_data(user_id): cache = get_cache_service() data = (user_id) if not data: data = f"UserData for {user_id}" (user_id, data) return data
Sample tests and results
Let's run a few times to see the effect:
if __name__ == "__main__": for i in range(5): result = process_user_data(f"user_{i}") print(result)
The output result is similar:
Write Redis UserData for user_0 UserData for user_1 Write Redis Write Redis UserData for user_3
This means that some requests have gone from the Redis implementation, and some are still using local cache. We can observe the actual effect, record abnormal indicators, and then gradually promote or fall back.
Time complexity
Single cache
get
orset
Operation: O(1)Overall process time complexity: O(n), n is the number of calls
Space complexity
- Use dictionary to simulate cache, and the space complexity is also O(n)
Summarize
We focused on these core points in this article:
The most fear of "locking" in technology selection is the most important thing, and a fallback mechanism must be reserved
Replacement/switching can be easily achieved using abstract interface + Feature Toggle
Grayscale launch is a key link in risk control
Technical pilots can reduce the cost of "selecting and trampling on pitfalls"
It’s not that you are afraid of mistakes, but that you are afraid that you cannot correct them if you make mistakes.With this "rollback" plan, you can escape even if you bet wrong.
The above is the detailed content of the sample code for using Python to implement a rollback scheme. For more information about Python to implement a rollback scheme, please pay attention to my other related articles!