优化性能

This commit is contained in:
2026-03-05 17:20:44 +08:00
parent effdaaa38b
commit 005f261e03
12 changed files with 99 additions and 28 deletions

View File

@@ -226,4 +226,60 @@ class UserCache
$key = self::sessionUsernamePrefix() . $username; $key = self::sessionUsernamePrefix() . $username;
return Cache::delete($key); return Cache::delete($key);
} }
/** 玩家缓存 key 前缀Token 中间件用,减少重复查库) */
private static function playerCachePrefix(): string
{
return config('api.player_cache_prefix', 'api:player:');
}
private static function playerCacheTtl(): int
{
return (int) config('api.player_cache_ttl', 300);
}
/**
* 按 username 缓存玩家信息(仅 id + username供中间件注入 request->player 后使用)
* 登录/信息变更时需调用 deletePlayerByUsername 失效
*/
public static function setPlayerByUsername(string $username, array $playerRow): bool
{
if ($username === '' || empty($playerRow)) {
return false;
}
$ttl = self::playerCacheTtl();
if ($ttl <= 0) {
return true;
}
$key = self::playerCachePrefix() . $username;
return Cache::set($key, json_encode($playerRow), $ttl);
}
/** 按 username 取缓存玩家,未命中返回 null */
public static function getPlayerByUsername(string $username): ?array
{
if ($username === '') {
return null;
}
if (self::playerCacheTtl() <= 0) {
return null;
}
$key = self::playerCachePrefix() . $username;
$val = Cache::get($key);
if ($val === null || $val === '') {
return null;
}
$data = json_decode((string) $val, true);
return is_array($data) ? $data : null;
}
/** 退出登录或玩家信息变更时删除玩家缓存 */
public static function deletePlayerByUsername(string $username): bool
{
if ($username === '') {
return false;
}
$key = self::playerCachePrefix() . $username;
return Cache::delete($key);
}
} }

View File

@@ -81,6 +81,7 @@ class UserController extends OpenController
return $this->fail('token 无效', ReturnCode::TOKEN_INVALID); return $this->fail('token 无效', ReturnCode::TOKEN_INVALID);
} }
UserCache::deleteSessionByUsername($username); UserCache::deleteSessionByUsername($username);
UserCache::deletePlayerByUsername($username);
return $this->success('已退出登录'); return $this->success('已退出登录');
} }

View File

@@ -84,6 +84,7 @@ class UserLogic
$userArr = $player->hidden(['password'])->toArray(); $userArr = $player->hidden(['password'])->toArray();
UserCache::setUser((int) $player->id, $userArr); UserCache::setUser((int) $player->id, $userArr);
UserCache::setPlayerByUsername($username, $userArr);
$baseUrl = rtrim(config('api.login_url_base', 'https://127.0.0.1:6777'), '/'); $baseUrl = rtrim(config('api.login_url_base', 'https://127.0.0.1:6777'), '/');
$lang = in_array($lang, ['chs', 'en'], true) ? $lang : 'chs'; $lang = in_array($lang, ['chs', 'en'], true) ? $lang : 'chs';

View File

@@ -66,11 +66,20 @@ class TokenMiddleware implements MiddlewareInterface
throw new ApiException('请重新登录(当前账号已在其他处登录)', ReturnCode::TOKEN_INVALID); throw new ApiException('请重新登录(当前账号已在其他处登录)', ReturnCode::TOKEN_INVALID);
} }
// 优先从 Redis 缓存取玩家,避免每次请求都查库
$player = null;
$cached = UserCache::getPlayerByUsername($username);
if ($cached !== null && isset($cached['id'])) {
$player = (new DicePlayer())->data($cached, true);
}
if ($player === null) {
$player = DicePlayer::where('username', $username)->find(); $player = DicePlayer::where('username', $username)->find();
if (!$player) { if (!$player) {
UserCache::deleteSessionByUsername($username); UserCache::deleteSessionByUsername($username);
throw new ApiException('请重新登录', ReturnCode::TOKEN_INVALID); throw new ApiException('请重新登录', ReturnCode::TOKEN_INVALID);
} }
UserCache::setPlayerByUsername($username, $player->hidden(['password'])->toArray());
}
$request->player_id = (int) $player->id; $request->player_id = (int) $player->id;
$request->player = $player; $request->player = $player;
return $handler($request); return $handler($request);

View File

@@ -27,4 +27,7 @@ return [
'user_cache_prefix' => env('API_USER_CACHE_PREFIX', 'api:user:'), 'user_cache_prefix' => env('API_USER_CACHE_PREFIX', 'api:user:'),
// 用户信息加密密钥(用于 Redis 中 value 的加密),建议 32 位 // 用户信息加密密钥(用于 Redis 中 value 的加密),建议 32 位
'user_encrypt_key' => env('API_USER_ENCRYPT_KEY', 'dafuweng_api_user_cache_key_32'), 'user_encrypt_key' => env('API_USER_ENCRYPT_KEY', 'dafuweng_api_user_cache_key_32'),
// 玩家信息按 username 缓存Token 中间件用0 表示不缓存
'player_cache_ttl' => (int) env('API_PLAYER_CACHE_TTL', 300),
'player_cache_prefix' => env('API_PLAYER_CACHE_PREFIX', 'api:player:'),
]; ];

View File

@@ -15,7 +15,8 @@
use support\Request; use support\Request;
return [ return [
'debug' => true, // 生产环境务必设为 false减少 I/O 与堆栈输出,提升接口响应
'debug' => env('APP_DEBUG', false),
'error_reporting' => E_ALL, 'error_reporting' => E_ALL,
'default_timezone' => 'Asia/Shanghai', 'default_timezone' => 'Asia/Shanghai',
'request_class' => Request::class, 'request_class' => Request::class,

View File

@@ -18,10 +18,10 @@ return [
PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers. PDO::ATTR_EMULATE_PREPARES => false, // Must be false for Swoole and Swow drivers.
], ],
'pool' => [ 'pool' => [
'max_connections' => 5, 'max_connections' => (int) env('DB_POOL_MAX', 20),
'min_connections' => 1, 'min_connections' => (int) env('DB_POOL_MIN', 2),
'wait_timeout' => 3, 'wait_timeout' => (float) env('DB_POOL_WAIT_TIMEOUT', 1.0),
'idle_timeout' => 60, 'idle_timeout' => (int) env('DB_POOL_IDLE_TIMEOUT', 60),
'heartbeat_interval' => 50, 'heartbeat_interval' => 50,
], ],
], ],

View File

@@ -20,7 +20,7 @@ return [
'constructor' => [ 'constructor' => [
runtime_path() . '/logs/webman.log', runtime_path() . '/logs/webman.log',
7, //$maxFiles 7, //$maxFiles
Monolog\Logger::DEBUG, env('LOG_LEVEL', Monolog\Logger::INFO),
], ],
'formatter' => [ 'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class, 'class' => Monolog\Formatter\LineFormatter::class,

View File

@@ -7,9 +7,9 @@ return [
'port' => env('REDIS_PORT', 6379), 'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0), 'database' => env('REDIS_DB', 0),
'pool' => [ 'pool' => [
'max_connections' => 5, 'max_connections' => (int) env('REDIS_POOL_MAX', 20),
'min_connections' => 1, 'min_connections' => (int) env('REDIS_POOL_MIN', 2),
'wait_timeout' => 3, 'wait_timeout' => (float) env('REDIS_POOL_WAIT_TIMEOUT', 1.0),
'idle_timeout' => 60, 'idle_timeout' => 60,
'heartbeat_interval' => 50, 'heartbeat_interval' => 50,
], ],

View File

@@ -24,13 +24,13 @@ return [
'tag_expire' => 86400 * 30, 'tag_expire' => 86400 * 30,
// 缓存标签前缀 // 缓存标签前缀
'tag_prefix' => 'tag:', 'tag_prefix' => 'tag:',
// 连接池配置 // 连接池配置(与 redis.php 对齐,生产可调大以减少等待)
'pool' => [ 'pool' => [
'max_connections' => 5, // 最大连接数 'max_connections' => (int) env('REDIS_POOL_MAX', 20),
'min_connections' => 1, // 最小连接数 'min_connections' => (int) env('REDIS_POOL_MIN', 2),
'wait_timeout' => 3, // 从连接池获取连接等待超时时间 'wait_timeout' => (float) env('REDIS_POOL_WAIT_TIMEOUT', 1.0),
'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收 'idle_timeout' => 60,
'heartbeat_interval' => 50, // 心跳检测间隔需要小于60秒 'heartbeat_interval' => 50,
], ],
], ],
// 文件缓存 // 文件缓存

View File

@@ -18,8 +18,7 @@ return [
'hostport' => env('DB_PORT', 3306), 'hostport' => env('DB_PORT', 3306),
// 数据库连接参数 // 数据库连接参数
'params' => [ 'params' => [
// 连接超时3秒 \PDO::ATTR_TIMEOUT => (int) env('DB_CONNECT_TIMEOUT', 2),
\PDO::ATTR_TIMEOUT => 3,
], ],
// 数据库编码默认采用utf8 // 数据库编码默认采用utf8
'charset' => 'utf8', 'charset' => 'utf8',
@@ -29,13 +28,13 @@ return [
'break_reconnect' => true, 'break_reconnect' => true,
// 自定义分页类 // 自定义分页类
'bootstrap' => '', 'bootstrap' => '',
// 连接池配置 // 连接池配置(与 database.php 对齐)
'pool' => [ 'pool' => [
'max_connections' => 5, // 最大连接数 'max_connections' => (int) env('DB_POOL_MAX', 20),
'min_connections' => 1, // 最小连接数 'min_connections' => (int) env('DB_POOL_MIN', 2),
'wait_timeout' => 3, // 从连接池获取连接等待超时时间 'wait_timeout' => (float) env('DB_POOL_WAIT_TIMEOUT', 1.0),
'idle_timeout' => 60, // 连接最大空闲时间,超过该时间会被回收 'idle_timeout' => (int) env('DB_POOL_IDLE_TIMEOUT', 60),
'heartbeat_interval' => 50, // 心跳检测间隔需要小于60秒 'heartbeat_interval' => 50,
], ],
], ],
], ],

View File

@@ -4,8 +4,9 @@ use plugin\saiadmin\app\middleware\SystemLog;
use plugin\saiadmin\app\middleware\CheckLogin; use plugin\saiadmin\app\middleware\CheckLogin;
use plugin\saiadmin\app\middleware\CheckAuth; use plugin\saiadmin\app\middleware\CheckAuth;
// 仅对 /core 后台路由生效,避免 /api 请求经过登录/权限/操作日志中间件,提升接口响应
return [ return [
'' => [ 'core' => [
CheckLogin::class, CheckLogin::class,
CheckAuth::class, CheckAuth::class,
SystemLog::class, SystemLog::class,