企业级web应用服务器TOMCAT入门详解

发布于:2025-08-10 ⋅ 阅读:(17) ⋅ 点赞:(0)

一. web

1.1 为什么“网页里的应用”≈“Tomcat 里的应用”?

  1. 浏览器只认识 HTTP。
    你在地址栏敲 http://xxx.com/login,浏览器发出去的就是一段纯文本 HTTP 报文。

  2. Tomcat 天生吃 HTTP。
    它实现了 JavaEE 里的 Servlet 规范:把 HTTP 请求封装成 HttpServletRequest → 交给程序员写的 LoginServlet → 生成 HTML → 再按 HTTP 格式返回。
    于是“浏览器 ↔ HTTP ↔ Tomcat ↔ 你的业务代码”这一条路就打通了。

  3. 因此,只要最终是通过浏览器访问的,几乎都可以说“由 Tomcat(或同类 Web 服务器)实现”。


1.2 B/S 与 C/S 的“空间之争”

维度 C/S B/S
客户端 必须安装专门软件(QQ、Steam、银行 U 盾) 只用浏览器
升级 每台电脑都要重新装包 改服务器就行
磁盘占用 客户端几百 MB 起步 0 MB(浏览器不算)
网络协议 随意(TCP/UDP、自定义) 只用 HTTP/HTTPS
代表场景 游戏、实时交易 论坛、OA、博客、后台管理

结论:
“节省磁盘空间”只是 B/S 最直观的优势,真正让它统治世界的是 零安装、零维护、跨平台


1.3、三大核心技术到底各干什么?

  1. HTML(骨架)
    纯文本的标签积木:<form><input><table>……告诉浏览器“这里有个登录框,那里放个按钮”。

  2. CSS(皮肤)
    同一段 HTML,可以换不同 CSS 立刻变成“极简风”或“赛博朋克”。
    例:

    css

    复制

    input[type=text] {
        border-radius: 8px;
        box-shadow: 0 0 10px #00f;
    }
  3. JavaScript(肌肉)
    让页面“动起来”:

    • 表单实时校验(失焦就提示“密码太短”)

    • Ajax 异步拉数据(下面细讲)

    • 动画、游戏、可视化……

浏览器拿到 .html → 边解析边向服务器要 .css.js渲染引擎把三者拼成你看到的像素。


1.4、同步交互:整页刷新之痛

经典场景:注册页面
流程:

  1. 填 8 个字段 → 点【提交】

  2. 浏览器整页 POST 给服务器

  3. 服务器发现“两次密码不一致”

  4. 返回一个全新 HTML 页面

  5. 浏览器重新渲染 → 前 7 个字段全清空
    这就是“同步”——一次 HTTP 请求对应一次完整页面刷新。

缺点:

  • 带宽浪费(CSS/JS/图片全部重传)

  • 体验差(用户想骂人)


1.5、异步交互:Ajax 的魔法

  1. 关键技术:XMLHttpRequest(浏览器内置 API)。
    浏览器悄悄再开一条 HTTP 连接,只拿回 需要的那一小块数据(JSON/HTML 片段),然后用 JS 把页面局部更新。
    用户无感刷新。

  2. 流程对比:

    • 同步:填表单 → 提交 → 等待 → 整页刷新

    • 异步:输完邮箱 → JS 立即发请求 /checkEmail?email=xxx → 返回 {"ok":false,"msg":"已注册"} → 页面只把提示字变红,其他不动

  3. 关键词:

    • Ajax(Asynchronous JavaScript And XML)

    • 现在多用 JSON 代替 XML

    • 衍生:Fetch API、Axios、jQuery.ajax()


1.6、从“代码”到“网页”的完整链路

  1. 你在 IDEA 写 LoginServlet.java,继承 HttpServlet,处理 POST /login

  2. mvn package 打成 war → 扔到 Tomcat 的 webapps

  3. 浏览器访问 http://域名/login.html

  4. Tomcat 把 login.html 吐给浏览器(HTML+CSS+JS)。

  5. 用户填完账号密码,JS 用 Ajax POST /login

  6. LoginServlet 查询数据库 → 返回 JSON {status:0,token:xxx}

  7. JS 把 token 存 localStorage,页面跳转到 /index.html,全程无整页刷新。

二 tomcat

#安装java环境
[root@tomcat ~]# yum install java-1.8.0-openjdk.x86_64 -y
 #查看java版本
[root@tomcatA ~]# java -version
 openjdk version "1.8.0_402"
 OpenJDK Runtime Environment (build 1.8.0_402-b06)
 OpenJDK 64-Bit Server VM (build 25.402-b06, mixed mode)
 #查看java的环境目录
[root@tomcatA ~]# which  java
 /usr/bin/java
 [root@tomcatA ~]# ll /usr/bin/java
 lrwxrwxrwx 1 root root 22 Jul 30 10:41 /usr/bin/java -> /etc/alternatives/java
 #java的运行环境
[root@tomcatA ~]# cd /etc/alternatives/jre
 [root@tomcatA jre]# ls
 ASSEMBLY_EXCEPTION  bin  lib  LICENSE  THIRD_PARTY_README
#解压并生成tomcat的程序目录
[root@tomcatA ~]# tar zxf apache-tomcat-9.0.107.tar.gz -C /usr/local/
 [root@tomcatA ~]# cd /usr/local/
 [root@tomcatA local]# ls
 apache-tomcat-9.0.107  bin  etc  games  include  lib  lib64  libexec  sbin  share  
src
 [root@tomcatA local]# mv apache-tomcat-9.0.107/ tomcat
 [root@tomcatA local]# ls
bin  etc  games  include  lib  lib64  libexec  sbin  share  src  tomcat
 #启动tomcat
 [root@tomcatA local]# cd tomcat/
 [root@tomcatA tomcat]# cd bin/
 [root@tomcatA bin]# ls
 bootstrap.jar       
commons-daemon-native.tar.gz  makebase.sh       
juli.jar
 catalina.bat        
native.tar.gz
 catalina.sh         
configtest.bat                
configtest.sh                 
wrapper.bat
 catalina-tasks.xml  daemon.sh                     
wrapper.sh
 ciphers.bat         
ciphers.sh          
digest.bat                    
digest.sh                     
commons-daemon.jar  makebase.bat                  
tomcat
setclasspath.bat  tomcat
setclasspath.sh   
shutdown.bat      
shutdown.sh       
startup.bat       
startup.sh
 [root@tomcatA bin]# ./startup.sh
 Using CATALINA_BASE:   /usr/local/tomcat
 Using CATALINA_HOME:   /usr/local/tomcat
 Using CATALINA_TMPDIR: /usr/local/tomcat/temp
 Using JRE_HOME:        
/usr
 tool
tool
version.bat
 version.sh
 Using CLASSPATH:       
/usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
 Using CATALINA_OPTS:
 Tomcat started.

[root@tomcat ~]# netstat -antlupe | grep java      

安装JAVA环境

java版本查看

查看java真正的环境目录

jre真正的运行环境

要把java的运行环境指定给Tomcat

安装tomcat:

解压并重命名

进入目录并启动它

启动成功后查看端口

测试:

在另一台主机上也要做

简单一点就直接复制了


编写启动程序

创建专用系统用户

useradd -r -s /sbin/nologin -M tomcat

统一目录权限

chown -R tomcat:tomcat /usr/local/tomcat

写入环境变量(Tomcat 专用)


文件:/usr/local/tomcat/conf/tomcat.conf
内容只有一行:

JAVA_HOME=/etc/alternatives/jre


生成 systemd 单元文件


文件:/lib/systemd/system/tomcat.service

[Unit]
Description=Apache Tomcat
After=syslog.target network.target

[Service]
Type=forking
EnvironmentFile=/usr/local/tomcat/conf/tomcat.conf
ExecStart=/usr/local/tomcat/bin/startup.sh
ExecStop=/usr/local/tomcat/bin/shutdown.sh
PrivateTmp=true
User=tomcat
Group=tomcat

[Install]
WantedBy=multi-user.target

启动并设为开机自启

systemctl daemon-reload
systemctl enable --now tomcat   # 立即启动 + 开机自启
systemctl status tomcat         # 查看运行状态

一键验证

ss -lntp | grep java            # 应看到 8080 端口
curl -I http://localhost:8080   # 返回 200 OK

内容中制定用户了,所以这里要建立用户

要给tomcat指定java的运行环境

报错情况:

此时是没有运行这个文件的权限

查看权限

加权限

测试:

2.2 结合反向代理实现tomcat部署

  1. 浏览器里看到的“网页应用”≈ Nginx + Tomcat 这对黄金搭档在干活,而 Nginx 负责反向代理 / 负载均衡,Tomcat 负责跑 Java 代码
    为了不丢登录态,还要解决 Session 一致性 问题。


  1. 什么是“反向代理”?


  • 正反向区别一句话:

    • 正向代理:帮 客户端 去访问外网(翻墙)。

    • 反向代理:帮 服务端 接收外网请求(统一入口)。

  • 为什么要反向代理 Tomcat?

    1. 端口统一:浏览器只认 80/443,Tomcat 默认 8080。

    2. 动静分离:Nginx 处理静态文件(css/js/png)速度是 Tomcat 的 10 倍。

    3. 安全:Tomcat 不再直接暴露,可放在内网。

  • 指令拆解

    nginx

    复制

    location ~ \.jsp$ {
        proxy_pass http://172.25.254.10:8080;   # 把请求原封不动转给 Tomcat
        proxy_set_header Host $host;            # 保留浏览器里的域名,否则 Tomcat 重定向会出错
    }

    浏览器发的是 Host: lee.timinglee.org,Tomcat 也收到同样的 Host,就不会跳错地址。


  1. 为什么要“负载均衡”?


  • 单台 Tomcat 的并发瓶颈:
    纯 Java 业务,QPS 大约几百~一两千。用户量一上来就卡死。

  • 思路:把同样的应用复制到多台机器,把压力 分摊,术语叫 Load Balance

  • Nginx 的 3 种常用调度算法

    1. 轮询(默认)——每人一次,最公平。

    2. ip_hash ——同一 IP 固定到一台,解决 会话保持(后面细说坑)。

    3. hash $cookie_JSESSIONID ——按 SessionID 选机器,比 ip_hash 更精准。


  1. HTTP 的无状态 & Session 机制


  • 无状态:HTTP 协议本身不带“记忆”。
    第一次请求登录成功,第二次刷新页面,Tomcat 压根不知道你是刚才那个人。

  • 解决思路

    1. 服务器给浏览器发一张“身份证”—— SessionID(随机字符串)。

    2. 浏览器以后每次请求都在 Cookie 里带上 JSESSIONID=xxx

    3. Tomcat 收到后,从自己 内存 里找对应的 SessionMap,取出用户信息。

  • 生命周期

    • 默认 30 min 没交互就失效(web.xml 可调)。

    • 关闭浏览器 Cookie 消失,再开就重新领身份证。


  1. 负载均衡后出现的新问题:Session 丢失


场景:

  • 浏览器第一次请求被分到 Tomcat-A,SessionID=1001 存在 A 的内存。

  • 第二次请求被分到 Tomcat-B,B 内存里没 1001 → 强制跳回登录页。

这就是“找不到 SessionID”的根本原因:HTTP 无状态 + 多台机器内存不共享


  1. 三种 Session 一致性方案对比


表格

复制

方案 原理 优点 缺点 适用
1. ip_hash Nginx 按客户端 IP 固定到同一台机器 零改动 NAT 场景下严重倾斜;单点故障需重新登录 内部后台、用户量小
2. Tomcat Cluster 多台 Tomcat 组播同步 Session 官方原生 组播受网络限制;同步风暴 小规模内网
3. MSM+Memcached Session 序列化后存 Memcached,多台 Tomcat 共享 无状态、高可用、扩展好 需额外部署 Memcached;首次配置稍复杂 生产最强

  1. MSM+Memcached 工作流程(图+文字)


复制

浏览器
   │
   │ 1. 登录请求 → Nginx → Tomcat-A
   │                     │
   │                     └─ 2. 创建 SessionID=1001
   │                          同时 3. 序列化 Session 到 Memcached
   │
   │ 4. 第二次请求 → Nginx → Tomcat-B
   │                     │
   │                     └─ 5. Tomcat-B 发现 Cookie:JSESSIONID=1001
                          6. 去 Memcached 取 Session → 继续业务
  • 如果 Tomcat-A 挂了,Tomcat-B/C/D 任何一台都能从 Memcached 拿到同一份 Session,用户无感知。


  1. 配置小结(回顾)


  1. 反向代理(单机)

    nginx

    复制

    location ~ \.jsp$ {
        proxy_pass http://172.25.254.10:8080;
        proxy_set_header Host $host;
    }
  2. 负载均衡(多机)

    nginx

    复制

    upstream tomcat {
        hash $cookie_JSESSIONID;      # 会话保持最稳
        server 172.25.254.10:8080;
        server 172.25.254.20:8080;
    }
  3. MSM 共享 Session

    • 把相关 jar 扔进 $CATALINA_HOME/lib

    • context.xml 指定 Memcached 节点

    • 重启 Tomcat 即可生效单机

    • 现在需要一个测试页面

      测试页面不能直接在root里要放到默认发布目录里

      直接下载nginx

      在配置文件里写下子配置命令 include 

错误情况:

访问超时

直接访问没问题

域名解析有误,之前实验的影响

测试:

之前的信息也会保留

这个代码,nginx不能写,是tomcat来写的

tomcat挂了,这个实验就不能用了


单机情况下,tomcat挂了,就不能用了

要解决这个问题,用多机来做

多机

测试:

会话绑定

缺点:如果同一个路由器过来的路由都会跑向一个路由器上了

cookie客户端生成的会话   session服务器生成的会话

会话:以用户的身份与服务器对话

此时的情况时,来一个服务器就重新对话

所以解决办法是生成sessionIP要与cookieIP一致,cookie值变了,就访问不同服务器

写cookie哈希

对键值进行哈希

测试:

ID是一样的就会访问同一个服务器上

只有挂了浏览器才会改变,此时ID也变了

前端还在做数据存储,但是后端的tomcat却挂了,前端是不知道的,该怎么办?

无论是10还是20,之前的数据该怎么保存?

三、Memcached

Memcached 只支持能序列化的数据类型,不支持持久化,基于Key-Value的内存缓存系统memcached 虽然没有像redis所具备的数据持久化功能,比如RDB和AOF都没有,但是可以通过做集群同步的方式, 让各memcached服务器的数据进行同步,从而实现数据的一致性,即保证各memcached的数据是一样 的,即使有任何一台 memcached 发生故障,只要集群中有一台 memcached 可用就不会出现数据丢 失,当其他memcached 重新加入到集群的时候,可以自动从有数据的memcached 当中自动获取数据并 提供服务。

Memcached 借助了操作系统的 libevent 工具做高效的读写。libevent是个程序库,它将Linux的epoll、 BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥高 性能。

memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能 Memcached 支持最大的内存存储对象为1M,超过1M的数据可以使用客户端压缩或拆分报包放到多个 key中,比较大的数据在进行读取的时候需要消耗的时间比较长,

memcached 最适合保存用户的 session实现session共享 Memcached存储数据时, Memcached会去申请1MB的内存, 把该块内存称为一个slab, 也称为一个page Memcached 支持多种开发语言,包括:JAVA,C,Python,PHP,C#,Ruby,Perl等

Memcached 官网: http://memcached.org/

它本身不支持持久化,只支持能序列化的数据类型

没有客户端,是个键值

[root@tomcat ~]# yum install memcached -y
 [root@tomcat ~]# vim /etc/sysconfig/memcached
 PORT="11211"
 USER="memcached"
 MAXCONN="1024"
 CACHESIZE="64"
 OPTIONS="-l 0.0.0.0,::1"
 0      
980        
[root@tomcat ~]# systemctl enable --now memcached
 [root@tomcat ~]# netstat -antlupe | grep memcache
 tcp        
0 0.0.0.0:11211           
97815      
34711/memcached
[root@tomcat ~]# telnet localhost 11211
 Trying ::1...
 Connected to localhost.
 Escape character is '^]'.
 #增加
add leekey  0 60 4      
#0 是否压缩  60 过期时间  4 字长
test
 STORED
 add leekey1 0 60 3
 lee
 STORED
 #查看
get  leekey
 VALUE leekey 0 4
 test
 get leekey1
 VALUE leekey1 0 3
 lee
 #改
set leekey 0 60 5
 test1
 STORED
 get leekey
 VALUE leekey 0 5
 test1
 END
 add leekey1 0 60 4
 test
 #删除
delete leekey
 DELETED
 get leekey
 END
get leekey1
 VALUE leekey1 0 3
 lee
 #清空
flush_all
 OK
 get leekey1
 END

实验:

修改接口,打开全部 

再次查看端口信息

要把接口都打开

测试(长连接实验也用过):

这里的2是字长 :规定后面输入的字数只能是两个

查看刚刚储存的内容

修改储存的内容

删除并退出

企业一般不用


使用插件,让tomcat往memcached里存储,实际上,两者是没有关系的。

四、msm

[root@tomcat-1 ~]# vim /usr/local/tomcat/conf/context.xml
 @@@@内容省略@@@@
 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
 memcachedNodes="n1:172.25.254.10:11211,n2:172.25.254.20:11211"
 failoverNodes="n1"
 requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
 transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFacto
 ry"
 />
 [root@tomcat-2 tomcat]# vim /usr/local/tomcat/conf/context.xml
 @@@@内容省略@@@@
 <Manager className="de.javakaffee.web.msm.MemcachedBackupSessionManager"
 memcachedNodes="n1:172.25.254.10:11211,n2:172.25.254.20:11211"
 failoverNodes="n2"
 requestUriIgnorePattern=".*\.(ico|png|gif|jpg|css|js)$"
 transcoderFactoryClass="de.javakaffee.web.msm.serializer.kryo.KryoTranscoderFacto
 ry"
 />

修改nginx配置

[root@Nginx ~]# vim /usr/local/nginx/conf.d/vhosts.conf
 upstream tomcat {
 hash $cookie_JSESSIONID;
 server 172.25.254.10:8080;
 server 172.25.254.20:8080;
 }
 server {
 listen 80;
 server_name lee.timinglee.org;
 root /webdataw/nginx/timinglee.org/lee;
 access_log /var/log/nginx/access.log;
 error_log  /var/log/nginx/error.log;
 try_files $uri $uri.html $uri/index.html /error/default.html;
 }
 location ~ \.jsp$ {
 proxy_pass http://tomcat;
 }

查看memcached的版本

要去找合适版本的插件

安装

要把插件放进tomcat库里

查看tomcat的插件存储位置

服务重启成功后IP会发生变化

failoverNodes:当一个服务器的tomcat出故障时,另一台会要找自己的memcached的,因为自己的里面也是有对端的数据的

重启服务

测试:

20tomcat挂了

这里会有之前数据的原因是,20往10的memcached里存的数据,20挂了,10会在memcached里读取数据


网站公告

今日签到

点亮在社区的每一天
去签到