日志框架
slf4j:日志接口和门面,记录日志;
JCL:commons logging,和slf4j类似的门面日志;
log4j:第三方日志输出的具体实现;
JUL:Java原生的日志输出;
logback:第三方日志输出,性能由于log4j,也是Spring Boot默认日志框架;
log4j2:第三方日志输出的具体实现,号称目前Java平台性能最好。
slf4j结构如下:
Java 日志框架
路径:java.util.logging
;
- Logger:记录日志;
- Handler:日志输出格式;
- Level:日志的不同等级;
- Formatter:日志信息格式化;
使用示例:
1 | public static void main(String[] args) { |
Tomcat 日志框架
JULI:基于JCL和JUL的处理框架。JVM原生的日志框架是每个JVM用同一份日志配置,但是Tomcat中每个Web应用可能有自己的日志框架;
DirectJDKLog:基于JUL中的Logger类,修改了默认输出格式;
LogFactory:单例,默认使用DirectJDKLog,通过ServiceLoader为Log提供自定义的实现版本;
Handler:
- FileHandler:读写锁实现,在某个特定位置往文件里输出日志;
- AsyncFileHandler:继承自FileHandler,实现了异步写操作,缓存存储通过LinkedBlockingQueue来实现,通过publish方法写入相应文件内。
Formatter:通过format方法将日志记录LogRecord转化成格式化的字符串,JULI提供了三个新的Formatter:
- OnlineFormatter:基本类似于JDK的SimpleFormatter,只不过把所有内容写到了同一行。
- VerbatimFormatter:只记录日志信息,没有任何额外信息;
- JdkLoggerFormatter:格式化了一个轻量级的日志信息。
配置文件:conf/logging.properties;以1catalina.org.apache.juli.AsyncFileHandler
为例:数字是为了区分同一个类的不同实例;catalina、localhost、manager和host-manager是Tomcat用来区分不同系统日志类的标志,后面的字符串表示了handler具体类型,如果需要添加Tomcat服务器的自定义Handler,需要在字符串里添加。接下来是日志等级,目录和文件前缀等。
1 | 1catalina.org.apache.juli.AsyncFileHandler.level = FINE |
Tomcat+Slf4j+Logback
- 去下该地址下载适合自己版本的Tomcat:https://github.com/tomcat-slf4j-logback/tomcat-slf4j-logback/releases/;
- 解压以后分别用bin、conf、lib下的内容替换或者复制到自己原有的Tomcat对应目录里;
- 启动Tomcat,可以看到日志格式已经变了:
1 | 18:06:17.595 INFO {main} [o.a.c.h.Http11NioProtocol] : Initializing ProtocolHandler ["http-nio-8080"] |
Session管理
Session的创建
Context中的interface Manager
,默认实现类是StandardManager
。
主要API:
- load:持久化;
- unload:从磁盘加载;
- getSession:获取该次请求的session,如果参数为ture,不存在时会新建;
class Request
:Tomcat实现了HttpServletRequest的类;class RequestFacade
:具体拿到的类,为了保证安全在Request上做的包装;
Request持有context,context持有manager,manager创建session。
Tomcat中Session的具体实现类是StandardSession,StandardSession implements javax.servlet.http.HttpSession,org.apache.catalina.Session
,所有创建的session都在一个名为sessions的ConcurrentHashMap中。
Session的清理
StandardContext调用StandardManager的后台backgroundProcess完成session的清理。每隔10s启动一次,backgroundProcess调用6(对6进行了取模)次才会执行一次session清理。
Session事件通知
servlet:Session生命周期过程中,要将事件通知监听者:interface HttpSessionListener extends EventListener
。
通过StandardContext中的集合取出HttpSessionListener类型的监听器,依次调用它们的sessionCreated方法或者sessionDestroyed方法。
集群通信
需要将server.xml中集群的一行注释打开:
1 | <!-- |
该配置等同于以下:
1 | <!-- |
集群同通信:组播,即Tomcat启动和运行的时候会周期性(默认500ms)向一组服务器发送组播心跳包,同一个集群的Tomcat都在相同的地址和端口监听这些信息,一定时间(默认3s)内不发送组播报文的节点被认为删除,就将其从本地维护的集群列表中移除。
默认情况下,使用DeltaManager进行集群通信,采用的是All-to-All的工作方式,Session会拷贝到集群内所有服务,集群内数量比较多的时候同步时间较长。
也可以使用BackupManager进行通信,Session只会拷贝到备份节点。
集群时,推荐所有的Tomcat使用相同的配置。
工作过程(Tomcat A和Tomcat B构成集群):
- 当在server.xml中配置了cluster组件时,Tomcat A在启动Host容器时,会关联Cluster组件。如果web应用在web.xml中配置了Distributable时,Tomcat会为此上下文创建一个DeltaManager,Cluster的默认实现SimpleTcpCluster启动Membership和Replication服务;
- Tomcat B启动,前面也是启动Host容器,关联Cluster,然后启动一个由A和B组成的Membership。接着Tomcat B会向A请求Session数据,如果A没用响应,则60s后time out,session完成以前不回响应浏览器请求;
- 用户请求,如果是ReplicationValve filter中配置的请求,就不拦截,否则就会更新session,并利用Replication服务通过TCP连接发送到Tomcat B进行拷贝;拷贝时会拷贝Session中所有可序列化的数据;
- A崩溃,Tomcat B将A从MemberShip中移除,同时负载均衡器会将所有的请求发到Tomcat B;
- B正常提供服务;
- A启动,重复1,2步;
- A接收用户注销请求,同时向B发送session过期的消息;
- B创建session,同步到A;
- A上的session超时过期,B同样过期(只要系统时间保持一致)。
Tomcat原生的集群通信适用于小规模集群。