面试题答案
一键面试存储方式优化
- 使用分布式缓存(如Redis)
- Redis具有高读写性能,适合处理高并发场景下的会话数据。
- 在Rails中,可以使用
redis - rails
gem。首先安装:
gem install redis - rails
- 配置
config/initializers/session_store.rb
:
Rails.application.config.session_store :redis_store, servers: { url: 'redis://localhost:6379/0' }, key: '_myapp_session'
- 数据库存储优化(针对关系型数据库如PostgreSQL)
- 索引优化:如果使用数据库存储会话,确保对与会话相关的关键列(如会话ID)添加索引。例如,在
schema.rb
中:
create_table "sessions", force: :cascade do |t| t.string "session_id", null: false # 其他会话相关字段 t.index ["session_id"], name: "index_sessions_on_session_id", unique: true end
- 分区:对于大型应用,可以考虑对会话表进行分区,按时间或其他维度(如用户ID范围)分区,以减少单个表的大小,提高查询性能。例如,在PostgreSQL中,可以使用范围分区:
CREATE TABLE sessions ( session_id text PRIMARY KEY, user_id int, created_at timestamp ) PARTITION BY RANGE (created_at); CREATE TABLE sessions_2023 PARTITION OF sessions FOR VALUES FROM ('2023 - 01 - 01') TO ('2024 - 01 - 01');
- 索引优化:如果使用数据库存储会话,确保对与会话相关的关键列(如会话ID)添加索引。例如,在
过期策略优化
- 动态过期策略
- 根据用户活动动态调整会话过期时间。可以在
ApplicationController
中添加如下代码:
class ApplicationController < ActionController::Base before_action :update_session_expiry def update_session_expiry if current_user session[:expiry] = Time.now + 30.minutes # 例如,30分钟无活动过期 end end end
- 在视图或其他地方检查会话是否过期:
if session[:expiry] && session[:expiry] < Time.now session.delete :user_id redirect_to new_session_path, notice: '会话已过期,请重新登录' end
- 根据用户活动动态调整会话过期时间。可以在
- 设置合适的默认过期时间
- 在
config/initializers/session_store.rb
中设置默认过期时间:
Rails.application.config.session_store :cookie_store, key: '_myapp_session', expires_in: 1.hour
- 在
并发控制
- 乐观锁
- 当使用数据库存储会话时,利用乐观锁机制。假设会话表有一个
version
字段,在更新会话时:
session = Session.find_by(session_id: session_id) begin session.update!(data: new_data, version: session.version + 1) rescue ActiveRecord::StaleObjectError # 重试逻辑 sleep 0.1 retry end
- 当使用数据库存储会话时,利用乐观锁机制。假设会话表有一个
- 分布式锁(使用Redis)
- 可以使用Redis的
SETNX
(Set if Not eXists)命令实现分布式锁。例如,使用redis - rails
gem:
def update_session_concurrently(session_id, new_data) lock_key = "session_lock:#{session_id}" redis = Rails.cache.store.send(:redis) if redis.set(lock_key, 'locked', nx: true, ex: 5) # 5秒锁过期时间 begin session = Session.find_by(session_id: session_id) session.update!(data: new_data) ensure redis.del(lock_key) end else # 等待或重试 sleep 0.1 retry end end
- 可以使用Redis的