有Tomcat,为什么还要Nginx?(有tomcat为什么还用nginx)
off999 2025-02-04 15:29 12 浏览 0 评论
只用Tomcat,不用Nginx搭建Web服务,行不行?我曾经提出的愚蠢问题,今天详细给自己解释下,为什么必须用Nginx!
不用Nginx,只用Tomcat的Http请求流程
浏览器处理一个Http请求时,会首先通过DNS服务器找到域名关联的IP地址,然后请求到对应的IP地址。以阿里云域名管理服务为例,一个域名可以最多绑定三个IP地址,这三个IP地址需要是公网IP地址,所以首先需要在三个公网Ip服务器上部署Tomcat实例。
此时我将面临的麻烦如下
- 由于DNS域名管理绑定的IP地址有限,最多三个,你如果想要扩容4台Tomcat,是不支持的。无法满足扩容的诉求
- 如果你有10个服务,对应10套Tomcat集群,就需要10 * 3台公网Ip服务器。成本还是蛮高的。
- 10个服务需要对应10个域名,分别映射到对应的Tomcat集群
- 10个域名我花不起这个钱啊!(其实可以用二级域名配置DNS映射)
- 公网服务器作为接入层需要有防火墙等安全管控措施,30台公网服务器,网络安全运维,我搞不定。
- 公网IP地址需要额外从移动联通运营商或云厂商购买,30个公网IP价格并不便宜。
- 前后端分离的情况,Tomcat无法作为静态文件服务器,只能用Nginx或Apache
以上几个问题属于成本、安全、服务扩容等方面。
如果Tomcat服务发布怎么办
Tomcat在服务发布期间是不可用的,在发布期间Http请求打到发布的服务器,就会失败。由于DNS 最多配置3台服务器,也就是发布期间是 1/3 的失败率。 我会被老板枪毙,用加特林
DNS不能自动摘掉故障的IP地址吗?
不能,DNS只是负责解析域名对应的IP地址,他并不知道对应的服务器状态,更不会知道服务器上Tomcat的状态如何。DNS只是解析IP,并没有转发Http请求,所以压根不知道哪台服务器故障率高。更无法自动摘掉IP地址。
我能手动下掉故障的IP地址吗?
这个我能,但是还是会有大量请求失败。以阿里云为例,配置域名映射时,我可以下掉对应的IP地址,但需要指定域名映射的缓存时间,默认10分钟。换句话说,就算你在上线前,摘掉了对应的IP,依然要等10分钟,所有的客户端才会拿到最新的DNS解析地址。
那么把TTL缓存时间改小,可以吗? 可以的,但是改小了,就意味更多的请求被迫从DNS服务器拿最新的映射,整体请求耗时增加,用户体验下降!被老板发现,会骂我。
节点突然挂掉怎么办?
虽然可以在DNS管理后台手动下掉IP地址,但是节点突然宕机、Tomcat Crash等因素导致的突然故障,我是来不及下掉对应IP地址的,我只能打电话告诉老板,“线上服务崩了,你等我10分钟改点东西”。
如果这时候有个软件能 对Tomcat集群健康检查和故障重试,那就太好了。
恰好,这是 Nginx 的长处!
Nginx可以健康检查和故障重试
而Tomcat没有。
例如有两台Tomcat节点,在Nginx配置故障重试策略
upstream test {
server 127.0.0.1:8001 fail_timeout=60s max_fails=2; # Server A
server 127.0.0.1:8002 fail_timeout=60s max_fails=2; # Server B
}
当A节点出现 connect refused时(端口关闭或服务器挂了),说明服务不可用,可能是服务发布,也可能是服务器挂了。此时nginx会把失败的请求自动转发到B节点。 假设第二个请求 请求到A还是失败,正好累计2个失败了,那么Nginx会自动把A节点剔除存活列表 60 秒,然后继续把请求2 转发到B节点进行处理。60秒后,再次尝试转发请求到A节点…… 循环往复,直至A节点活过来……
而这一过程客户端是感知不到失败的。因为两次请求都二次转发到B节点成功处理了。客户端并不会感知到A节点的处理失败,这就是Nginx 反向代理的好处。即客户端不用直连服务端,加了个中间商,服务端的个别节点宕机或发布,对客户端都毫无影响。
而Tomcat只是Java Web容器,并不能做这些事情。
10个服务,10个Tomcat集群,就要10个域名,30个公网IP吗?
以阿里云为例,域名管理后台是可以配置二级域名映射,所以一个公网域名拆分为10个二级域名就可以了。
所以只用Tomcat,不用Nginx。需要1个公网域名,10个二级域名,30台服务器、30个公网IP。
当我和老板提出这些的时候,他跟我说:“你XX疯了,要不滚蛋、要不想想别的办法。老子没钱,你看我脑袋值几个钱,拿去换公网IP吧”。
DNS映射到Tomcat的IP地址,必须要公网,成本实在hold不住。心里苦啊,要是能有一个软件,能帮我把一个域名分别映射到30个内网IP就好了。
恰好 Nginx可以!
Nginx 虚拟主机和反向代理
例如把多个二级域名映射到不同的文件目录,例如
- bbs.abc.com,映射到 html/bbs
- blog.abc.com 映射到 html/blog
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name www.abc.com;
location / {
root html/www;
index index.html index.htm;
}
}
server {
listen 80;
server_name bbs.abc.com;
location / {
root html/bbs;
index index.html index.htm;
}
}
server {
listen 80;
server_name blog.abc.com;
location / {
root html/blog;
index index.html index.htm;
}
}
}
例如把不同的二级域名或者URL路径 映射到不同的 Tomcat集群
- 分别定义 serverGroup1、serverGroup2 两个Tomcat集群
- 分别把路径group1、group1 反向代理到serverGroup1、serverGroup2
upstream serverGroup1 { # 定义负载均衡设备的ip和状态
server 192.168.225.100:8080 ; # 默认权重值为一
server 192.168.225.101:8082 weight=2; # 值越高,负载的权重越高
server 192.168.225.102:8083 ;
server 192.168.225.103:8084 backup; # 当其他非backup状态的server 不能正常工作时,才请求该server,简称热备
}
upstream serverGroup2 { # 定义负载均衡设备的ip和状态
server 192.168.225.110:8080 ; # 默认权重值为一
server 192.168.225.111:8080 weight=2; # 值越高,负载的权重越高
server 192.168.225.112:8080 ;
server 192.168.225.113:8080 backup; # 当其他非backup状态的server 不能正常工作时,才请求该server,简称热备
}
server { # 设定虚拟主机配置
listen 80; # 监听的端口
server_name picture.itdragon.com; # 监听的地址,多个域名用空格隔开
location /group1 { # 默认请求 ,后面 "/group1" 表示开启反向代理,也可以是正则表达式
root html; # 监听地址的默认网站根目录位置
proxy_pass http://serverGroup1; # 代理转发
index index.html index.htm; # 欢迎页面
deny 127.0.0.1; # 拒绝的ip
allow 192.168.225.133; # 允许的ip
}
location /group2 { # 默认请求 ,后面 "/group2" 表示开启反向代理,也可以是正则表达式
root html; # 监听地址的默认网站根目录位置
proxy_pass http://serverGroup2; # 代理转发
index index.html index.htm; # 欢迎页面
deny 127.0.0.1; # 拒绝的ip
allow 192.168.225.133; # 允许的ip
}
error_page 500 502 503 504 /50x.html;# 定义错误提示页面
location = /50x.html { # 配置错误提示页面
root html;
}
}
经过以上的教训,我再也不会犯这么愚蠢的错误了,我需要Tomcat,也需要Nginx。
当然如果钱足够多、资源无限丰富,公网IP、公网服务器、域名无限…… 服务发布,网站崩溃,无动于衷,可以不用Nginx。
相关推荐
- Python变量类型判断方法详解(python怎么判断变量名合不合法)
-
技术背景在Python编程中,变量类型的判断是一项基础且重要的操作。由于Python是动态类型语言,变量的类型在运行时才能确定,因此在开发过程中,我们常常需要明确变量的类型,以便进行相应的操作。同时,...
- 如何确定Python变量的类型(python指定变量类型)
-
技术背景在Python编程中,变量是动态类型的,即变量在使用过程中可以被赋予不同类型的值。这在带来灵活性的同时,也可能导致在某些情况下需要明确变量的具体类型。例如,在进行数据处理、类型转换或错误检查时...
- Python 中检查类型的标准方法(python检查函数)
-
在Python的编程世界里,我们常常会遇到需要检查变量类型的情况。在StackOverflow上有一个热门问题“What'sthecanonicalwaytocheck...
- Python中确定对象类型的方法(python中确定对象类型的方法有哪些)
-
技术背景在Python编程中,有时候需要确定一个变量的类型,例如判断一个变量是列表、字典还是其他类型。了解对象的类型有助于进行条件判断、错误处理以及编写通用的代码。Python提供了多种方法来实现这一...
- Python 中的类型检查(python类型检查函数)
-
Python是一种解释型、交互式和面向对象的编程语言。它支持动态类型,具有非常高级的动态数据类型。动态数据类型使得开发者能够专注于实际程序,而不是在编写代码时花费时间和精力去指定数据类型。Pytho...
- Python从入门到放弃-详解列表、元组和字典
-
什么是列表?列表是在Python中一种常见的数据存储结构,它可以用来存储不同类型的数据。与其他开发语言不同的是Python中的列表中可以存储各种类型的数据,而不是只能用来存储一种类型的数据,如下所示l...
- 现代化python字典合并的技巧(python字典怎么合并)
-
现代Python字典合并:使用|运算符在Python3.9之前,有两种常见的合并字典的方法:使用update方法或**运算符。然而,这两种方法都有其缺点。在本文中,我们将探讨Python中合并字典的...
- 三种常用方法合并 Python 字典,你学会了吗?
-
在使用Python字典时,你有时需要将多个字典合并成一个,以便后续处理。本教程将介绍三种常见的Python字典合并方法。我们将重点学习以下三种方式:使用update()方法字典解包并集运算...
- 23-Python-第三方库Json(python第三方库代码大全)
-
1-json库的使用`json`库是Python标准库的一部分,用于处理JSON数据。它提供了`loads`、`dumps`等方法。安装三方库pipinstalljson1-1-将JSON字符串解...
- Python中复制字典并仅修改副本的方法
-
技术背景在Python编程中,当我们想要复制一个字典并对副本进行修改,而不影响原始字典时,可能会遇到一些问题。直接使用赋值语句dict2=dict1并不能实现真正的复制,而是让dict2和...
- Python 中的字典推导式(字典在python)
-
通过本文,你将了解有关Python字典推导式的所有信息,包括如何创建字典、使用条件语句(if-else语句)访问字典以及如何使用易于实现的步骤嵌套推导式!什么是字典Python中的字典是项目的...
- python笔记17:字典推导式(python 字典的字典)
-
字典推导式'''#如:1,2,……10为键,平方为值dict_shu={}forimteinrange(1,11):dict_shu[imte]=imte**2print...
- Python代码使用字典推导式(字典 python)
-
解释python代码:stoi={ch:ifori,chinenumerate(chars)}这段Python代码使用字典推导式创建了一个字符到索引的映射字典。具体解释如下:stoi=...
- Python-中的词典 {_}(python字典用法大全)
-
字典是键值对的集合,其中每个键都链接到一个值(可以是数字、字符串、列表,甚至是另一个字典)。键和值用冒号分隔,每个键值对用逗号分隔,用大括号{}括起来。访问值:可以通过引用方括号内的键来检索值。a...
- Python 开发工程师必会的 5 个文件操作库
-
在Python开发的世界里,文件操作是一项基础且高频的任务。从日常的数据处理到复杂的项目部署,熟练掌握文件操作库能让我们的开发工作事半功倍。本文和大家聊聊我眼中开发必备的5个文件操作库,它们各...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- python计时 (54)
- python安装路径 (54)
- python类型转换 (75)
- python进度条 (54)
- python的for循环 (56)
- python串口编程 (60)
- python写入txt (51)
- python读取文件夹下所有文件 (59)
- java调用python脚本 (56)
- python操作mysql数据库 (66)
- python字典增加键值对 (53)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python qt (52)
- python人脸识别 (54)
- python斐波那契数列 (51)
- python多态 (60)
- python命令行参数 (53)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- centos7安装python (53)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)