MST

星途 面试题库

面试题:Redis如何与MySQL配合提升数据查询响应速度

请阐述在实际应用中,如何通过Redis缓存机制提升MySQL数据查询的响应速度,包括数据写入缓存的策略以及缓存更新的方式。
36.1万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

1. 数据写入缓存的策略

  • 直写式(Write-Through)
    • 原理:在写入MySQL数据库的同时,将数据写入Redis缓存。这样能保证缓存和数据库的数据一致性。
    • 示例代码(Python + Flask + SQLAlchemy + Redis)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import redis

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='mysql://user:password@localhost/mydb'
db = SQLAlchemy(app)
r = redis.Redis(host='localhost', port=6379, db = 0)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))

@app.route('/create_user/<name>')
def create_user(name):
    new_user = User(name = name)
    db.session.add(new_user)
    db.session.commit()
    r.set(f'user:{new_user.id}', new_user.name)
    return 'User created successfully'
  • 延迟写(Write-Behind)
    • 原理:先将数据写入Redis缓存,然后由专门的异步任务或线程将数据批量写入MySQL数据库。这种方式可以提高写入性能,但可能会在异步写入前丢失数据。
    • 示例代码(Python + Celery + Redis + SQLAlchemy)
from celery import Celery
from flask_sqlalchemy import SQLAlchemy
import redis

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] ='mysql://user:password@localhost/mydb'
db = SQLAlchemy(app)
r = redis.Redis(host='localhost', port=6379, db = 0)

celery = Celery('tasks', broker='redis://localhost:6379/0')

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))

@celery.task
def write_to_db(user_id, name):
    new_user = User(id = user_id, name = name)
    db.session.add(new_user)
    db.session.commit()

@app.route('/create_user/<name>')
def create_user(name):
    user_id = r.incr('user_counter')
    r.set(f'user:{user_id}', name)
    write_to_db.delay(user_id, name)
    return 'User creation in progress'

2. 缓存更新的方式

  • 主动更新
    • 原理:当MySQL数据库中的数据发生变化(如插入、更新、删除操作)时,主动去更新Redis缓存中的相应数据。
    • 示例代码(以更新为例,Python + Flask + SQLAlchemy + Redis)
@app.route('/update_user/<int:user_id>/<name>')
def update_user(user_id, name):
    user = User.query.get(user_id)
    if user:
        user.name = name
        db.session.commit()
        r.set(f'user:{user_id}', name)
        return 'User updated successfully'
    return 'User not found'
  • 失效模式
    • 原理:为Redis缓存中的数据设置一个过期时间。当数据过期后,下次查询时发现缓存中没有数据,就从MySQL数据库中查询并重新写入缓存。
    • 示例代码(Python + Flask + SQLAlchemy + Redis)
@app.route('/get_user/<int:user_id>')
def get_user(user_id):
    user_name = r.get(f'user:{user_id}')
    if user_name:
        return user_name.decode('utf-8')
    user = User.query.get(user_id)
    if user:
        r.setex(f'user:{user_id}', 3600, user.name) # 设置过期时间为1小时
        return user.name
    return 'User not found'
  • 读写锁(Read - Write Lock)
    • 原理:使用读写锁来控制对缓存和数据库的读写操作。读操作可以并发进行,而写操作时需要先获取写锁,阻止其他读写操作,确保数据一致性。在Redis中可以通过一些脚本或第三方库来模拟读写锁。例如,使用redlock - py库实现分布式读写锁来保护缓存和数据库的读写操作。
    • 示例代码(使用redlock - py库简化示例)
from redlock import Redlock
import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
redlock = Redlock([{
    "host": "localhost",
    "port": 6379,
    "db": 0
}])

# 读操作
def read_data(key):
    lock = redlock.lock('read - lock', 1000)
    if lock:
        data = r.get(key)
        redlock.unlock(lock)
        return data
    return None

# 写操作
def write_data(key, value):
    lock = redlock.lock('write - lock', 1000)
    if lock:
        r.set(key, value)
        # 同时更新数据库操作(这里省略具体数据库操作代码)
        redlock.unlock(lock)
        return True
    return False

3. 通过Redis缓存提升MySQL数据查询响应速度的整体流程

  1. 查询请求到达:应用程序接收到查询请求。
  2. 检查缓存:首先检查Redis缓存中是否有所需数据。如果有,直接返回缓存中的数据,大大提高响应速度。
  3. 缓存未命中:如果Redis缓存中没有所需数据,则从MySQL数据库中查询数据。
  4. 数据写入缓存:从MySQL查询到数据后,将数据写入Redis缓存,以便后续查询可以直接从缓存获取。
  5. 返回数据:将从缓存或数据库获取的数据返回给应用程序。