Laravel Lighthouse GraphQL查询未命中Redis缓存问题排查
GraphQL缓存未命中问题:已生成缓存但查询耗时仍未优化
问题背景
我有一个GraphQL查询,获取1700条数据耗时约10秒,计划通过设置10分钟TTL的缓存优化性能。已按文档在Query上添加@cache指令,Redis中能看到生成的缓存键且包含结果,但每次请求响应时间仍维持在10秒左右,疑似缓存未命中。
GraphQL查询代码
query GetMapAssets($first: Int, $page: Int) { assets(first: $first, page: $page, where: { AND: [ { column: "mag_id" operator: IS_NOT_NULL } { column: "last_mag_data_id" operator: IS_NOT_NULL } ] }) { paginatorInfo { count currentPage lastPage total } data { id reference lastPosition { latitude longitude } asset_type { id name } state { id } branches { data { id } } sites { data { site_type { id name } } } mag { mag_id } asset_group { id } date_enter_site } } }
Schema定义
extend type Query @guard(with: ["passport", "web"]) { assets( orderBy: _ @orderBy(columns: [ "id", "reference", "buy_value", "asset_type_name", "asset_mag_id", "asset_group_reference", "asset_state_name" ]) where: _ @whereConditions ): [Asset] @paginate(defaultCount: 10, scopes: [ "filterBranch", "assetTypeName", "assetMagId", "assetGroupReference", "assetStateName" ]) @can(ability: "view", model: "App\\Models\\Asset") @cache (private: true, maxAge: 600) asset(reference: String @where(key: "reference"), id: ID @where(key: "id")): Asset @first @can(ability: "view", model: "App\\Models\\Asset") } type Asset { id: ID! mag: Mag @belongsTo company: Company @belongsTo branches( orderBy: _ @orderBy(columns: ["id", "name"]) where: _ @whereConditions ): [Branch] @belongsToMany(type: PAGINATOR) asset_type: AssetType @belongsTo state: AssetState @belongsTo reference: String! buy_value: Float last_mag_data_id: Int asset_group: AssetGroup @belongsTo responsible( orderBy: _ @orderBy(columns: ["id", "name"]) where: _ @whereConditions ): [User] @belongsToMany(relation: "users", type: PAGINATOR) shipping_orders: [ShippingOrder] @hasMany(scopes:["tracked"]) responsibles( orderBy: _ @orderBy(columns: ["id", "name"]) where: _ @whereConditions ): [User] @hasMany(relation: "users", type: PAGINATOR) mag_datas( orderBy: _ @orderBy(columns: ["id", "device_timestamp"]) where: _ @whereConditions ): [MagData] @hasMany(type: PAGINATOR) latestMagData: MagData @hasOne custom_parameters( orderBy: _ @orderBy(columns: ["id", "name"]) where: _ @whereConditions ): [CustomParameter] @morphMany(relation: "custom_parameters", type: PAGINATOR) lastTemperature: MagData lastPosition: MagData @hasOne current_shipping_order: [ShippingOrder] @hasMany(relation: "shipping_orders", scopes: ["tracked"]) sites( orderBy: _ @orderBy(columns: ["id", "name"]) where: _ @whereConditions ): [Site] @belongsToMany(type: PAGINATOR) @can(ability: "view", model: "App\\Models\\Site") previous_sites( orderBy: _ @orderBy(columns: ["id", "name"]) where: _ @whereConditions ): [Site] @belongsToMany(type: PAGINATOR) @can(ability: "view", model: "App\\Models\\Site") date_enter_site: DateTime }
Lighthouse缓存配置
'cache' => [ 'enable' => env('LIGHTHOUSE_CACHE_ENABLE', 'local' !== env('APP_ENV')), 'key' => env('LIGHTHOUSE_CACHE_KEY', 'lighthouse-schema'), 'store' => env('LIGHTHOUSE_CACHE_STORE', null), 'ttl' => env('LIGHTHOUSE_CACHE_TTL', null), ],
Redis中生成的缓存键
1) "company_cache:lighthouse:query:5463d14c79c39a60ba59927e444e37095660a3cc28cf14bf4cc97c2ecb263c34" 2) "company_cache:lighthouse-schema" 3) "company_cache:lighthouse:auth:1:Query::assets:first:2000:page:0:where:{"operator":"=","AND":[{"column":"mag_id","operator":"NotNull"},{"column":"last_mag_data_id","operator":"NotNull"}]}"
排查与解决步骤
1. 确认缓存键参数匹配
- 核对请求参数与缓存键的参数:比如查询实际传的
first是1700,但Redis缓存键里是first:2000,参数不匹配会导致每次生成新缓存,无法命中。确保请求的first、page参数和缓存键中的完全一致。 - 检查
where条件序列化差异:查询中用的是IS_NOT_NULL,缓存键里是NotNull,虽然语义相同,但Lighthouse的缓存键是基于参数序列化结果生成的,要确认请求的where条件序列化后和缓存键中的字符串完全一致。
2. 检查@cache指令配置
- 确认
@cache指令作用范围:@paginate会包装分页结果,@cache放在@paginate之后是正确的,但要确保使用的Lighthouse版本支持对分页字段缓存,避免版本兼容性问题。 - 验证
private: true的影响:private表示缓存是用户专属的,缓存键中的auth:1对应用户ID,测试时要确保使用同一个用户发起请求,否则会无法命中缓存。
3. 验证Lighthouse缓存配置生效
- 确认
LIGHTHOUSE_CACHE_STORE:配置为null时会使用Laravel默认缓存驱动,检查.env中CACHE_DRIVER=redis是否正确设置。 - 开启缓存开关:如果在本地测试,需要手动设置
LIGHTHOUSE_CACHE_ENABLE=true,因为默认配置是local环境不开启。
4. 监听缓存命中事件
在Laravel的AppServiceProvider的boot方法中添加日志监听,确认请求是否真的命中缓存:
Cache::listen(function ($event) { Log::info("Cache event: {$event->event}", ['key' => $event->key]); });
执行查询后查看日志,如果是miss说明缓存键不匹配;如果是hit但仍慢,排查Redis反序列化或其他中间件耗时问题。
5. 其他排查点
- 检查权限逻辑:
@can指令是否在缓存之前执行?如果缓存命中,应该不会走到数据库查询和权限验证的耗时逻辑,若仍耗时,可能是缓存未真正生效。 - 测试Redis性能:用
redis-cli ping测试Redis响应速度,排除Redis本身性能问题。
内容的提问来源于stack exchange,提问作者Radyum
相关产品推荐
相关产品推荐

