也许这是微不足道的,但是我没有发现任何有意义的东西,或者我不知道在哪里看...
(如何)一旦请求特定路径就可以发送curl /任何命令?
遵循这些原则,但实际上会起作用:
location / {
curl --data 'v=1&t=pageview&tid=UA-XXXXXXXX-X&cid=123&dp=hit' https://google-analytics.com/collect
}
答案 0 :(得分:3)
(如评论中所指出),ngx_http_lua_module
可以做到!
location / {
access_by_lua_block {
os.execute("/usr/bin/curl --data 'v=1&t=pageview&tid=UA-XXXXXXXX-X&cid=123&dp=hit' https://google-analytics.com/collect >/dev/null 2>/dev/null")
}
}
请注意,执行将暂停页面加载,直到卷曲完成为止。要在后台运行curl并立即继续页面加载,请在末尾添加一个空格和一个&
,使它看起来像
>/dev/null 2>/dev/null &")
答案 1 :(得分:3)
您要执行的操作-针对服务器上的每个URL请求为Google Analytics(分析)执行新的curl
实例-解决该问题的方法错误:
Nginx本身可以轻松地在任何给定时间为10k +并发连接提供服务,作为下限(即,如果您做正确的话,至少是最低要求),请参阅https://en.wikipedia.org/wiki/C10k_problem。
> li>另一方面,fork
(创建新进程的基础system call)的性能,如果要为每个请求运行curl
,这是必要的,它非常慢,以每秒1k的分叉为上限,例如,如果您做对了,那将是有史以来最快的速度,请参阅Faster forking of large processes on Linux?。
具有更好架构的最佳替代解决方案是什么?
我的建议是通过批处理执行此操作。通过实时执行Google Analytics(分析)并不能真正获得任何收益,延迟5分钟的统计数据就足够了。您可以使用自己选择的编程语言编写一个简单的脚本,以浏览相关的http://nginx.org/r/access_log,收集所需时间段内的数据并发出单个批处理请求(和/或在单个流程中进行多个单独的请求) )访问Google Analytics(分析),并提供最近5分钟内有关每个访问者的必要信息。您可以将其作为守护进程运行,也可以作为cron
作业中的脚本运行,请参见crontab(5)
和crontab(1)
。
或者,如果您仍希望对Google Analytics(分析)进行实时处理(我不建议这样做,因为大多数这些服务本身都是在最终一致性的基础上实现的,也就是说, GA本身并不一定要保证最近XX秒/分钟/小时/等的实时准确统计信息,那么您可能想要实现某种形式的守护程序来实时处理统计信息:
我的建议仍然是在这样的守护进程中使用access_log
,例如,通过您喜欢的编程语言中的tail -f /var/www/logs/access_log
等价物,您将在其中打开{{1} }文件作为流,并在数据到达时和何时到达时对其进行处理。
或者,您可以实现此守护程序以使其本身具有HTTP请求接口,并将每个传入请求复制到您的实际后端以及此额外的服务器。
您可以在非默认的auth_request
或add_after_body
的帮助下,通过nginx对其进行多路复用,以对每个请求进行“免费”子请求。该子请求将转到您的服务器,例如,以Go编写。服务器将至少具有两个 goroutines :一个将进入的请求处理到队列中(通过缓冲的字符串通道实现),立即向客户端发出回复,以确保不延迟nginx上游;另一个人将通过第一个access_log
接收来自第一个的请求,对其进行处理,然后向Google Analytics(分析)发送适当的请求。
最终,无论您采用哪种方式,您都可能仍想实施某种级别的批处理和/或限制,因为我想在某个时候,如果您继续发送Google Analytics(分析)本身,可能会受到限制来自同一个IP地址的请求过多,没有任何批处理实现。根据{{3}}和What is the rate limit for direct use of the Google Analytics Measurement Protocol API?来看,大多数图书馆似乎对每秒要发送给Google的请求数量实施内部限制。
答案 2 :(得分:2)
如果您需要将命中提交给Google Analytics(分析),那么可以轻松完成:Nginx可以即时修改页面HTML,在结束</body>
标记之前嵌入GA代码:
sub_filter_once on;
sub_filter '</body>' "<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXXXXX-X', 'auto');
ga('send', 'pageview');
</script></body>";
location / {
}
此Nginx模块称为sub
。
答案 3 :(得分:1)
这是我最终的做法-基于https://github.com/vorodevops/nginx-analytics-measurement-protocol/tree/master/lua的proxy_pass而不是curl。该代码假定openresty或只是lua安装。不确定注释格式是否兼容(未经测试),因此最好在使用前将其删除。
# pick your location
location /example {
# invite lua to the party
access_by_lua_block {
# set request parameters
local request = {
v = 1,
t = "pageview",
# don' forget to put your own property here
tid = "UA-XXXXXXX-Y",
# this is a "unique" user id based on a hash of ip and user agent, not too reliable but possibly best that one can reasonably do without cookies
cid = ngx.md5(ngx.var.remote_addr .. ngx.var.http_user_agent),
uip = ngx.var.remote_addr,
dp = ngx.var.request_uri,
dr = ngx.var.http_referer,
ua = ngx.var.http_user_agent,
# here you truncate the language string to make it compatible with the javascript format - you'll want either the first two characters like here (e.g. en) or the first five (e.g en_US) with ...1, 5
ul = string.sub(ngx.var.http_accept_language, 1, 2)
}
# use the location.capture thingy to send everything to a proxy
local res = ngx.location.capture( "/gamp", {
method = ngx.HTTP_POST,
body = ngx.encode_args(request)
})
}
}
# make a separate location block to proxy the request away
location = /gamp {
internal;
expires epoch;
access_log off;
proxy_pass_request_headers off;
proxy_pass_request_body on;
proxy_pass https://google-analytics.com/collect;
}