mdbq 4.0.106__tar.gz → 4.0.107__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mdbq might be problematic. Click here for more details.
- {mdbq-4.0.106 → mdbq-4.0.107}/PKG-INFO +1 -1
- mdbq-4.0.107/mdbq/__version__.py +1 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/redis/redis_cache.py +116 -48
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq.egg-info/PKG-INFO +1 -1
- mdbq-4.0.106/mdbq/__version__.py +0 -1
- {mdbq-4.0.106 → mdbq-4.0.107}/README.txt +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/auth/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/auth/auth_backend.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/auth/rate_limiter.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/js/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/js/jc.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/log/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/log/mylogger.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/myconf/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/myconf/myconf.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/mysql/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/mysql/deduplicator.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/mysql/mysql.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/mysql/s_query.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/mysql/unique_.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/mysql/uploader.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/other/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/other/download_sku_picture.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/other/error_handler.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/other/otk.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/other/pov_city.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/other/ua_sj.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/pbix/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/pbix/pbix_refresh.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/pbix/refresh_all.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/redis/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/redis/getredis.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/route/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/route/analytics.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/route/monitor.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/route/routes.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/selenium/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/selenium/get_driver.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq/spider/__init__.py +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq.egg-info/SOURCES.txt +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq.egg-info/dependency_links.txt +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/mdbq.egg-info/top_level.txt +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/setup.cfg +0 -0
- {mdbq-4.0.106 → mdbq-4.0.107}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = '4.0.107'
|
|
@@ -35,44 +35,57 @@ logger = mylogger.MyLogger(
|
|
|
35
35
|
class CacheConfig:
|
|
36
36
|
"""缓存系统配置类"""
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
38
|
+
def __init__(self, db_name: str = "redis统计", table_name: str = "dpflask路由分析"):
|
|
39
|
+
# TTL配置(秒)
|
|
40
|
+
self.default_ttl = 3600 # 1小时
|
|
41
|
+
self.short_ttl = 300 # 5分钟
|
|
42
|
+
self.medium_ttl = 1800 # 30分钟
|
|
43
|
+
self.long_ttl = 7200 # 2小时
|
|
44
|
+
self.very_long_ttl = 86400 # 24小时
|
|
45
|
+
|
|
46
|
+
# 缓存键前缀
|
|
47
|
+
self.cache_prefix = "smart_cache:"
|
|
48
|
+
self.stats_prefix = "cache_stats:"
|
|
49
|
+
self.lock_prefix = "cache_lock:"
|
|
50
|
+
|
|
51
|
+
# 统计配置
|
|
52
|
+
self.stats_interval = 900 # 统计间隔(秒), 自动提交统计信息到MySQL的间隔
|
|
53
|
+
self.stats_retention = 30 # MySQL统计数据保留天数,超过此天数的数据将被自动删除
|
|
54
|
+
|
|
55
|
+
# 性能配置
|
|
56
|
+
self.max_key_length = 250
|
|
57
|
+
self.max_value_size = 1024 * 1024 # 1MB
|
|
58
|
+
self.batch_size = 100
|
|
59
|
+
|
|
60
|
+
# MySQL数据库配置
|
|
61
|
+
self.db_name = db_name
|
|
62
|
+
self.table_name = table_name
|
|
63
|
+
|
|
64
|
+
# 锁配置
|
|
65
|
+
self.lock_timeout = 30 # 分布式锁超时时间
|
|
66
|
+
self.lock_retry_delay = 0.1 # 锁重试延迟
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
class SmartCacheSystem:
|
|
69
70
|
"""智能缓存系统核心类"""
|
|
70
71
|
|
|
71
|
-
def __init__(self, redis_client: redis.Redis, mysql_pool=None, instance_name: str = "default"
|
|
72
|
+
def __init__(self, redis_client: redis.Redis, mysql_pool=None, instance_name: str = "default",
|
|
73
|
+
config: CacheConfig = None, db_name: str = None, table_name: str = None):
|
|
72
74
|
self.redis_client = redis_client
|
|
73
75
|
self.mysql_pool = mysql_pool
|
|
74
76
|
self.instance_name = instance_name
|
|
75
|
-
|
|
77
|
+
|
|
78
|
+
# 配置优先级:传入的config > 自定义db_name/table_name > 默认配置
|
|
79
|
+
if config:
|
|
80
|
+
self.config = config
|
|
81
|
+
elif db_name or table_name:
|
|
82
|
+
self.config = CacheConfig(
|
|
83
|
+
db_name=db_name or "redis统计",
|
|
84
|
+
table_name=table_name or "dpflask路由分析"
|
|
85
|
+
)
|
|
86
|
+
else:
|
|
87
|
+
self.config = CacheConfig()
|
|
88
|
+
|
|
76
89
|
self.logger = logger
|
|
77
90
|
|
|
78
91
|
# 统计数据
|
|
@@ -126,13 +139,14 @@ class SmartCacheSystem:
|
|
|
126
139
|
try:
|
|
127
140
|
with connection.cursor() as cursor:
|
|
128
141
|
# 创建数据库
|
|
129
|
-
cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{self.config.
|
|
130
|
-
cursor.execute(f"USE `{self.config.
|
|
142
|
+
cursor.execute(f"CREATE DATABASE IF NOT EXISTS `{self.config.db_name}` DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci")
|
|
143
|
+
cursor.execute(f"USE `{self.config.db_name}`")
|
|
131
144
|
|
|
132
145
|
# 创建表(MySQL 8.4+兼容语法)
|
|
133
146
|
create_table_sql = f"""
|
|
134
|
-
CREATE TABLE IF NOT EXISTS `{self.config.
|
|
147
|
+
CREATE TABLE IF NOT EXISTS `{self.config.table_name}` (
|
|
135
148
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
|
149
|
+
`日期` date NOT NULL COMMENT '统计日期',
|
|
136
150
|
`统计时间` datetime NOT NULL COMMENT '统计时间',
|
|
137
151
|
`时间段` varchar(20) NOT NULL COMMENT '时间段标识',
|
|
138
152
|
`缓存命中数` bigint DEFAULT 0 COMMENT '缓存命中次数',
|
|
@@ -152,6 +166,7 @@ class SmartCacheSystem:
|
|
|
152
166
|
`创建时间` timestamp DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
|
|
153
167
|
`更新时间` timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间',
|
|
154
168
|
PRIMARY KEY (`id`),
|
|
169
|
+
KEY `idx_stats_date` (`日期`),
|
|
155
170
|
KEY `idx_stats_time` (`统计时间`),
|
|
156
171
|
KEY `idx_time_period` (`时间段`),
|
|
157
172
|
KEY `idx_hit_rate` (`命中率`),
|
|
@@ -164,8 +179,8 @@ class SmartCacheSystem:
|
|
|
164
179
|
connection.commit()
|
|
165
180
|
|
|
166
181
|
self.logger.info("MySQL数据库表初始化成功", {
|
|
167
|
-
'database': self.config.
|
|
168
|
-
'table': self.config.
|
|
182
|
+
'database': self.config.db_name,
|
|
183
|
+
'table': self.config.table_name
|
|
169
184
|
})
|
|
170
185
|
return True
|
|
171
186
|
|
|
@@ -179,8 +194,8 @@ class SmartCacheSystem:
|
|
|
179
194
|
def _generate_cache_key(self, key: str, namespace: str = "") -> str:
|
|
180
195
|
"""生成缓存键"""
|
|
181
196
|
if namespace:
|
|
182
|
-
return f"{self.config.
|
|
183
|
-
return f"{self.config.
|
|
197
|
+
return f"{self.config.cache_prefix}{namespace}:{key}"
|
|
198
|
+
return f"{self.config.cache_prefix}{key}"
|
|
184
199
|
|
|
185
200
|
def _record_operation(self, operation: str, response_time: float = 0):
|
|
186
201
|
"""记录操作统计"""
|
|
@@ -239,7 +254,7 @@ class SmartCacheSystem:
|
|
|
239
254
|
|
|
240
255
|
try:
|
|
241
256
|
cache_key = self._generate_cache_key(key, namespace)
|
|
242
|
-
ttl = ttl or self.config.
|
|
257
|
+
ttl = ttl or self.config.default_ttl
|
|
243
258
|
|
|
244
259
|
# 序列化值
|
|
245
260
|
if isinstance(value, (dict, list, tuple)):
|
|
@@ -248,7 +263,7 @@ class SmartCacheSystem:
|
|
|
248
263
|
serialized_value = str(value)
|
|
249
264
|
|
|
250
265
|
# 检查值大小
|
|
251
|
-
if len(serialized_value.encode('utf-8')) > self.config.
|
|
266
|
+
if len(serialized_value.encode('utf-8')) > self.config.max_value_size:
|
|
252
267
|
self.logger.warning(f"缓存值过大,跳过设置: {len(serialized_value)} bytes")
|
|
253
268
|
return False
|
|
254
269
|
|
|
@@ -300,7 +315,7 @@ class SmartCacheSystem:
|
|
|
300
315
|
def clear_namespace(self, namespace: str) -> int:
|
|
301
316
|
"""清除指定命名空间的所有缓存"""
|
|
302
317
|
try:
|
|
303
|
-
pattern = f"{self.config.
|
|
318
|
+
pattern = f"{self.config.cache_prefix}{namespace}:*"
|
|
304
319
|
keys = self.redis_client.keys(pattern)
|
|
305
320
|
|
|
306
321
|
if keys:
|
|
@@ -389,6 +404,7 @@ class SmartCacheSystem:
|
|
|
389
404
|
|
|
390
405
|
def _stats_worker(self):
|
|
391
406
|
"""后台统计工作线程"""
|
|
407
|
+
cleanup_counter = 0 # 清理计数器
|
|
392
408
|
while self._stats_running:
|
|
393
409
|
try:
|
|
394
410
|
# 收集统计数据
|
|
@@ -400,11 +416,17 @@ class SmartCacheSystem:
|
|
|
400
416
|
# 清理过期的热点键统计
|
|
401
417
|
self._cleanup_hot_keys()
|
|
402
418
|
|
|
419
|
+
# 每24次统计周期(约2小时)执行一次过期数据清理
|
|
420
|
+
cleanup_counter += 1
|
|
421
|
+
if cleanup_counter >= 24: # 24 * 300秒 = 2小时
|
|
422
|
+
self._cleanup_expired_mysql_data()
|
|
423
|
+
cleanup_counter = 0
|
|
424
|
+
|
|
403
425
|
except Exception as e:
|
|
404
426
|
self.logger.error(f"统计工作线程异常: {e}")
|
|
405
427
|
|
|
406
428
|
# 等待下一个统计间隔
|
|
407
|
-
time.sleep(self.config.
|
|
429
|
+
time.sleep(self.config.stats_interval)
|
|
408
430
|
|
|
409
431
|
def _submit_stats_to_mysql(self, stats_data: Dict[str, Any]):
|
|
410
432
|
"""提交统计数据到MySQL"""
|
|
@@ -416,24 +438,26 @@ class SmartCacheSystem:
|
|
|
416
438
|
connection = self.mysql_pool.connection()
|
|
417
439
|
try:
|
|
418
440
|
with connection.cursor() as cursor:
|
|
419
|
-
cursor.execute(f"USE `{self.config.
|
|
441
|
+
cursor.execute(f"USE `{self.config.db_name}`")
|
|
420
442
|
|
|
421
443
|
# 准备数据
|
|
422
444
|
now = datetime.now()
|
|
445
|
+
date_str = now.strftime("%Y-%m-%d") # 格式: 2024-10-01
|
|
423
446
|
time_period = now.strftime("%Y%m%d_%H%M")
|
|
424
447
|
|
|
425
448
|
insert_sql = f"""
|
|
426
|
-
INSERT INTO `{self.config.
|
|
427
|
-
`统计时间`, `时间段`, `缓存命中数`, `缓存未命中数`, `缓存设置数`,
|
|
449
|
+
INSERT INTO `{self.config.table_name}` (
|
|
450
|
+
`日期`, `统计时间`, `时间段`, `缓存命中数`, `缓存未命中数`, `缓存设置数`,
|
|
428
451
|
`缓存删除数`, `缓存错误数`, `命中率`, `总操作数`, `平均响应时间`,
|
|
429
452
|
`每秒操作数`, `唯一键数量`, `系统运行时间`, `热点键统计`,
|
|
430
453
|
`服务器主机`, `实例名称`
|
|
431
454
|
) VALUES (
|
|
432
|
-
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
|
|
455
|
+
%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
|
|
433
456
|
)
|
|
434
457
|
"""
|
|
435
458
|
|
|
436
459
|
cursor.execute(insert_sql, (
|
|
460
|
+
date_str,
|
|
437
461
|
now,
|
|
438
462
|
time_period,
|
|
439
463
|
stats_data['hits'],
|
|
@@ -474,6 +498,44 @@ class SmartCacheSystem:
|
|
|
474
498
|
sorted_keys = sorted(self.hot_keys.items(), key=lambda x: x[1], reverse=True)
|
|
475
499
|
self.hot_keys = dict(sorted_keys[:1000])
|
|
476
500
|
|
|
501
|
+
def _cleanup_expired_mysql_data(self):
|
|
502
|
+
"""清理过期的MySQL统计数据"""
|
|
503
|
+
if not self.mysql_pool:
|
|
504
|
+
return
|
|
505
|
+
|
|
506
|
+
try:
|
|
507
|
+
connection = self.mysql_pool.connection()
|
|
508
|
+
try:
|
|
509
|
+
with connection.cursor() as cursor:
|
|
510
|
+
cursor.execute(f"USE `{self.config.db_name}`")
|
|
511
|
+
|
|
512
|
+
# 计算过期时间点
|
|
513
|
+
from datetime import timedelta
|
|
514
|
+
expire_date = datetime.now() - timedelta(days=self.config.stats_retention)
|
|
515
|
+
|
|
516
|
+
# 删除过期数据
|
|
517
|
+
delete_sql = f"""
|
|
518
|
+
DELETE FROM `{self.config.table_name}`
|
|
519
|
+
WHERE `统计时间` < %s
|
|
520
|
+
"""
|
|
521
|
+
|
|
522
|
+
cursor.execute(delete_sql, (expire_date,))
|
|
523
|
+
deleted_rows = cursor.rowcount
|
|
524
|
+
connection.commit()
|
|
525
|
+
|
|
526
|
+
if deleted_rows > 0:
|
|
527
|
+
self.logger.info("清理过期MySQL统计数据", {
|
|
528
|
+
'deleted_rows': deleted_rows,
|
|
529
|
+
'expire_date': expire_date.strftime('%Y-%m-%d %H:%M:%S'),
|
|
530
|
+
'retention_days': self.config.stats_retention
|
|
531
|
+
})
|
|
532
|
+
|
|
533
|
+
finally:
|
|
534
|
+
connection.close()
|
|
535
|
+
|
|
536
|
+
except Exception as e:
|
|
537
|
+
self.logger.error(f"清理过期MySQL统计数据失败: {e}")
|
|
538
|
+
|
|
477
539
|
def shutdown(self):
|
|
478
540
|
"""关闭缓存系统"""
|
|
479
541
|
self.logger.info("正在关闭缓存系统...")
|
|
@@ -516,18 +578,24 @@ class CacheManager:
|
|
|
516
578
|
self._initialized = True
|
|
517
579
|
self.logger = logger
|
|
518
580
|
|
|
519
|
-
def initialize(self, redis_client: redis.Redis, mysql_pool=None, instance_name: str = "default"
|
|
581
|
+
def initialize(self, redis_client: redis.Redis, mysql_pool=None, instance_name: str = "default",
|
|
582
|
+
config: CacheConfig = None, db_name: str = None, table_name: str = None):
|
|
520
583
|
"""初始化缓存系统"""
|
|
521
584
|
try:
|
|
522
585
|
self.cache_instance = SmartCacheSystem(
|
|
523
586
|
redis_client=redis_client,
|
|
524
587
|
mysql_pool=mysql_pool,
|
|
525
|
-
instance_name=instance_name
|
|
588
|
+
instance_name=instance_name,
|
|
589
|
+
config=config,
|
|
590
|
+
db_name=db_name,
|
|
591
|
+
table_name=table_name
|
|
526
592
|
)
|
|
527
593
|
self.initialization_error = None
|
|
528
594
|
self.logger.info("缓存管理器初始化成功", {
|
|
529
595
|
'instance_name': instance_name,
|
|
530
|
-
'mysql_enabled': mysql_pool is not None
|
|
596
|
+
'mysql_enabled': mysql_pool is not None,
|
|
597
|
+
'db_name': self.cache_instance.config.db_name,
|
|
598
|
+
'table_name': self.cache_instance.config.table_name
|
|
531
599
|
})
|
|
532
600
|
return self # 支持链式调用
|
|
533
601
|
|
mdbq-4.0.106/mdbq/__version__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VERSION = '4.0.106'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|