redis的学习!拿来优化ai客户端
前情回顾
点我回顾前景
在很久很久之前开发了一个ai客户端,已经好久没搞过了都有点忘记写了点什么了...
某天在用的时候,发现一个问题,由于上下文越来越长,每次切换对话的加载时间也越来越长
作为高贵的英专生,我们学习的每一分每一秒都是十分珍贵的
我不允许这样的事情发生,于是我便想到可以用redis来解决这一难题
先介绍一下redis是什么,这里借用知乎的一篇文章
点我去知乎!
Redis,英文全称是Remote Dictionary Server(远程字典服务),是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
与MySQL数据库不同的是,Redis的数据是存在内存中的。它的读写速度非常快,每秒可以处理超过10万次读写操作。因此redis被广泛应用于缓存,另外,Redis也经常用来做分布式锁。除此之外,Redis支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。
也就是说我们可以把mysql中的数据拿出来存在内存中,这样就可以大大加快读取速度
export async function GET(
request: NextRequest,
{ params }: { params: { chatId: string } }
) {
const session = await getServerSession(authOptions)
if (!session?.user) return new Response("Unauthorized", { status: 401 })
const startTime = Date.now();
try {
const redis = redisManager.getClient();
const searchParams = request.nextUrl.searchParams
const limit = parseInt(searchParams.get('limit') || '20')
const before = searchParams.get('before')
const forceRefresh = searchParams.get('forceRefresh') === 'true'
const useCache = !before && isRedisConnected() && !forceRefresh
const cacheKey = `messages:${params.chatId}:${session.user.id}`
console.log(`[GET_MESSAGES] chatId=${params.chatId}, useCache=${useCache}, forceRefresh=${forceRefresh}`)
let responseData;
let retryCount = 0;
const maxRetries = 3;
while (retryCount < maxRetries) {
try {
if (useCache) {
const cachedData = await redis.get(cacheKey)
if (cachedData) {
try {
const parsedData = JSON.parse(cachedData)
if (parsedData.messages &&
Array.isArray(parsedData.messages) &&
parsedData.messages.length > 0 &&
parsedData.messages.every((msg: { id: string; content: string | null; role: string; }) =>
msg.id && msg.content !== null && msg.role
) &&
parsedData.timestamp &&
Date.now() - parsedData.timestamp < 300000) {
const elapsedTime = Date.now() - startTime;
console.log(`[CACHE_HIT] Using cached messages for ${params.chatId} (${parsedData.messages.length} messages) in ${elapsedTime}ms`)
responseData = parsedData;
break;
} else {
console.log(`[CACHE_INVALID] Invalid or incomplete cache data for ${params.chatId}`)
}
} catch (err) {
console.error("[CACHE_ERROR] Invalid cache data:", err)
}
}
}
const dbStartTime = Date.now();
let whereCondition: any = {
chatId: params.chatId,
userId: session.user.id
}
if (before) {
const beforeMessage = await prisma.message.findUnique({
where: { id: before },
select: { createdAt: true }
})
if (beforeMessage) {
whereCondition.createdAt = {
lt: beforeMessage.createdAt
}
}
}
const messages = await prisma.message.findMany({
where: whereCondition,
select: {
id: true,
content: true,
role: true,
createdAt: true,
updatedAt: true,
images: true,
model: true,
reasoning_content: true,
sourceDocs: true,
thinking_start_time: true,
thinking_end_time: true
},
orderBy: { createdAt: 'desc' },
take: limit + 1
})
if (messages.length > 0) {
const hasMore = messages.length > limit
const responseMessages = messages.slice(0, limit).reverse()
responseData = {
messages: responseMessages,
hasMore: hasMore,
timestamp: Date.now()
}
const dbElapsedTime = Date.now() - dbStartTime;
console.log(`[DB_FETCH] Fetched ${responseMessages.length} messages from DB for ${params.chatId} in ${dbElapsedTime}ms`)
if (isRedisConnected() && !before) {
await redis.set(
cacheKey,
JSON.stringify(responseData),
'EX',
300 // 5分钟过期
);
console.log(`[CACHE_UPDATE] Updated cache for ${params.chatId} with ${responseMessages.length} messages`)
}
break;
} else {
console.log(`[DB_FETCH] No messages found in database for ${params.chatId}`)
}
retryCount++;
if (retryCount < maxRetries) {
console.log(`[RETRY] Attempt ${retryCount + 1} of ${maxRetries} for ${params.chatId}`);
await new Promise(resolve => setTimeout(resolve, 1000 * retryCount));
}
} catch (error) {
console.error(`[ERROR] Attempt ${retryCount + 1} failed:`, error);
retryCount++;
if (retryCount < maxRetries) {
await new Promise(resolve => setTimeout(resolve, 1000 * retryCount));
}
}
}
if (!responseData || !responseData.messages) {
console.log(`[NO_MESSAGES] No messages found for ${params.chatId}`);
return new Response(
JSON.stringify({
messages: [],
hasMore: false,
timestamp: Date.now()
}),
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
}
const totalElapsedTime = Date.now() - startTime;
return new Response(JSON.stringify(responseData), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-store',
'X-Cache': responseData ? 'HIT' : 'MISS',
'X-Response-Time': `${totalElapsedTime}ms`
}
})
} catch (error) {
const errorTime = Date.now() - startTime;
console.error(`[GET_MESSAGES] Error in ${errorTime}ms:`, error)
return new Response("Internal Error", { status: 500 })
}
}
初始化一个redis客户端,并加入这一串神秘代码后,便成功了,在加载完一次后,很长一段时间不会再进行加载,这样就不会切换对话导致加载半天了