import { Hono } from 'hono'
import { cron } from 'hono/cron'
import mysql from 'mysql2/promise'
// 创建 MySQL 连接池
const pool = mysql.createPool({
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASSWORD || 'password',
database: process.env.DB_NAME || 'cdn_weights',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
const app = new Hono()
// 缓存域名列表和权重
let domainsCache = []
// 刷新缓存函数
async function refreshDomains() {
try {
const [rows] = await pool.query(
'SELECT domain, weight FROM domains WHERE active = 1 ORDER BY id ASC'
)
domainsCache = rows
console.log('Domains cache updated:', domainsCache)
} catch (error) {
console.error('Error refreshing domains:', error)
}
}
// 加权选择算法
function selectWeightedDomain(domains) {
if (domains.length === 0) return null
// 计算总权重
const totalWeight = domains.reduce((sum, domain) => sum + domain.weight, 0)
let random = Math.random() * totalWeight
// 寻找匹配的域名
let current = 0
for (const domain of domains) {
current += domain.weight
if (random <= current) {
return domain
}
}
// 兜底返回最后一个
return domains[domains.length - 1]
}
// 每小时刷新一次缓存
cron('0 */1 * * *', async () => {
await refreshDomains()
})
// 初始化时立即刷新缓存
refreshDomains().catch(console.error)
// 图片请求处理
app.get('/image/*', async (c) => {
const domains = domainsCache
if (domains.length === 0) {
return c.text('No available CDN domains', 503)
}
const selectedDomain = selectWeightedDomain(domains)
const imagePath = c.req.path
// 构建 CDN URL
const cdnUrl = `https://${selectedDomain.domain}${imagePath}`
// 可以选择直接重定向或代理请求
return c.redirect(cdnUrl, 302)
})
// 管理接口:更新域名权重
app.post('/admin/domain/:domain', async (c) => {
const domain = c.req.param('domain')
const { weight } = await c.req.json()
try {
await pool.query(
'UPDATE domains SET weight = ? WHERE domain = ?',
[weight, domain]
)
await refreshDomains() // 立即刷新缓存
return c.json({ success: true, message: 'Domain updated' })
} catch (error) {
console.error('Update domain error:', error)
return c.json({ success: false, message: 'Update failed' }, 500)
}
})
// 启动服务器
const port = process.env.PORT || 3000
console.log(`Server running on port ${port}`)
export default {
port,
fetch: app.fetch
}
MySQL 表结构:
CREATE TABLE domains (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
domain VARCHAR(255) NOT NULL UNIQUE,
weight INT NOT NULL DEFAULT 1,
active TINYINT(1) NOT NULL DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
环境变量 (.env):
text
Copy Code
DB_HOST=localhost
DB_USER=your_user
DB_PASSWORD=your_password
DB_NAME=cdn_weights
PORT=3000
功能说明:
加权轮询算法:通过概率分布实现权重分配,保证高权重域名被更频繁选中 缓存机制:定时刷新域名数据,减少数据库压力 健康检查:通过 active 字段控制域名可用性 管理接口:提供实时更新域名权重的 API 自动重定向:根据权重选择最优 CDN 域名进行重定向 使用示例:
添加测试数据:
sql
Copy Code
INSERT INTO domains (domain, weight) VALUES
('cdn1.example.com', 3),
('cdn2.example.com', 2),
('cdn3.example.com', 1);
更新域名权重:
bash
Copy Code
curl -X POST -H "Content-Type: application/json" -d '{"weight":5}' http://localhost:3000/admin/domain/cdn1.example.com
优化建议:
添加域名健康检查机制,自动更新 active 状态
实现 JWT 认证保护管理接口
增加请求日志记录和分析
添加速率限制防止滥用
实现平滑权重调整算法(如动态权重调整)
这个方案通过组合 MySQL 的持久化存储和 Hono 的高性能路由处理,实现了灵活可配置的加权 CDN 分发系统。管理员可以通过数据库直接管理 CDN 节点权重,系统会自动根据配置的权重值进行流量分配。