package analyze import ( "fmt" "sync/atomic" "time" "yunyan/utils" ) // statLoc 统计日界时区,由模块 Init 经 setStatLoc 写入(默认 Asia/Shanghai)。 // 埋点(Report)与同步(sync)两侧共用,保证 0 点切日口径一致;未初始化时回退固定 UTC+8。 var statLoc atomic.Value // *time.Location func setStatLoc(loc *time.Location) { statLoc.Store(loc) } func statLocation() *time.Location { if v := statLoc.Load(); v != nil { return v.(*time.Location) } return time.FixedZone("UTC+8", 8*3600) } // dayNumber 把时间转成 YYYYMMDD 形式的统计日(按固定统计时区,跨部署口径一致)。 func dayNumber(t time.Time) uint32 { return utils.StatDayNumber(t, statLocation()) } // ============================ Redis 键 ============================ // keyPrefix 形如 {集群标签}:analyze:{应用ID}:{区域},由 setupKeys 写入; // 多集群 / 多应用 / 多区域共用一套 Redis 时互不串台。 // 用 atomic 保证 setupKeys(启动期) 与 Report(运行期) 间无竞态。 var keyPrefix atomic.Value // string func prefix() string { if p := keyPrefix.Load(); p != nil { return p.(string) } return "" } // indexKey 活跃统计分区的索引集合:成员为 "产品ID:统计日"。 func indexKey() string { return prefix() + ":idx" } // hashKey 某 [产品×日] 累加计数的哈希。 func hashKey(productId, statDay uint32) string { return fmt.Sprintf("%s:%d:%d", prefix(), productId, statDay) } // hllKey 某 [产品×日] 某去重指标的 HyperLogLog。 func hllKey(productId, statDay uint32, metric string) string { return fmt.Sprintf("%s:%d:%d:u:%s", prefix(), productId, statDay, metric) } // partition 索引集合的成员,标识一个 产品:日 分区。 func partition(productId, statDay uint32) string { return fmt.Sprintf("%d:%d", productId, statDay) } // 统计哈希的字段名,与 stats_global_day 表列名保持一致,便于追溯。 const ( fLoginCount = "login_count" fNewUserCount = "new_user_count" fActiveDeviceCount = "active_device_count" fBindDeviceCount = "bind_device_count" fQRActiveCount = "qr_active_count" fOrderCreateCount = "order_create_count" fOrderPaidCount = "order_paid_count" fOrderFailedCount = "order_failed_count" fOrderCreateAmount = "order_create_amount" fOrderPaidAmount = "order_paid_amount" fGrantVipDay = "grant_vip_day" fGrantAiIntegral = "grant_ai_integral" fGrantTradeSecond = "grant_trade_second" fGrantMeetSecond = "grant_meet_second" fAiChatCount = "ai_chat_count" fAiUpToken = "ai_up_token" fAiDownToken = "ai_down_token" fTradeCount = "trade_count" fTradeSecond = "trade_second" fTradeWords = "trade_words" fMeetCount = "meet_count" fMeetSecond = "meet_second" ) // 去重指标的 HLL 名(对应 stats_global_day 的 *_user_count 列)。 const ( uLogin = "login" uActive = "active" uPay = "pay" )