我有一个网络应用程序,我的客户要求他想知道。
我提出了两个想法
如果他们是正确的,我想验证我的想法。
这些是客户要求。
谁:访客是谁(例如remoteAddress-IP)
什么时候:访问者什么时候在网络应用程序上做了什么
什么:访客采取了什么确切的行动,例如“按下打印按钮”
其中:哪个页面,例如访问者访问的网址
我的想法1.
只需发出SQL查询即可记录访问该网站的每个人的用户活动。
如果访问者单击了指向页面的链接,则Web应用程序会将用户活动写入数据库并呈现所请求的页面。
我认为这会对用户体验产生不良影响。页面渲染可能会变慢,因为它必须做额外的工作。这种方法最终会发出太多的SQL查询并最终成为一个坏主意吗?
我的想法2.
为每个用户或每个用户活动(例如单击打印按钮)启动新线程。
页面渲染以自己的速度继续进行,并且将在线程中单独完成日志记录。
我认为这可能会创建太多线程。这是一个好主意还是最终会占用太多资源?
我想知道这些是否是一个好的,现实世界的做法。如果有更好的方法,请分享。 :)
答案 0 :(得分:1)
建议1:使用和不使用数据库日志记录系统来配置应用程序。您可能会发现数据库日志记录可以满足您的性能需求,而无需进行重大架构更改或性能调整。
如果您发现自己能够维持吞吐量要求,但偶尔会在高峰时段进行备份,则可以将数据库日志记录移动到单个线程中,并使用java.util.concurrent
中的并发队列传递日志消息。这比为每个日志事件分配一个单独的线程要高效得多。
我怀疑如果你发现性能问题,你会发现成为数据库的瓶颈。但这只是预感 - 你必须描述自己的设置,以找到优点和缺点。
注意:要比较启用和不启用日志记录的性能,您可以在启动时将开/关布尔值或特定日志级别配置为最终静态变量。如果这些条件保证为假,JIT将优化if (loggingEnabled)
或if (logLevel > 3)
块中包含的任何代码。这使得您可以使用和不使用日志记录运行相同的代码,而无需在分析当前(非日志记录)方法时为日志记录代码支付性能损失。
答案 1 :(得分:0)
创意1很好。创建一个实用程序方法以将条目记录到数据库中。因此,每次要记录某些事件时,只需调用此方法即可。不应该占用太多的服务器资源,也不会大大减慢响应时间。
答案 2 :(得分:0)
您的问题描述似乎符合生产者/消费者模式。
您有许多线程处理用户请求,这些请求将生成将信息写入数据库的请求。您将有一个(或可能多个)线程消耗这些请求并将数据写入数据库。
有许多方法可以在Java中实现它。你可以:
ExecutorService
,这将被重用并避免多种开销BlockingQueue
,您将在其中放入来自servlet的日志请求,并在循环中拥有一个(或多个)线程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(...));
}
}
您实例化此类一次,调用.start()
,您就可以记录所需的所有内容。
如果您需要(例如,因为您发现日志请求累积太快),您可以更改while(...)
循环中的逻辑以一次接收更多请求(如果可用),并且您的代码向数据库发出一次写入,或者在单个事务中写入,或类似的事情。
这实际上取决于您的特定情况,但如果您遇到性能问题,则瓶颈将成为数据库。
答案 3 :(得分:0)
出于性能原因,最好将日志处理与页面呈现分开,这最好使用JMS完成。
当用户执行某些操作时,您需要做的就是创建日志对象并使用消息源发送JMS消息(JMS队列应该是合适的)。
在另一端(消息接收器),您需要设置一个消息接收器来接收消息并记录它们(在您的情况下为DB)。
这种解耦确保了对用户活动的最小影响以及对使用操作的可靠记录。
答案 4 :(得分:0)
现代日志框架支持ASYNCHRONOUS登录的想法。例如,有log appender in LogBack支持异步日志记录,响应时间非常长。