# SmartPool Database Separation ## Tổng quan SmartPool sử dụng 2 database riêng biệt trong ClickHouse để tối ưu hóa hiệu suất và quản lý: 1. **smart_pool_meta** - Metadata database 2. **smart_pool_logs** - Logs & Analytics database ## Lý do tách riêng ### 1. Performance Optimization - **Metadata database**: Ít thay đổi, truy vấn nhanh, không cần TTL - **Logs database**: Ghi liên tục, volume lớn, có TTL để tự động xóa dữ liệu cũ ### 2. Scalability - Có thể scale từng database độc lập - Logs database có thể dùng cluster riêng với nhiều replica - Metadata database có thể dùng SSD nhanh hơn ### 3. Backup & Maintenance - Backup metadata thường xuyên hơn (quan trọng) - Backup logs ít hơn hoặc không cần (có thể tái tạo) - Maintenance window riêng biệt ### 4. Access Control - Có thể phân quyền riêng cho từng database - Service chỉ đọc metadata không cần quyền ghi logs ## Cấu trúc Database ### smart_pool_meta ``` smart_pool_meta/ ├── proxy_metadata (ReplacingMergeTree) │ ├── id, host, port │ ├── protocol, ip_version, country │ ├── auth_username, auth_password │ └── status, cluster, source │ └── proxy_access_mapping (ReplacingMergeTree) ├── access_token ├── cluster (← Maps to cluster, not proxy_id) └── priority ``` **Đặc điểm:** - Dữ liệu ít thay đổi - Không có TTL - Sử dụng ReplacingMergeTree để update - Truy vấn nhanh với FINAL ### smart_pool_logs ``` smart_pool_logs/ ├── proxy_usage_logs (MergeTree) │ ├── access_token, target_domain │ ├── proxy_id, status_code │ ├── response_time_ms, is_success │ ├── timestamp │ └── TTL: 90 days │ ├── proxy_stats_hourly (AggregatingMergeTree) │ ├── hour, access_token │ ├── target_domain, proxy_id │ └── Aggregate states │ └── mv_proxy_stats_hourly (Materialized View) └── Auto-aggregate from usage_logs ``` **Đặc điểm:** - Ghi liên tục, volume lớn - TTL 90 ngày tự động xóa - Partition by date - Materialized View tự động aggregate ## Configuration ### appsettings.json ```json { "ClickHouse": { "Host": "localhost", "Port": 8123, "MetaDatabase": "smart_pool_meta", "LogsDatabase": "smart_pool_logs", "Username": "default", "Password": "", "UseCompression": true, "CommandTimeout": 30 } } ``` ### Production Recommendations ```json { "ClickHouse": { "Host": "clickhouse-cluster.internal", "Port": 8123, "MetaDatabase": "smart_pool_meta", "LogsDatabase": "smart_pool_logs", "Username": "smartpool_user", "Password": "secure_password", "UseCompression": true, "CommandTimeout": 30 } } ``` ## Code Implementation ### IClickHouseContext Interface ```csharp public interface IClickHouseContext { /// /// Create connection to metadata database /// ClickHouseConnection CreateMetaConnection(); /// /// Create connection to logs database /// ClickHouseConnection CreateLogsConnection(); } ``` ### Repository Usage **ProxyMetadataRepository** - Sử dụng Meta Database: ```csharp using var connection = _clickHouseContext.CreateMetaConnection(); var proxies = await connection.QueryAsync( "SELECT * FROM smart_pool_meta.proxy_metadata FINAL" ); ``` **ProxyLogRepository** - Sử dụng Logs Database: ```csharp using var connection = _clickHouseContext.CreateLogsConnection(); await connection.ExecuteAsync( "INSERT INTO smart_pool_logs.proxy_usage_logs (...) VALUES (...)" ); ``` **Cross-Database Query** - Khi cần enrich data: ```csharp // 1. Query metadata từ meta database using var metaConn = _clickHouseContext.CreateMetaConnection(); var proxyMeta = await metaConn.QueryFirstOrDefaultAsync( "SELECT host, protocol FROM smart_pool_meta.proxy_metadata WHERE id = @id" ); // 2. Insert vào logs database với enriched data using var logsConn = _clickHouseContext.CreateLogsConnection(); await logsConn.ExecuteAsync( "INSERT INTO smart_pool_logs.proxy_usage_logs (...) VALUES (...)" ); ``` ## Query Examples ### Metadata Queries ```sql -- Get all active proxies SELECT * FROM smart_pool_meta.proxy_metadata FINAL WHERE status = 1; -- Get proxy access mapping SELECT * FROM smart_pool_meta.proxy_access_mapping FINAL WHERE access_token = 'your-token'; -- Get proxy by ID SELECT * FROM smart_pool_meta.proxy_metadata FINAL WHERE id = 123; ``` ### Logs Queries ```sql -- Get recent logs SELECT * FROM smart_pool_logs.proxy_usage_logs WHERE timestamp >= now() - INTERVAL 1 HOUR ORDER BY timestamp DESC LIMIT 100; -- Get proxy stats SELECT proxy_id, avgMerge(avg_response_time_state) as avg_time, sumIfMerge(success_count_state) / countMerge(request_count_state) as success_rate FROM smart_pool_logs.proxy_stats_hourly WHERE hour >= now() - INTERVAL 24 HOUR GROUP BY proxy_id; -- Get success rate by domain SELECT target_domain, proxy_id, sumIfMerge(success_count_state) / countMerge(request_count_state) as success_rate FROM smart_pool_logs.proxy_stats_hourly WHERE hour >= now() - INTERVAL 7 DAY GROUP BY target_domain, proxy_id ORDER BY success_rate DESC; ``` ## Migration Guide Nếu bạn đang migrate từ single database: ### 1. Backup dữ liệu cũ ```bash clickhouse-client --query "SELECT * FROM smart_pool.proxy_metadata FORMAT Native" > proxy_metadata.native clickhouse-client --query "SELECT * FROM smart_pool.proxy_access_mapping FORMAT Native" > proxy_access_mapping.native ``` ### 2. Tạo databases mới ```bash clickhouse-client < clickhouse_init.sql ``` ### 3. Import dữ liệu ```bash cat proxy_metadata.native | clickhouse-client --query "INSERT INTO smart_pool_meta.proxy_metadata FORMAT Native" cat proxy_access_mapping.native | clickhouse-client --query "INSERT INTO smart_pool_meta.proxy_access_mapping FORMAT Native" ``` ### 4. Cập nhật configuration Thay đổi `Database` thành `MetaDatabase` và `LogsDatabase` trong appsettings.json ### 5. Deploy code mới Deploy API với code đã cập nhật ## Monitoring ### Disk Usage ```sql -- Check meta database size SELECT database, table, formatReadableSize(sum(bytes)) as size FROM system.parts WHERE database = 'smart_pool_meta' GROUP BY database, table; -- Check logs database size SELECT database, table, formatReadableSize(sum(bytes)) as size FROM system.parts WHERE database = 'smart_pool_logs' GROUP BY database, table; ``` ### Query Performance ```sql -- Slow queries on meta database SELECT query, query_duration_ms, read_rows, read_bytes FROM system.query_log WHERE database = 'smart_pool_meta' AND type = 'QueryFinish' AND query_duration_ms > 1000 ORDER BY query_duration_ms DESC LIMIT 10; ``` ## Best Practices 1. **Metadata Database**: - Sử dụng FINAL trong queries - Cache kết quả ở application layer - Update ít, read nhiều 2. **Logs Database**: - Async insert để không block - Sử dụng batch insert khi có thể - Query từ aggregated tables (proxy_stats_hourly) thay vì raw logs 3. **Connection Management**: - Reuse connections khi có thể - Set appropriate timeout - Handle connection errors gracefully 4. **Security**: - Tạo user riêng cho mỗi database - Phân quyền READ/WRITE phù hợp - Sử dụng SSL trong production ## Troubleshooting ### Connection Issues ```csharp // Test meta connection try { using var conn = _clickHouseContext.CreateMetaConnection(); await conn.ExecuteAsync("SELECT 1"); Console.WriteLine("Meta DB: OK"); } catch (Exception ex) { Console.WriteLine($"Meta DB Error: {ex.Message}"); } // Test logs connection try { using var conn = _clickHouseContext.CreateLogsConnection(); await conn.ExecuteAsync("SELECT 1"); Console.WriteLine("Logs DB: OK"); } catch (Exception ex) { Console.WriteLine($"Logs DB Error: {ex.Message}"); } ``` ### Performance Issues - Check if using correct database - Verify indexes and partitions - Monitor query execution time - Check disk I/O and memory usage ## Summary Việc tách metadata và logs thành 2 database riêng mang lại: ✅ **Performance**: Tối ưu cho từng loại workload ✅ **Scalability**: Scale độc lập ✅ **Maintenance**: Quản lý dễ dàng hơn ✅ **Security**: Phân quyền chi tiết ✅ **Cost**: Tối ưu storage và compute Thiết kế này phù hợp cho production với high-volume logging và real-time analytics.