英文:
tracking online users in Golang
问题
很久以前,我用Golang构建了一个网站,现在我想要追踪在线用户。
我想要在没有Redis的情况下使用SessionID来实现这个功能。
对于我的工作,最好的方式是什么?
我编写了一个全局处理器:
type Tracker struct {
http.Handler
}
func NewManager(handler http.Handler) *Tracker {
return &Tracker{Handler: handler}
}
func (h *Tracker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println(r.RemoteAddr)
h.Handler.ServeHTTP(w, r)
}
...
...
srv := &http.Server{
Handler: newTracker(e),
Addr: "127.0.0.1" + port,
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
我认为我可以做的其中一件事是:
在客户端添加一个sessionID,并将其保存在服务器的一个映射中,然后统计在线用户并进行跟踪。
这样做好吗?
英文:
Long time ago , I built a website with Golang , now , I want to track online users.
I want to do this without Redis and working with SessionID.
What is the best way for my work ?
I wrote a global handler :
type Tracker struct {
http.Handler
}
func NewManager(handler http.Handler) *Tracker {
return &Tracker{Handler: handler}
}
func (h *Tracker) ServeHTTP(w http.ResponseWriter, r *http.Request) {
log.Println(r.RemoteAddr)
h.Handler.ServeHTTP(w,r)
}
.
.
.
srv := &http.Server{
Handler: newTracker(e),
Addr: "127.0.0.1" + port,
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Fatal(srv.ListenAndServe())
I think one of work that I can do is :
Add a sessionID in client and save it in a map at server And counting online users and following there.
Is it good and right way ?
答案1
得分: 3
一个全局处理程序、中间件(如果你使用路由包,请查看这个)或者只是在热门页面上调用一个统计函数就足够了。注意排除机器人、RSS点击或其他你不关心的流量。
假设你只有一个进程,并且想要追踪最近5分钟内的在线用户,那么在服务器端使用一个映射就可以了。你可以发放令牌(取决于用户是否允许使用cookie,在每个请求上消耗带宽),或者只是对IP进行哈希(效果很好,可能会略微低估)。然后你需要在一段时间后使其过期,并使用互斥锁来保护它们。重新启动后,计数会丢失,如果运行两个进程,你就无法做到这一点,这是内存存储的缺点,你需要另一个缓存进程来持久化。所以这对于大型网站来说不太适用,但是你可以很容易地转移到使用更持久的存储。
var PurgeInterval = 5 * time.Minute
var identifiers = make(map[string]time.Time)
var mu sync.RWMutex
...
// 对IP + UA进行哈希以保护我们的存储中的匿名性
hasher := sha256.New()
hasher.Write([]byte(ip))
hasher.Write([]byte(ua))
id := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
// 插入当前时间的条目
mu.Lock()
identifiers[id] = time.Now()
mu.Unlock()
...
// 定期清除缓存
mu.Lock()
for k, v := range identifiers {
purgeTime := time.Now().Add(-PurgeInterval)
if v.Before(purgeTime) {
delete(identifiers, k)
}
}
mu.Unlock()
类似这样的实现。
英文:
A global handler, middleware (if you're using a router pkg look at this) or just calling a stats function on popular pages would be enough. Be careful to exclude bots, rss hits, or other traffic you don't care about.
Assuming you have one process, and want to track users online in last 5 mins or something, yes, a map server side would be fine, you can issue tokens (depends on user allowing cookies, takes bandwidth on each request), or just hash ip (works pretty well, potential for slight undercounting). You then need to expire them after some interval, and use a mutex to protect them. On restart you lose the count, if running two processes you can't do this, this is the downside of in memory storage, you need another caching process to persist. So this is not suitable for large sites, but you could easily move to using a more persistent store later.
var PurgeInterval = 5 * time.Minute
var identifiers = make(map[string]time.Time)
var mu sync.RWMutex
...
// Hash ip + ua for anonymity in our store
hasher := sha256.New()
hasher.Write([]byte(ip))
hasher.Write([]byte(ua))
id := base64.URLEncoding.EncodeToString(hasher.Sum(nil))
// Insert the entry with current time
mu.Lock()
identifiers[id] = time.Now()
mu.Unlock()
...
// Clear the cache at intervals
mu.Lock()
for k, v := range identifiers {
purgeTime := time.Now().Add(-PurgeInterval)
if v.Before(purgeTime) {
delete(identifiers, k)
}
}
mu.Unlock()
Something like that.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论