Tomcat详细配置、优化、负载均衡
简介
Tomcat本身完全用java语言编写,要先安装JDK,才能运行。目前是Apache开源软件组织的一个软件项目,它的官网 http://tomcat.apache.org。
Tomcat类加载默认使用的是双亲委托模型-子类优先
。
一、目录结构
1、Tomcat 的目录层次结构
- bin: 存放启动和关闭等
Tomcat
的脚本文件、环境变量,catalina
可以设置JDK、JRE
路径和Tomcat
内存。 - conf: 存放
Tomcat
服务器的各种配置文件,catalina目录下可以设置默认加载的项目。catalina文件可以设置tomcat服务器内存大小。context.xml可以用来配置数据源之类的东西。logging文件记录tomcat服务器运行的日志记录。server.xml可以设置域名、端口号、IP、请求的编码、默认加载的项目。web.xml可以设置tomcat服务器支持的文件类型。 - lib: 存放
Tomcat
服务器支撑的jar
包,可以做多项目的jar
优化。 - logs: 存放
Tomcat
的日志文件。 - temp: 存放
Tomcat
运行时产生的临时文件,对Tomcat
没有影响。 - webapps:web应用虽在目录,即供外界访问的web资源的存放目录,支持以war包、Jar包、普通文件夹三种形式发布应用。
- work:
Tomcat
的工作目录,Catalina
就在这目录中,用来存放Tomcat运行时编译后的文件。清空work目录,重启Tomcat,可以达到清除Tomcat服务器缓存的目的。 - 文件
LICENSE、NOTICE、RELEASE-NOTES、RUNNING.txt
:Tomcat
服务器的一些签证,运行,注意的信息,比如JDK
版本、变量及作用。
2、JavaWeb应用的组成结构
webapps\aoolication______Web应用所在目录
|----html、jsp、css、js等文件,根目录下的文件外界可以直接访问
|----WEB-INF目录:目录下的文件外界无法直接访问,由web服务器负责调用
|---------classes目录(java类)
|---------lib目录(java类运行所需的jar包)
|---------web.xml(web应用的配置文件)
3、Tomcat的组成结构
1 | <!-- 代表整个Servlet容器组件,是最顶层元素,可以包含一个或多个<Service>元素 --> |
4、Tomcat体系结构
5、项目虚拟目录的映射方式
从Tomcat6
开始,Tomcat
支持自动映射,即Tomcat
服务器会自动管理webapps
目录下的所有web
应用,并把它映射成虚拟目录,换句话说,只需把web
应用放在webapps
目录下,不需要配置Context
,外界可以直接访问,但是如果你不想讲项目放在webapps
下,而是放在其他地方,还是需要配置Context
,比如我的tomcat
在/home
路径下,我的项目在D盘,则需要在Host
下增加如下虚拟目录映射语句
1 |
|
6、Context的寻址优先级
-1):到Tomcat安装目录/conf/Context.xml
文件中查找
2):到Tomcat安装目录
/conf/[enginename]/[hostname]/context.xml.default
文件中查找元素。 enginename:表示
的name属性 hostname:表示
d的那么属性
3):到Tomcat安装目录
/conf/[enginename]/[hostname]/[contextpath].xml
文件中查找元素 - contextpath:表示单个Web应用的URL入口
4):到Web应用的
META-INF/context.xml
文件中查找<Context>
元素5):到Tomcat安装目录
/conf/server.xml
文件中查找<Context>
元素。只适用于单个Web应用
7、修改项目为默认路径
方式一:
在Tomcat默认安装后,tomcat的主目录是webapps/root目录,所以如果想改变tomcat的主目录的话可以如下所做:
在/conf/server.xml
文件的 <Host></Host>
之间加入代码
1 | <Context path="" docBase="/home/myapp" reloadable="true" debug="0"></Context> |
方式二:
将tomcat安装目录下的ROOT下的所有文件删除,换成自己项目的文件。
二、常用配置
1、Context元素的属性
- path: 指定访问该
Web
应用的URL入口 - docBase: 指定
Web
应用的文件路径,可以写绝对路径,也可以写相对于appBase
属性的相对路径 - className:指定实现
Context
组件的Java
类的名字,这个类必须实现org.apache.catalina.Contex
接口,该属性默认值为org.apache.catalina.core.StandardContext
(不建议大家改动) - reloadable:如果为
true
,Tomcat
服务器在运行状态下回监视在WEB-INF/classes
和WEB-INF/lib
目录下的class
文件的改动,以及监视Web应用的WEB-INF/web.xml
文件的改动,如果检测到有更新,服务器会自动更新加载web
应用。其默认值为false
。在开发和调试阶段,将其改为true
,一般像Eclipse
等开发环境都会默认改为true。在正式发布阶段,应将其该为false,可以降低Tomcat
的运行负荷,提高Tomcat
的运行性能,
在一般情况下,<Context>
元素都会使用默认的标准Context
组件,即className
属性采用默认值org.apache.catalina.core.StandardContext
,它除了拥有上面介绍到的属性外,还有自身专有的属性: - cachingAllowed:是否允许启用静态资源(HTML、图片、声音等)的缓存。默认值为
true
。 - cacheMaxSize:设置静态资源缓存的最大值,单位为K。
- workDir:指定Web应用的工作目录。
- uppackWAR:如果为
true
,会把war文件展开为开放目录后再运行。为false
,直接运行war
文件。默认值为true
。
2、web.xml文件
该文件必须放在/WEB-INF目录下,但是从7.0版本开始,Tomcat可以不使用web.xml文件,而是使用注解方式。
1 |
|
TOMCAT中web.xml文件和java项目中WEB-INF目录下的web.xml文件的区别:
加载顺序:
1、tomcat conf目录下;
2、项目目录下的;
tomcat config目录下的为服务器全局作用域,一般用来配置全局设置、数据源等,而项目目录下的为局部作用域。
在tomcat 的web.xml是可以设置session的;
三、Tomcat 优化
1、内存使用配置
Tomcat
是依赖于JVM
的,所以Tomcat
的使用内存配置实质上是JVM
的内存配置
-在 /bin
目录下的 catalina.sh
可以直接通过 Tomcat
设置 JVM
内存参数
set "JAVA_OPTS=%JAVA_OPT% -server -Xms2048m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m -Djava.awt.headless=true"
-通过内存设置充分利用服务器内存
-server
: 模式启动应用慢,但是极大程度提高运行性能-Xms2048m -Xmx2048m
: 设置的是堆内存java8
开始,PermSize
被MetaspaceSize
代替,MetaspaceSize
共享heap
,不会再有java.lang.OutOfMemoryError:PermGen space
,可以不设置.Headless=true
: 适用于Linux系统,与图形操作有关,如生成验证码含义是当前的是无显示器的服务器,应用中如果获取系统显示有关的参数会抛出异常,windows
系统可不用设置.
-可通过 jmap -heap process_id
查看设置是否成功
2、最大连接数配置(并发能力)
在
/conf/server.xml
里进行配置在
<Connector>
属性中将
protocol
属性改为"org.apache.coyote.http11.Http11NioProtocol",NIO
模型的效率更高
加入
1 | maxThreads="500" //当前可以同时处理的最大用户访问数 |
四、负载均衡配置
负载均衡是提高应用负载量和容错的有效手段,可以结合 Nginxs
与 Tomcat
实现, Nginx
是一款性能优异的反向代理服务器。
1、负载均衡配置实现
反向代理原理示意图:
负载均衡示意图:
负载均衡策略:
- Nginx 提供轮询(round robin)
- 用户IP哈希(client IP)
- 指定权重
2、负载均衡时Session的处理策略
问题:
` Session ` 是 ` Tomcat ` 服务器上的内存空间,如果一个用户发出多个请求,却发到了多个 ` tomcat ` 服务器中,那么就会出现 ` Session ` 不同步的问题。
解决方案1:请求锁定
将一个用户的请求锁定到某一台服务器上,简单,但是缺乏容错性,一旦某个服务器发生故障, ` Session ` 可能丢失,(但是服务器发生故障是一个低概率事件,如果一个服务器经常挂掉,要么是硬件有问题,要么是应用有问题)。
可以使用用户IP哈希实现
解决方案2:Session复制
` Session ` 复制策略,基于网络的广播策略,一个节点 ` Session ` 变化,其他节点同步复制,具有容错性,但节点多或复制量大时对网络负荷大,使网络效率低下,甚至阻塞
① 在
/conf/server.xml
文件中开启Session
复制的选项,将<Cluster>
注释去掉,7.0默认值以配置好,需要接收器<Receiver>
绑定内网(
一般服务器都有两块网卡)网卡地址,修改端口>。② 在应用中指定应用是在分布式部署之下,在
web.xml
中添加<distributable/>
选项
解决方案3:共享Session
额外创建一个共享的空间用来存放 ` Session ` ,所有服务器共享一个 ` Session `
` memcached ` 缓存共享方案基本原理
粘性 ` Session ` 与非粘性 ` Session ` 方式:
需要一些工具 jar
包,官网有目录和下载连接,在 /conf/context.xml
中进行配置,全局有效。
3、集群环境中应用代码应注意的问题
① 传递
Session
需要实体类序列化支持,实现可序列化接口,设置版本号② 获取用户IP地址方法的变化,获取真实客户端ip而不是
Nginx
代理地址③ 动静分离结构的预规划,
/一般高并发的网站上,资源类的文件,如
js
、css
,图片通常是由静态服务器处理,Nginx
处理静态文件效率就非常高,而Tomcat
处理静态文件是它很大的一个弱势,Tomcat
只负责动态请求的处理。那么编码的时候就要考虑静态资源最后可能要被拿出去,地址会有变化,所以在开发的时候应该规划访问地址,保持最大灵活性。
本文地址:Tomcat详细配置、优化、负载均衡
Centos7 安装 Docker
Docker 要求 CentOS
系统的内核版本高于 3.10 。
不要使用 root
用户管理 Docker
。
1 | uname -r |
版本底的可以不用向下看了。
1、基本操作
1 | sudo rpm -qa|grep docker |
使用 repository
1 | # 需要挂载 ISO 镜像 |
查看docker版本
1 | sudo yum list docker-ce --showduplicates | sort -r |
安装docker
1 | sudo yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin |
当 GPG key
为 060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35
出入 y 继续.
启动 Docker
1 | sudo systemctl start docker |
测试
1 | sudo docker run hello-world |
会打印一条 Hello from Docker!
然后退出。
更新
从 get.Docker. com
下载脚本,然后运行它在 Linux
上安装最新的 Docker
稳定版本:
1 | sudo curl -fsSL https://get.docker.com -o get-docker.sh |
配置修改
1 | sudo vim /etc/docker/daemon.json |
registry-mirrors
镜像dns
hosts
远程访问
1 | { |
远程访问配置
"hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]
其它源
1 | { |
服务
1 | sudo vim /lib/systemd/system/docker.service |
将第11行的ExecStart=/usr/bin/dockerd,替换为:
1 | #ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -H tcp://0.0.0.0:7654 |
2375
是管理端口,7654
是备用端口
在~/.bashrc
中写入docker
管理端口
1 | export DOCKER_HOST=tcp://0.0.0.0:2375 |
开机自启
1 | sudo systemctl enable docker.service |
查看 docker
信息
1 | docker info |
添加 docker
组用户
1 | sudo usermod -aG docker $USER |
完全退出后,重新登录,然后不适用 sudo
测试
1 | docker run hello-world |
2、常用命令
镜像相关
1)docter pull NAME[:TAG] 使用pull命令从docker hub仓库下载镜像到本地
2)docker tag oldName newName 为本地镜像添加新的标签
3)docker images 列出本地主机上已有的镜像
4)docker search TERM 默认搜索docker hub官方仓库的镜像
5)docker rmi IMAGE [IMAGE…] IMGE可以是标签或id
6)docker commit [OPTIONS] CONTAINER[REPOSITORY[:TAG]] 基于已有镜像的容器创建镜像,可以创建比较复杂的镜像。-a:作者信息,-m:提交信息,-p:提交时暂停容器运行
7)docker import -NAME[:TAG] 基于本地模板导入镜像
8)docker build -t NAME[:TAG] dockerfile路径 基于dockerfile创建
9)docker save –o xxx.tar NAME[:TAG] 存出镜像到本地文件
- docker load <xxxx.tar 载入镜像
11)docker inspect 镜像id 查看镜像详细信息
容器相关
1)docker create –it NAME[:TAG] 创建容器
2)docker start NAME[:TAG] 启动容器
3)docker run –it NAME[:TAG] 等于先执行docker create命令,再执行docker start,-it交互式,守护态运行,通过run后加-d实现
4)docker stop[-t|–time[=10]] 终止容器
5)docker restart NAME[:TAG] 启动状态重新启动
6)docker ps –a –q 查看处于终止的容器id信
7)docker ps 查看正在运行的容器
8)docker ps –a 查看所有容器
9)docker rm 容器id 删除容器,需要先停止
10)docker logs 容器id 查看容器日志
11)docker port <container-name|container-id> 端口 查看容器映射端口
12)docker inspect 容器id 查看容器信息
13)docker exec -u root -it containerID /bin/bash 指定用户进入容器操作
14)env 容器内部输入env查看容器内部环境变量
15)docker cp
16)docker cp container-id:
17)docker network create app_net 创建自定义网络
18)docker network connect app_net container-name连接网络
19)docker run -it -v /dbdata –name dbdata 创建数据卷容器dbdata,并在其中创建数据卷挂载到/dbdata。其他容器挂载使用–volumes-from dbdata,可以多次使
用,从多个容器挂载多个数据卷,还可以从一挂载数据卷的容器来挂载数据卷,且使用–volumes-from 参数所挂载数据卷的容器自身不需要保持运行,要删除一个数据卷
必须在删除最后一个还挂着它的容器时显示使用docker rm -v命令来指定同时删除关联的容器
原文:https://blog.csdn.net/songer_xing/article/details/78599197
本文地址 Centos7 安装 docker
3、迁移镜像
保存镜像到本地
保存镜像命令
1 | docker save -o 本地文件名 要保存的镜像 |
查看镜像
1 | docker images |
保存一个镜像
1 | docker save -o redis.tar redis |
导入镜像
1 | docker load --input 文件 |
卸载 Docker
1 | sudo yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin |
重装
1 | sudo yum remove docker \ |
附录
daemon.json
windows
下的地址C:\Users\${USER}\.docker\daemon.json
linux
下的地址/etc/docker/daemon.json
1 | sudo mkdir -p /etc/docker |
其它配置
1 | { |
允许请求转发
1 | vim /etc/sysctl.conf |
写入
1 | net.ipv4.ip_forward=1 |
重启
1 | sudo systemctl daemon-reload |
web管理工具portainer
1 | docker volume create portainer_data |
离线安装
1 | mkdir ~/docker |
已经安装可以使用 reinstall
配置信任
1 | { |
JDK环境变量无效问题(Linux)
\
很多人在 /etc/profile中配置环境变量之后,发现并没有生效。
第一步: vim /etc/profile
环境变量没写对
#set java environment
#export JAVA_HOME=”/usr/local/java/jdk1.8”
export CLASSPATH=”.:/usr/local/java/jdk1.8/jre/lib/rt.jar:/usr/local/java/jdk1.8/lib/dt.jar:/usr/local/java/jdk1.8/lib/tools.jar”
export PATH=”/usr/local/java/jdk1.8/bin:$PATH”
所有的路径用直接路径,保证路径不会错,
然后执行 source /etc/profile。
java -version
```
java version “1.8.0_181”
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
```
就会成功了。
如果没有效果,那就是环境变量没写对,都使用绝对路径肯定没错。
写到这里,正好喜马拉雅道出“大道至简”,来形容这个在好不过了
本文地址 JDK环境变量无效问题(Linux)
Linux安装sdkman及使用方法
sdkman介绍
sdkman(The Software Development Kit Manager)
软件开发工具管理包,用来管理多个版本的开发环境的工具。提供命令行来安装、切换、删除、列出候选版本。
sdkman安装
1 | curl -s "https://get.sdkman.io" | bash |
使用方法
sdk install 软件名 [版本号]
若不加版本号,则安装最新的稳定版;若加版本号则安装指定版本
安装举例
安装sprint-boot:
1 | sdk install springboot |
安装gradle:
sdk install gradle 3.0
安装java:
1 | sdk install java |
常用命令
1 | sdk help #查看帮助信息 |
本文地址 Linux安装sdkman及使用方法
SSH\scp命令传输文件
1、上传文件
scp /local_path/filename username@servername:/target_path/
2、下载文件
scp username@servername:/target_path/filename /local_path/
3、上传文件夹
scp -r /local_path/ username@servername:/target_path/
4、下载文件夹
scp -r username@servername:/target_path/ /local_path/
*local_path 表示本地目录,target_path表示远程主机目录,filename表示文件,*_path/表示当前
本文地址 SSH\scp命令传输文件
ntfs-3g让Linux 打开ntfs盘
- 加源 用的阿里
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
- 安装
1
2
3yum update;yum install ntfs-3g
#建议安装全家桶
yum update;yum install ntfs*
没有权限的话:su
输入密码,重复上面操作
如果ntfs硬盘状态为只读
1 | #修复文件系统/dev/sda7是自己的硬盘 |
参考链接:https://www.jianshu.com/p/7648613b4a63
无法挂载参考链接
rdesktop安装和使用(Linux)
最简单粗暴的教程
1 | wget http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm |
1 | - rpm -Uvh nux-dextop-release*rpm |
最艰难的一个yum
libgssglue.so.1:进入下面链接下载
http://www.rpmfind.net/linux/rpm2html/search.php?query=libgssglue.so.1()(64bit)
下载后
1 | rpm -ivh lib64gssglue1-0.4-1-mdv2012.0.x86_64.rpm |
再次安装 可以直接用:
1 | rdesktop -f ip:port -u user -p passwd -r disk:max=/dev/ |
这里注意一点,如果是连接window系统,disk只能用window支持的硬盘格式
本文地址 rdesktop安装和使用(Linux)
ZIP文件操作(Linux)
1、安装zip、unzip应用。
1 | yum install zip unzip |
2、压缩和解压文件
以下命令均在/home目录下操作
cd /home #进入/home目录
- 把/home目录下面的mydata目录压缩为mydata.zip
zip -r mydata.zip mydata #压缩mydata目录
- 把/home目录下面的mydata.zip解压到mydatabak目录里面
unzip mydata.zip -d mydatabak
- 把/home目录下面的abc文件夹和mydata.txt压缩成为mydatatxt.zip
zip -r mydatatxt.zip mydata.txt
- 把/home目录下面的mydata.zip直接解压到/home目录里面
unzip mydata.zip
- 把/home目录下面的mydatatxt.zip、mydata2.zip、mydata3.zip同时解压到/home目录里面
unzip mydata\*.zip
- 查看把/home目录下面的mydata.zip里面的内容
unzip -v mydata.zip
- 验证/home目录下面的mydata.zip是否完整
unzip -t mydata.zip
- 把/home目录下面mydata.zip里面的所有文件解压到第一级目录
unzip -j mydata.zip
本文地址 ZIP文件操作(Linux)
Lodash操作以及问题
遇到的问题
_.sum 函数丢失精度的问题
一般情况下,我们都会在前端保留两位小数,这时候计算平均或者汇总就经常用到Lodash
。
这个时候,对于多个小数求和或平均之后的值为 3.655
,
但是如果用 _.sum(values,'val') ;
,这个函数的结果就不一定是3.655
,在我做的某个项目中,结果始终为 3.6549999***7
。
第二种情况,JS
丢失精度:
1 | 2.55.toFixed(1) = 2.5; |
也就是说,正常情况下,保留两位小时时,四舍五入是对的(大于2.55499999999999999
这个情况就是非正常了)。