面试题答案
一键面试- Redis EVAL命令特性:
EVAL
命令可以在Redis服务器端执行Lua脚本。Lua脚本在Redis中是原子执行的,这意味着在脚本执行期间,Redis不会执行其他客户端的命令,直到脚本执行完成。
- 保证日志记录数据一致性的方案:
- 避免数据丢失:
- 使用Lua脚本将日志记录操作包装起来。例如,假设日志记录是向Redis的一个列表(List)中添加元素。
local key = KEYS[1] local logMessage = ARGV[1] redis.call('RPUSH', key, logMessage) return 1
- 在客户端使用
EVAL
命令执行该脚本,如在Python中使用redis - py
库:
import redis r = redis.Redis(host='localhost', port = 6379, db = 0) script = """ local key = KEYS[1] local logMessage = ARGV[1] redis.call('RPUSH', key, logMessage) return 1 """ key = 'log - list' log_message = 'This is a log message' result = r.eval(script, 1, key, log_message)
- 由于Lua脚本的原子性,在脚本执行过程中不会被其他客户端干扰,从而保证日志不会丢失。
- 避免重复记录:
- 可以利用Redis的集合(Set)数据结构来实现去重。在Lua脚本中,先检查日志消息是否已经存在于集合中,如果不存在则记录日志。
local keySet = KEYS[1] local keyList = KEYS[2] local logMessage = ARGV[1] local exists = redis.call('SISMEMBER', keySet, logMessage) if exists == 0 then redis.call('SADD', keySet, logMessage) redis.call('RPUSH', keyList, logMessage) return 1 else return 0 end
- 在客户端执行该脚本:
import redis r = redis.Redis(host='localhost', port = 6379, db = 0) script = """ local keySet = KEYS[1] local keyList = KEYS[2] local logMessage = ARGV[1] local exists = redis.call('SISMEMBER', keySet, logMessage) if exists == 0 then redis.call('SADD', keySet, logMessage) redis.call('RPUSH', keyList, logMessage) return 1 else return 0 end """ set_key = 'log - set' list_key = 'log - list' log_message = 'This is a log message' result = r.eval(script, 2, set_key, list_key, log_message)
- 这样,通过集合的唯一性,可以避免重复记录日志,同时由于Lua脚本的原子性,在高并发场景下也能保证数据一致性。
- 避免数据丢失: