Java web应用程序的真实世界用户活动日志记录策略
我有一个web应用程序,我的客户请求他知道。Java web应用程序的真实世界用户活动日志记录策略,java,multithreading,tomcat,Java,Multithreading,Tomcat,我有一个web应用程序,我的客户请求他知道。 我想出了两个主意。 我想验证我的想法是否正确。 这些是客户的要求。 谁:访问者是谁(如remoteAddress IP) 何时:访问者何时在web应用程序上执行操作 内容:访问者采取了什么具体行动,例如“按下打印按钮” 其中:哪一页,例如访问者访问的URL 我的想法1. 只需发出一个SQL查询来记录访问网站的每个人的用户活动。 如果访问者单击指向页面的链接,web应用程序会将用户活动写入数据库并呈现请求的页面。 我认为这将对用户体验产生不良影响。页
我想出了两个主意。
我想验证我的想法是否正确。
这些是客户的要求。
谁:访问者是谁(如remoteAddress IP)
何时:访问者何时在web应用程序上执行操作
内容:访问者采取了什么具体行动,例如“按下打印按钮”
其中:哪一页,例如访问者访问的URL
我的想法1.
只需发出一个SQL查询来记录访问网站的每个人的用户活动。 如果访问者单击指向页面的链接,web应用程序会将用户活动写入数据库并呈现请求的页面。
我认为这将对用户体验产生不良影响。页面呈现可能会变慢,因为它必须做额外的工作。这种方法最终会发出太多SQL查询并最终成为一个坏主意吗?
我的想法2.
为每个用户或每个用户活动(如单击“打印”按钮)启动一个新线程。 页面渲染以自己的速度进行,日志记录将在线程中单独完成。
我认为这可能会创建太多线程。这是一个好主意还是会占用太多资源
我想知道这些是否是一个好的,现实世界的做法。如果有更好的方法,请分享。:) 想法1很好。创建一个实用程序方法,将条目记录到数据库中。所以每次你想记录一些事件,只要调用这个方法。不应该占用太多服务器资源,也不会显著降低响应时间。想法1很好。创建一个实用程序方法,将条目记录到数据库中。所以每次你想记录一些事件,只要调用这个方法。不应占用太多服务器资源,也不会显著降低响应时间。建议1:使用或不使用数据库日志记录系统评测应用程序。您可能会发现,DB日志记录可以满足您的性能需求,而无需进行重大的体系结构更改或性能调整 如果您发现自己能够满足吞吐量要求,但偶尔会在高峰时段进行备份,则可以将DB日志记录移动到单个线程中,并使用
java.util.concurrent
中的并发队列传递日志消息。这将比为每个日志事件分叉一个单独的线程更有效
我的怀疑是,如果发现性能问题,就会发现瓶颈是数据库。但这只是一种预感——你必须对自己的设置进行分析,以找出优势和劣势
注意:要比较启用和不启用日志记录时的性能,可以在启动时将开/关布尔值或特定日志级别配置为最终静态变量。JIT将优化包含在
if(loggingEnabled)
或if(logLevel>3)
块中的任何代码,前提是这些条件保证为false。这使您可以在使用和不使用日志记录的情况下运行相同的代码,而无需在分析当前(非日志记录)方法时为日志记录代码支付性能惩罚。建议1:使用和不使用数据库日志记录系统来分析应用程序。您可能会发现,DB日志记录可以满足您的性能需求,而无需进行重大的体系结构更改或性能调整
如果您发现自己能够满足吞吐量要求,但偶尔会在高峰时段进行备份,则可以将DB日志记录移动到单个线程中,并使用java.util.concurrent
中的并发队列传递日志消息。这将比为每个日志事件分叉一个单独的线程更有效
我的怀疑是,如果发现性能问题,就会发现瓶颈是数据库。但这只是一种预感——你必须对自己的设置进行分析,以找出优势和劣势
注意:要比较启用和不启用日志记录时的性能,可以在启动时将开/关布尔值或特定日志级别配置为最终静态变量。JIT将优化包含在
if(loggingEnabled)
或if(logLevel>3)
块中的任何代码,前提是这些条件保证为false。这使您可以在有日志记录和无日志记录的情况下运行相同的代码,而无需在分析当前(非日志记录)方法时为日志记录代码支付性能惩罚。对问题的描述似乎符合生产者/消费者模式
您有许多线程处理用户请求,这些请求将生成将信息写入数据库的请求。您将有一个(或多个)线程使用这些请求,并将数据写入数据库
有很多方法可以在Java中实现这一点。你可以:
- 每次要将一条信息记录到数据库中时,都要启动一个新线程
- 使用一个共享的
,线程数量有限,这样可以重复使用并避免各种开销ExecutorService
- 使用一个共享的
,您将在其中放置来自servlet的日志请求,并使一个(或多个)线程BlockingQueue
元素处于循环中,并根据您获取的元素将数据写入数据库take()
RequestLogger
类中,例如:
public class RequestLogger {
private final Thread thread;
private final BlockingQueue<LogRequest> logRequestQueue = new LinkedBlockingQueue<>();
public RequestLogger() {
this.thread = new Thread(new Runnable() {
@Override public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
final LogRequest req = logRequestQueue.take();
// ... log it to the database somehow ...
}
} catch (Exception e) { ... do something ... }
}
});
}
public void start() { thread.start(); }
public void stop() { thread.interrupt(); }
public void log(...) {
logRequestQueue.offer(new LogRequest(...));
}
}
公共类请求记录器{
专用终螺纹;
private final BlockingQueue logRequestQueue=新建LinkedBlockingQueue();
公共请求记录器(){
this.thread=新线程(new Runnable()){
@重写公共无效运行(){
试一试{
而(!Thread.currentThread().isInterrupted()){
final LogRequest req=logRequestQueue.take();
//…以某种方式将其记录到数据库中。。。
}
}捕获(例外)