关于aws-lambda-haskell-runtime与Amazonka的性能问题:如何获取每个查询的耗时?
解决Amazonka中获取API调用耗时的问题
我之前在使用Amazonka结合Lambda Haskell Runtime时也遇到过类似的性能排查需求,确实默认的Trace日志不会输出每个API调用的耗时。这里有几个可行的方案供你参考:
1. 手动包装send调用(推荐用于API操作级别的耗时统计)
这是最直接且可控的方式,因为Amazonka的所有API请求最终都会通过send函数执行。我们可以写一个包装函数,在调用前后记录时间并计算差值:
import Data.Time.Clock import Network.AWS (AWS, send, Env) import Control.Monad.Reader (runReaderT) -- 包装send函数,返回结果和耗时 timedSend :: Env -> AWS a -> IO (a, NominalDiffTime) timedSend env req = do startTime <- getCurrentTime result <- runReaderT (send req) env endTime <- getCurrentTime let duration = diffUTCTime endTime startTime -- 这里可以替换成你需要的日志输出逻辑,比如写入CloudWatch或者Lambda日志 putStrLn $ "[AWS API] Call took " ++ show duration return (result, duration) -- 使用示例 main = do env <- newEnv Discover (_, duration) <- timedSend env (listBuckets :: AWS ListBucketsResponse) putStrLn $ "List buckets operation took: " ++ show duration
这个方案的优势是:
- 统计的是整个Amazonka API操作的总耗时,包括重试、分页等内部逻辑
- 完全自定义输出格式和处理逻辑,比如可以把耗时上报到监控系统
- 不需要依赖额外库,代码侵入性低
2. 利用http-client中间件(用于底层HTTP请求级别的耗时统计)
Amazonka底层基于http-client实现,所以我们可以通过自定义http-client的ManagerSettings添加中间件,拦截所有HTTP请求并记录耗时:
import Network.HTTP.Client import Network.AWS (newEnv, envManager, Env(..)) import Data.Time.Clock import Data.IORef -- 创建一个带耗时统计的中间件 timingMiddleware :: ManagerSettings -> ManagerSettings timingMiddleware baseSettings = baseSettings { managerModifyRequest = \req -> do -- 在请求发起前记录时间,存在IORef里 startTimeRef <- newIORef =<< getCurrentTime let req' = req { requestUserState = Just startTimeRef } managerModifyRequest baseSettings req' , managerResponseHook = \req resp -> do -- 在响应返回后读取开始时间,计算耗时 case requestUserState req of Just startTimeRef -> do startTime <- readIORef startTimeRef endTime <- getCurrentTime let duration = diffUTCTime endTime startTime uri = show $ getUri req putStrLn $ "[HTTP Request] " ++ uri ++ " took " ++ show duration Nothing -> return () -- 执行原有的响应钩子 managerResponseHook baseSettings req resp } -- 创建带计时中间件的AWS环境 createTimedEnv :: IO Env createTimedEnv = do baseEnv <- newEnv Discover let baseManagerSettings = managerSettings $ envManager baseEnv timedManagerSettings = timingMiddleware baseManagerSettings timedManager <- newManager timedManagerSettings return baseEnv { envManager = timedManager }
这个方案的特点是:
- 统计的是每个底层HTTP请求的耗时,如果Amazonka的API操作包含多次HTTP请求(比如分页、重试),会分别记录
- 全局生效,不需要修改每个
send调用 - 适合排查网络层面的性能问题,比如单个请求的延迟
3. 关于runAWST的补充
runAWST本身并没有提供直接的钩子来记录每个API调用的耗时,不过你可以在runAWST的上下文中使用上面的包装函数,或者传入带计时中间件的Env,就能实现耗时统计的需求。
内容的提问来源于stack exchange,提问作者GlinesMome
相关产品推荐
相关产品推荐

