Skip to content

Commit 75c6f27

Browse files
committed
feat: Complete Redis + Memcached integration with Nginx
🚀 Redis + Memcached Integration: - Created Lua modules for Redis and Memcached caching - Integrated dual cache system (Redis primary, Memcached fallback) - Added OpenResty Nginx with Lua support - Custom Dockerfile with all required modules 💾 Advanced Caching: - Redis: 2GB RAM, allkeys-lru policy, connection pooling - Memcached: 1GB RAM, optimized for high concurrency - Nginx proxy cache: 500MB RAM zone, 2GB max size - Lua-based cache logic with JSON serialization ⚡ Performance Features: - Dual cache lookup (Redis → Memcached → Nginx) - Cache hit/miss headers for monitoring - Automatic cache warming - Cache optimization tools - Real-time cache statistics 🔧 Management Tools: - cache-manager.sh: Complete cache management - Redis/Memcached statistics and monitoring - Cache clearing and optimization - Cache warming functionality - Integration with docker-manage.sh 📊 Monitoring: - X-Cache-Status headers (HIT/MISS/EXPIRED) - X-Cache-Backend headers (Redis/Memcached) - Cache hit rates and performance metrics - Real-time cache statistics 🎯 Expected Performance: - TTFB: 5-20ms (cache hit) - Cache hit rate: 95%+ for static content - Dual redundancy for maximum reliability - Automatic failover between cache backends
1 parent 703b97a commit 75c6f27

File tree

9 files changed

+681
-10
lines changed

9 files changed

+681
-10
lines changed

cache-manager.sh

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
#!/bin/bash
2+
# Cache Manager for Bitrix CDN Server
3+
# Author: Chibilyaev Alexandr <[email protected]>
4+
5+
set -e
6+
7+
# Colors
8+
RED='\033[0;31m'
9+
GREEN='\033[0;32m'
10+
YELLOW='\033[1;33m'
11+
BLUE='\033[0;34m'
12+
NC='\033[0m'
13+
14+
echo -e "${BLUE}🗄️ Bitrix CDN Cache Manager${NC}"
15+
echo "================================"
16+
17+
# Redis cache management
18+
redis_stats() {
19+
echo -e "\n${BLUE}📊 Redis Cache Statistics${NC}"
20+
echo "============================="
21+
22+
# Redis info
23+
local redis_info=$(docker exec cdn-redis redis-cli info memory | grep used_memory_human)
24+
echo "Redis memory usage: $redis_info"
25+
26+
# Redis keys count
27+
local keys=$(docker exec cdn-redis redis-cli dbsize)
28+
echo "Redis keys count: $keys"
29+
30+
# Redis hit rate
31+
local hits=$(docker exec cdn-redis redis-cli info stats | grep keyspace_hits | cut -d: -f2 | tr -d '\r')
32+
local misses=$(docker exec cdn-redis redis-cli info stats | grep keyspace_misses | cut -d: -f2 | tr -d '\r')
33+
if [ "$hits" -gt 0 ] || [ "$misses" -gt 0 ]; then
34+
local hit_rate=$(echo "scale=2; $hits * 100 / ($hits + $misses)" | bc -l 2>/dev/null || echo "0")
35+
echo "Redis hit rate: ${hit_rate}%"
36+
fi
37+
38+
# Redis connected clients
39+
local clients=$(docker exec cdn-redis redis-cli info clients | grep connected_clients | cut -d: -f2 | tr -d '\r')
40+
echo "Connected clients: $clients"
41+
42+
# Redis operations per second
43+
local ops=$(docker exec cdn-redis redis-cli info stats | grep instantaneous_ops_per_sec | cut -d: -f2 | tr -d '\r')
44+
echo "Operations per second: $ops"
45+
}
46+
47+
# Memcached cache management
48+
memcached_stats() {
49+
echo -e "\n${BLUE}📊 Memcached Cache Statistics${NC}"
50+
echo "=================================="
51+
52+
# Memcached stats
53+
local memcached_stats=$(docker exec cdn-memcached memcached-tool localhost:11211 stats | head -20)
54+
echo "$memcached_stats"
55+
56+
# Memcached memory usage
57+
local mem_usage=$(docker exec cdn-memcached memcached-tool localhost:11211 stats | grep "bytes" | head -1)
58+
echo "Memory usage: $mem_usage"
59+
60+
# Memcached hit rate
61+
local hits=$(docker exec cdn-memcached memcached-tool localhost:11211 stats | grep "get_hits" | awk '{print $2}')
62+
local misses=$(docker exec cdn-memcached memcached-tool localhost:11211 stats | grep "get_misses" | awk '{print $2}')
63+
if [ "$hits" -gt 0 ] || [ "$misses" -gt 0 ]; then
64+
local hit_rate=$(echo "scale=2; $hits * 100 / ($hits + $misses)" | bc -l 2>/dev/null || echo "0")
65+
echo "Memcached hit rate: ${hit_rate}%"
66+
fi
67+
}
68+
69+
# Nginx cache management
70+
nginx_cache_stats() {
71+
echo -e "\n${BLUE}📊 Nginx Cache Statistics${NC}"
72+
echo "=============================="
73+
74+
# Nginx cache directory size
75+
local cache_size=$(docker exec cdn-nginx du -sh /tmp/nginx_cache 2>/dev/null | awk '{print $1}' || echo "0")
76+
echo "Nginx cache size: $cache_size"
77+
78+
# Nginx cache files count
79+
local cache_files=$(docker exec cdn-nginx find /tmp/nginx_cache -type f 2>/dev/null | wc -l || echo "0")
80+
echo "Nginx cache files: $cache_files"
81+
82+
# Nginx memory usage
83+
local nginx_mem=$(docker stats cdn-nginx --no-stream --format "table {{.MemUsage}}" | tail -1)
84+
echo "Nginx memory usage: $nginx_mem"
85+
}
86+
87+
# Clear Redis cache
88+
clear_redis() {
89+
echo -e "\n${YELLOW}🗑️ Clearing Redis cache...${NC}"
90+
docker exec cdn-redis redis-cli flushall
91+
echo -e "${GREEN}✅ Redis cache cleared${NC}"
92+
}
93+
94+
# Clear Memcached cache
95+
clear_memcached() {
96+
echo -e "\n${YELLOW}🗑️ Clearing Memcached cache...${NC}"
97+
docker exec cdn-memcached memcached-tool localhost:11211 flush_all
98+
echo -e "${GREEN}✅ Memcached cache cleared${NC}"
99+
}
100+
101+
# Clear Nginx cache
102+
clear_nginx() {
103+
echo -e "\n${YELLOW}🗑️ Clearing Nginx cache...${NC}"
104+
docker exec cdn-nginx rm -rf /tmp/nginx_cache/*
105+
echo -e "${GREEN}✅ Nginx cache cleared${NC}"
106+
}
107+
108+
# Clear all caches
109+
clear_all() {
110+
echo -e "\n${YELLOW}🗑️ Clearing all caches...${NC}"
111+
clear_redis
112+
clear_memcached
113+
clear_nginx
114+
echo -e "${GREEN}✅ All caches cleared${NC}"
115+
}
116+
117+
# Cache warming
118+
warm_cache() {
119+
echo -e "\n${BLUE}🔥 Warming up caches...${NC}"
120+
121+
# Warm up with common requests
122+
local urls=(
123+
"/health"
124+
"/nginx_status"
125+
"/upload/resize_cache/test.jpg"
126+
"/upload/resize_cache/test.webp"
127+
"/upload/resize_cache/test.avif"
128+
)
129+
130+
for url in "${urls[@]}"; do
131+
echo "Warming: $url"
132+
curl -s "http://localhost$url" > /dev/null 2>&1 || true
133+
done
134+
135+
echo -e "${GREEN}✅ Cache warming complete${NC}"
136+
}
137+
138+
# Cache optimization
139+
optimize_cache() {
140+
echo -e "\n${BLUE}⚡ Optimizing caches...${NC}"
141+
142+
# Redis optimization
143+
echo "Optimizing Redis..."
144+
docker exec cdn-redis redis-cli config set maxmemory-policy allkeys-lru
145+
docker exec cdn-redis redis-cli config set save ""
146+
147+
# Memcached optimization
148+
echo "Optimizing Memcached..."
149+
# Memcached is already optimized in docker-compose.yml
150+
151+
# Nginx optimization
152+
echo "Optimizing Nginx..."
153+
docker exec cdn-nginx nginx -s reload
154+
155+
echo -e "${GREEN}✅ Cache optimization complete${NC}"
156+
}
157+
158+
# Main function
159+
main() {
160+
case "$1" in
161+
redis-stats)
162+
redis_stats
163+
;;
164+
memcached-stats)
165+
memcached_stats
166+
;;
167+
nginx-cache)
168+
nginx_cache_stats
169+
;;
170+
clear-redis)
171+
clear_redis
172+
;;
173+
clear-memcached)
174+
clear_memcached
175+
;;
176+
clear-nginx)
177+
clear_nginx
178+
;;
179+
clear-all)
180+
clear_all
181+
;;
182+
warm)
183+
warm_cache
184+
;;
185+
optimize)
186+
optimize_cache
187+
;;
188+
*)
189+
echo "Usage: $0 {redis-stats|memcached-stats|nginx-cache|clear-redis|clear-memcached|clear-nginx|clear-all|warm|optimize}"
190+
echo ""
191+
echo "Commands:"
192+
echo " redis-stats - Show Redis cache statistics"
193+
echo " memcached-stats - Show Memcached cache statistics"
194+
echo " nginx-cache - Show Nginx cache statistics"
195+
echo " clear-redis - Clear Redis cache"
196+
echo " clear-memcached - Clear Memcached cache"
197+
echo " clear-nginx - Clear Nginx cache"
198+
echo " clear-all - Clear all caches"
199+
echo " warm - Warm up caches"
200+
echo " optimize - Optimize cache settings"
201+
exit 1
202+
;;
203+
esac
204+
}
205+
206+
# Run
207+
main "$@"

docker-compose.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
services:
66
# NGINX с модулем для обработки изображений
77
nginx:
8-
image: nginx:1.27-alpine
8+
build:
9+
context: ./docker/nginx
10+
dockerfile: Dockerfile
911
container_name: cdn-nginx
1012
restart: unless-stopped
1113
ports:
@@ -23,7 +25,7 @@ services:
2325
soft: 65535
2426
hard: 65535
2527
healthcheck:
26-
test: ["CMD", "sh", "-c", "ps aux | grep 'nginx: master process' | grep -v grep || exit 1"]
28+
test: ["CMD", "curl", "-f", "http://localhost/health"]
2729
interval: 30s
2830
timeout: 10s
2931
retries: 3
@@ -33,6 +35,7 @@ services:
3335
- ./docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
3436
- ./docker/nginx/conf.d:/etc/nginx/conf.d:ro
3537
- ./docker/nginx/html:/usr/share/nginx/html:ro
38+
- ./docker/nginx/lua:/etc/nginx/lua:ro
3639

3740
# SSL сертификаты
3841
- ./docker/ssl:/etc/nginx/ssl:ro

docker-manage.sh

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -341,13 +341,22 @@ main() {
341341
cache)
342342
echo -e "${BLUE}Cache Management${NC}"
343343
echo ""
344-
echo "Available commands:"
345-
echo " redis-stats - Redis cache statistics"
346-
echo " memcached-stats - Memcached statistics"
347-
echo " nginx-cache - Nginx cache statistics"
348-
echo " clear-all - Clear all caches"
349-
echo ""
350-
echo "Usage: ./docker-manage.sh cache [command]"
344+
if [ -n "$2" ]; then
345+
./cache-manager.sh "$2"
346+
else
347+
echo "Available commands:"
348+
echo " redis-stats - Redis cache statistics"
349+
echo " memcached-stats - Memcached statistics"
350+
echo " nginx-cache - Nginx cache statistics"
351+
echo " clear-redis - Clear Redis cache"
352+
echo " clear-memcached - Clear Memcached cache"
353+
echo " clear-nginx - Clear Nginx cache"
354+
echo " clear-all - Clear all caches"
355+
echo " warm - Warm up caches"
356+
echo " optimize - Optimize cache settings"
357+
echo ""
358+
echo "Usage: ./docker-manage.sh cache [command]"
359+
fi
351360
;;
352361
help|*)
353362
print_help

docker/nginx/Dockerfile

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Custom Nginx with Lua support for Redis/Memcached integration
2+
# Author: Chibilyaev Alexandr <[email protected]>
3+
4+
FROM openresty/openresty:1.25.3.1-alpine
5+
6+
# Install additional packages
7+
RUN apk add --no-cache \
8+
curl \
9+
redis-tools \
10+
memcached-tools \
11+
bc
12+
13+
# Install Lua modules
14+
RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-redis
15+
RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-memcached
16+
RUN /usr/local/openresty/luajit/bin/luarocks install lua-cjson
17+
18+
# Create directories
19+
RUN mkdir -p /etc/nginx/lua \
20+
/tmp/nginx_cache \
21+
/var/cache/nginx
22+
23+
# Copy configuration files
24+
COPY nginx.conf /etc/nginx/nginx.conf
25+
COPY conf.d/ /etc/nginx/conf.d/
26+
COPY lua/ /etc/nginx/lua/
27+
COPY html/ /usr/share/nginx/html/
28+
29+
# Set permissions
30+
RUN chown -R nginx:nginx /tmp/nginx_cache /var/cache/nginx
31+
32+
# Health check
33+
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
34+
CMD curl -f http://localhost/health || exit 1
35+
36+
EXPOSE 80 443
37+
38+
CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"]

docker/nginx/conf.d/cdn.conf

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,34 @@ server {
118118
deny all;
119119
}
120120

121-
# Handle resize_cache images - MAXIMUM PERFORMANCE with RAM caching
121+
# Handle resize_cache images - MAXIMUM PERFORMANCE with Redis + Memcached
122122
location ~ ^/upload/resize_cache/.*\.(jpg|jpeg|png|gif|bmp)$ {
123123
# Rate limiting
124124
limit_req zone=images burst=500 nodelay;
125125

126+
# Redis + Memcached cache integration
127+
access_by_lua_block {
128+
local redis_cache = require "redis-cache"
129+
local memcached_cache = require "memcached-cache"
130+
131+
if redis_cache.should_cache() then
132+
local key = redis_cache.generate_cache_key()
133+
local cache_data = redis_cache.get_from_cache(key)
134+
135+
if cache_data then
136+
redis_cache.handle_cache_hit(cache_data)
137+
else
138+
-- Try Memcached as fallback
139+
local memcached_data = memcached_cache.get_from_cache(key)
140+
if memcached_data then
141+
memcached_cache.handle_cache_hit(memcached_data)
142+
else
143+
redis_cache.handle_cache_miss()
144+
end
145+
end
146+
end
147+
}
148+
126149
# PROXY CACHE - ALL IN RAM
127150
proxy_cache ram_cache;
128151
proxy_cache_valid 200 1y;
@@ -150,6 +173,23 @@ server {
150173

151174
# Set correct content type
152175
add_header Content-Type $image_content_type;
176+
177+
# Set cache after response
178+
header_filter_by_lua_block {
179+
local redis_cache = require "redis-cache"
180+
local memcached_cache = require "memcached-cache"
181+
182+
if redis_cache.should_cache() and ngx.var.upstream_cache_status == "MISS" then
183+
local content = ngx.arg[1]
184+
local content_type = ngx.var.image_content_type or "image/jpeg"
185+
local cache_control = "public, immutable, max-age=31536000"
186+
local ttl = 31536000 -- 1 year
187+
188+
-- Set to both Redis and Memcached
189+
redis_cache.handle_cache_set(content, content_type, cache_control, ttl)
190+
memcached_cache.handle_cache_set(content, content_type, cache_control, ttl)
191+
end
192+
}
153193
}
154194

155195
# Handle WebP files with MAXIMUM PERFORMANCE

0 commit comments

Comments
 (0)