MST

星途 面试题库

面试题:Redis队列优化MySQL商品库存更新的高级策略问题

当大量商品库存更新请求涌入Redis队列,导致MySQL更新压力过大,如何通过优化Redis队列的使用以及结合Redis的特性来缓解MySQL压力并保证库存更新的准确性和一致性?
38.5万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试
  1. 批量处理
    • 在Redis中,可以设置一个合适的阈值,例如每收集到100个库存更新请求,再批量从Redis队列中取出数据,一次性更新到MySQL。这样可以减少MySQL的更新次数,降低压力。
    • 示例代码(以Python为例,使用redis - py库和pymysql库):
    import redis
    import pymysql
    
    r = redis.Redis(host='localhost', port=6379, db = 0)
    conn = pymysql.connect(host='localhost', user='user', password='password', database='test')
    cursor = conn.cursor()
    
    batch_size = 100
    while True:
        batch = r.lrange('stock_update_queue', 0, batch_size - 1)
        if not batch:
            break
        update_sql = "UPDATE products SET stock = %s WHERE product_id = %s"
        data = []
        for item in batch:
            product_id, stock = item.decode('utf - 8').split(',')
            data.append((stock, product_id))
        cursor.executemany(update_sql, data)
        conn.commit()
        r.ltrim('stock_update_queue', batch_size, -1)
    conn.close()
    
  2. 使用Redis事务
    • Redis事务可以保证在事务执行期间,一系列操作要么全部成功,要么全部失败。对于库存更新请求,可以将相关操作放入一个Redis事务中,确保数据的一致性。
    • 例如,假设库存更新请求包含商品ID和更新数量,首先从Redis中获取当前库存值,然后在事务中进行更新操作,最后将结果同步到MySQL。
    • 示例代码(以Python为例,使用redis - py库):
    import redis
    
    r = redis.Redis(host='localhost', port=6379, db = 0)
    
    product_id = '123'
    update_amount = 10
    
    pipe = r.pipeline()
    current_stock = pipe.get(product_id)
    if current_stock is None:
        new_stock = update_amount
    else:
        new_stock = int(current_stock.decode('utf - 8'))+update_amount
    pipe.set(product_id, new_stock)
    pipe.execute()
    
    # 后续将新的库存值同步到MySQL
    
  3. 缓存库存数据
    • 将库存数据缓存在Redis中,对于频繁的库存查询请求,直接从Redis中获取数据,减少对MySQL的读压力。
    • 当有库存更新请求时,先更新Redis中的库存数据,再异步更新MySQL。可以使用消息队列(如RabbitMQ、Kafka等)来异步处理MySQL的更新,确保数据最终一致性。
    • 例如,在Python中使用Flask框架处理库存查询和更新:
    from flask import Flask
    import redis
    
    app = Flask(__name__)
    r = redis.Redis(host='localhost', port=6379, db = 0)
    
    @app.route('/stock/<product_id>', methods=['GET'])
    def get_stock(product_id):
        stock = r.get(product_id)
        if stock is None:
            # 从MySQL获取库存并更新到Redis
            # 这里省略MySQL查询代码
            stock = 100
            r.set(product_id, stock)
        return str(stock)
    
    @app.route('/update_stock/<product_id>/<update_amount>', methods=['POST'])
    def update_stock(product_id, update_amount):
        current_stock = r.get(product_id)
        if current_stock is None:
            new_stock = int(update_amount)
        else:
            new_stock = int(current_stock.decode('utf - 8'))+int(update_amount)
        r.set(product_id, new_stock)
        # 将更新请求发送到消息队列,异步更新MySQL
        # 这里省略消息队列发送代码
        return 'Stock updated successfully'
    
    if __name__ == '__main__':
        app.run(debug=True)
    
  4. 限流
    • 利用Redis的原子操作(如INCR)实现限流,限制单位时间内进入MySQL的库存更新请求数量。例如,设置每秒最多允许100个库存更新请求进入MySQL。
    • 示例代码(以Python为例,使用redis - py库):
    import redis
    import time
    
    r = redis.Redis(host='localhost', port=6379, db = 0)
    
    limit = 100
    period = 1  # 秒
    
    def is_allowed():
        key = 'update_limit_key'
        current_count = r.incr(key)
        if current_count == 1:
            r.expire(key, period)
        return current_count <= limit
    
    while True:
        if is_allowed():
            # 从Redis队列取出数据更新MySQL
            # 这里省略更新MySQL代码
            pass
        else:
            time.sleep(0.01)