MongoDB基本概念

微信截图_20200921170214.png

1
2
3
4
5
6
7
8
9
# 可以显示所有数据的列表
show dbs

# db 显示当前数据库对象或集合
> db
test

# use 可以连接到一个指定的数据库
use local

数据库也通过名字来标识。数据库名可以是满足以下条件的任意 UTF-8 字符串。

  • 不能是空字符串(””)。
  • 不得含有’ ‘(空格)、.、$、/、\和\0 (空字符)。
  • 应全部小写。
  • 最多64字节。

有一些数据库名是保留的,可以直接访问这些有特殊作用的数据库。

  • admin: 从权限的角度来看,这是 root 数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
  • local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
  • config: 当Mongo用于分片设置时,config 数据库在内部使用,用于保存分片的相关信息。

文档(Document)

RDBMS (关系数据库管理系统:Relational Database Management System) 与 MongoDB 对应的术语:

微信截图_20200921170852.png

需要注意的是:

  • 文档中的键/值对是有序的。
  • 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  • MongoDB区分类型和大小写。
  • MongoDB的文档不能有重复的键。
  • 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
  • .和$有特别的意义,只有在特定环境下才能使用。
  • 以下划线”_”开头的键是保留的(不是严格要求的)。

集合

当第一个文档插入时,集合就会被创建。

合法的集合名

  • 集合名不能是空字符串””。
  • 集合名不能含有\0字符(空字符),这个字符表示集合名的结尾。
  • 集合名不能以”system.”开头,这是为系统集合保留的前缀。
  • 用户创建的集合名字不能含有保留字符。有些驱动程序的确支持在集合名里面包含,这是因为某些系统生成的集合中包含该字符。除非你要访问这种系统创建的集合,否则千万不要在名字里出现$。

capped collections

名词解释:

capped:用…覆盖顶部(或端部)

Capped collections 就是固定大小的 collection

它有很高的性能以及队列过期的特性(过期按照插入的顺序). 有点和 “RRD” 概念类似(round robin database,即环形数据库)。

Capped collections 是高性能自动的维护对象的插入顺序。它非常适合类似记录日志的功能和标准的 collection 不同,你必须要显式的创建一个 capped collection,指定一个 collection 的大小,单位是字节。collection 的数据存储空间值提前分配的。

Capped collections 可以按照文档的插入顺序保存到集合中,而且这些文档在磁盘上存放位置也是按照插入顺序来保存的,所以当我们更新 Capped collections 中文档的时候,更新后的文档不可以超过之前文档的大小,这样话就可以确保所有文档在磁盘上的位置一直保持不变。

由于 Capped collection 是按照文档的插入顺序而不是使用索引确定插入位置,这样的话可以提高增添数据的效率。MongoDB 的操作日志文件 oplog.rs 就是利用 Capped Collection 来实现的。

要注意的是指定的存储大小包含了数据库的头信息。

db.createCollection("mycoll", {capped:true, size:100000})

size 是整个集合空间大小,单位为【KB】

max 是集合文档个数上线,单位是【个】

如果空间大小到达上限,则插入下一个文档时,会覆盖第一个文档;如果文档个数到达上限,同样插入下一个文档时,会覆盖第一个文档。
两个参数上限判断取的是【与】的逻辑。

  • 在 capped collection 中,你能添加新的对象。
  • 能进行更新,然而,对象不会增加存储空间。如果增加,更新就会失败 。
  • 使用 Capped Collection 不能删除一个文档,可以使用 drop() 方法删除 collection 所有的行。
  • 删除之后,你必须显式的重新创建这个 collection
  • 在 32位机器中,capped collection 最大存储为 1e9( 1X109)个字节,约为482.5M,64位上只受系统文件大小的限制。。
  • 对固定集合进行插入速度极快
  • 按照插入顺序的查询输出速度极快
  • 能够在插入最新数据时,淘汰最早的数据

用法

用法1:储存日志信息
用法2:缓存一些少量的文档

元数据

数据库的信息是存储在集合中。它们使用了系统的命名空间:

dbname.system.*

在MongoDB数据库中名字空间 <dbname>.system.* 是包含多种系统信息的特殊集合 (Collection),如下:

微信截图_20200921174139.png

对于修改系统集合中的对象有如下限制。

1
2
3
4
在 {{system.indexes}} 插入数据,可以创建索引。
但除此之外该表信息是不可变的(特殊的 `drop index` 命令将自动更新相关信息)。

{{system.users}} 是可修改的。 {{system.profile}} 是可删除的。

MongoDB 数据类型

微信截图_20200921174631.png

ObjectId

ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:

  • 前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
  • 接下来的 3 个字节是机器标识码
  • 紧接的两个字节由进程 id 组成 PID
  • 最后三个字节是随机数

MongoDB 中存储的文档必须有一个 _id 键。这个键的值可以是任何类型的,默认是个 ObjectId对象

由于 ObjectId 中保存了创建的时间戳,所以你不需要为你的文档保存时间戳字段,你可以通过 getTimestamp 函数来获取文档的创建时间:

1
2
3
4
5
6
7
> var newObject = ObjectId()
> newObject.getTimestamp()
ISODate("2017-11-25T07:21:10Z")
ObjectId 转为字符串

> newObject.str
5a1919e63df83ce79df8b38f

字符串

BSON 字符串都是 UTF-8 编码。

时间戳

BSON 有一个特殊的时间戳类型用于 MongoDB 内部使用,与普通的 日期 类型不相关。 时间戳值是一个 64 位的值。其中:

前32位是一个 time_t 值(与Unix新纪元相差的秒数)
后32位是在某秒中操作的一个递增的序数
在单个 mongod 实例中,时间戳值通常是唯一的。

在复制集中, oplog 有一个 ts 字段。这个字段中的值使用BSON时间戳表示了操作时间。

BSON 时间戳类型主要用于 MongoDB 内部使用。在大多数情况下的应用开发中,你可以使用 BSON 日期类型。

日期

表示当前距离 Unix新纪元(1970年1月1日)的毫秒数。日期类型是有符号的, 负数表示 1970 年之前的日期。

1
2
3
4
5
6
7
8
9
10
> var mydate1 = new Date()     //格林尼治时间
> mydate1
ISODate("2020-09-21T09:49:56.273Z")
> typeof mydate1
object
> var mydate2 = ISODate() //格林尼治时间
> mydate2
ISODate("2020-09-21T09:50:29.386Z")
> typeof mydate2
object

这样创建的时间是日期类型,可以使用 JS 中的 Date 类型的方法。

返回一个时间类型的字符串:

1
2
3
4
5
6
7
> var mydate1str = mydate1.toString()
> mydate1str
Mon Sep 21 2020 17:49:56 GMT+0800
> typeof mydate1str
string
> Date()
Mon Sep 21 2020 17:51:15 GMT+0800

参考:

MongoDB 概念解析

下载安装包,安装

https://www.mongodb.com/try/download/community

默认安装位置:C:\Program Files\MongoDB\Server\4.4\bin

运行 MongoDB 服务器

命令行运行

1
2
cd C:\Program Files\MongoDB\Server\4.4\bin\
mongod --dbpath D:\MongoDBData

微信截图_20200921162755.png

连接服务

1
2
cd C:\Program Files\MongoDB\Server\4.4\bin\
mongo.exe

微信截图_20200921162957.png

配置 MongoDB 服务

mongod 默认配置文件:

微信截图_20200921161709.png

根据实际情况,修改日志路径,和文档路径。

如:dbPath: D:\MongoDBData

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# mongod.conf

# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
dbPath: C:\Program Files\MongoDB\Server\4.4\data
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:

# where to write logging data.
systemLog:
destination: file
logAppend: true
path: C:\Program Files\MongoDB\Server\4.4\log\mongod.log

# network interfaces
net:
port: 27017
bindIp: 127.0.0.1


#processManagement:

#security:

#operationProfiling:

#replication:

#sharding:

## Enterprise-Only Options:

#auditLog:

#snmp:

安装 MongoDB服务

1
mongod.exe --config "C:\Program Files\MongoDB\Server\4.4\bin\mongod.cfg" --install

dbpath,可以在配置文件(例如:C:\mongodb\mongod.cfg)或命令行中通过 --dbpath 选项指定。

可以安装 mongod.exemongos.exe 的多个实例的服务。只需要通过使用 --serviceName--serviceDisplayName 指定不同的实例名。

以管理员身份启动 cmd:

1
2
3
4
5
6
7
8
9
# 启动MongoDB服务
net start MongoDB

# 关闭MongoDB服务
net stop MongoDB

# 移除 MongoDB 服务
cd C:\Program Files\MongoDB\Server\4.4\bin
mongod.exe --remove

MongoDB 后台管理 Shell

打开 mongodb 装目录的下的bin目录,然后执行 mongo.exe 文件,MongoDB ShellMongoDB 自带的交互式 Javascript shell ,用来对MongoDB进行操作和管理的交互式环境。

当进入mongoDB后台后,它默认会链接到 test 文档(数据库):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
C:\Program Files\MongoDB\Server\4.4\bin>mongo
MongoDB shell version v4.4.1
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Implicit session: session { "id" : UUID("7aa2a8eb-097a-4433-a348-314868079dff") }
MongoDB server version: 4.4.1
---
The server generated these startup warnings when booting:
2020-09-21T16:38:42.622+08:00: ***** SERVER RESTARTED *****
2020-09-21T16:38:43.487+08:00: Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
---
---
Enable MongoDB's free cloud-based monitoring service, which will then receive and display
metrics about your deployment (disk utilization, CPU, operation statistics, etc).

The monitoring data will be available on a MongoDB website with a unique URL accessible to you
and anyone you share the URL with. MongoDB may use this information to make product
improvements and to suggest MongoDB products and deployment options to you.

To enable free monitoring, run the following command: db.enableFreeMonitoring()
To permanently disable this reminder, run the following command: db.disableFreeMonitoring()
---
> db
test
> 2 + 2
4
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB

参考:

Windows 平台安装 MongoDB

一个应用服务(service)中,配置多个端口号

一个service配置多个端口,项目可以通过多个端口访问。

修改 vim /usr/local/apache-tomcat-8.5.40/conf/server.xml,在Service下配置多个 <Connector> 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<Service name="Catalina"> 
<Connector connectionTimeout="20000" port="8013" protocol="HTTP/1.1" redirectPort="8443"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>

<Connector port="8014" protocol="HTTP/1.1" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000" URIEncoding="utf-8"
disableUploadTimeout="true" />

<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
<Context path="/" reloadable="true" docBase="/test/webapp"></Context>
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>
</Engine>
</Service>

在这个应用里,可以用8080端口号访问服务,也可以用8099端口号来访问服务; 服务放置的路径由host决定,上例中服务放在 webapps 下。
以下两种方式访问同一个项目:

1
2
http://localhost:8013/项目名称
http://localhost:8014/项目名称

在一个Tomcat下配置多个服务,用不同的端口号。

配置多个service,每个service可以配置多个端口。

修改 vim /usr/local/apache-tomcat-8.5.40/conf/server.xml ,添加多个 Service 即可。

注意 Service nameEngine nameappBase端口号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<Service name="Catalina">
<Connector connectionTimeout="20000" port="8013" protocol="HTTP/1.1" redirectPort="8443"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
<Engine defaultHost="localhost" name="Catalina">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
</Host>
</Engine>
</Service>

<Service name="Catalina1">
<Connector connectionTimeout="20000" port="8014" protocol="HTTP/1.1" redirectPort="8443"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
<Engine defaultHost="localhost" name="Catalina1">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<Host appBase="webapps1" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
</Host>
</Engine>
</Service>

<Service name="Catalina2">
<Connector connectionTimeout="20000" port="8015" protocol="HTTP/1.1" redirectPort="8443"/>
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
<Engine defaultHost="localhost" name="Catalina2">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
<Host appBase="webapps2" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
</Host>
</Engine>
</Service>

以上三个service,发布的路径不同,项目分别发布在 webapps、webapps1、webapps2下,

访问不同的项目的方法:

1
2
3
http://localhost:8013/项目名称1
http://localhost:8014/项目名称2
http://localhost:8015/项目名称3

参考:

Tomcat 配置多个端口号或多个应用

Tomcat配置为系统服务

创建Tomcat8服务文件

1
2
touch /usr/lib/systemd/system/tomcat8.service
vim /usr/lib/systemd/system/tomcat8.service

tomcat8.service文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=Tomcat8
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
Type=forking

Environment="JAVA_HOME=/usr/local/jdk1.8.0_91"
ExecStart=/usr/local/apache-tomcat-8.5.40/bin/startup.sh
ExecReload=/usr/local/apache-tomcat-8.5.40/bin/startup.sh
ExecStop=/usr/local/apache-tomcat-8.5.40/bin/shutdown.sh

[Install]
WantedBy=multi-user.target
1
2
3
4
5
systemctl enable tomcat8.service
systemctl is-enabled tomcat8
systemctl daemon-reload
systemctl status tomcat8
systemctl restart tomcat8

验证

1
2
3
# 查看监听的端口
# Tomcat默认8080端口
netstat -lnpt

参考:

centos7配置tomcat开机自启动

CentOS 7下Tomcat 安装与配置(Tomcat开机启动)

Linux 文件打开最大数

1
2
3
4
5
6
7
8
vi /etc/security/limits.conf
* soft nproc 65535
* hard nproc 65535
* soft nofile 65535
* hard nofile 65535

# 查看当前打开文件数
lsof | wc -l

参考:Linux最大文件打开数

内核优化

方法一:修改 /proc 下内核参数文件内容,不能使用编辑器来修改内核参数文件,理由是由于内核随时可能更改这些文件中的任意一个,另外,这些内核参数文件都是虚拟文件,实际中不存在,因此不能使用编辑器进行编辑,而是使用echo命令,然后从命令行将输出重定向至 /proc 下所选定的文件中。如:将 timeout_timewait 参数设置为30秒:

echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout

参数修改后立即生效,但是重启系统后,该参数又恢复成默认值。因此,想永久更改内核参数,需要修改/etc/sysctl.conf文件

方法二.修改 /etc/sysctl.conf 文件

优化适合apachenginxsquid 多种等web应用。

文件:/etc/sysctl.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 表示套接字由本端要求关闭,这个参数决定了它保持在FIN-wAIT-2状态的时间,默认值是60秒
# server端主动发起断开连接后保持在FIN-WAIT-2状态的时间(建议30s)
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_fin_timeout 60
net.ipv4.tcp_fin_timeout = 30

## reuse和recycle这俩个参数是为防止生产环境下 web,nginx 等业务服务器 time_wait 网络状态数量过多设置的

# 表示开启重用,允许TIME-wAIT sockets重新用于新的TCP链接,默认值为0
# 表示关闭,该参数对应系统路径为:/proc/sys/net/ipv4/tcp_tw_reuse 0
net.ipv4.tcp_tw_reuse = 1

# 表示开启TCP链接中TIME_WAIT sockets的快速回收,
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_tw_recycle
# 默认为0 表示关闭,建议为0
net.ipv4.tcp_tw_recycle = 0
reuse/recycle注解:

因为TCP连接是双向的,所以在关闭连接的时候,两个方向各自都需要关闭。先发 FIN 包的一方执行的是 主动关闭;后发 FIN 包的一方执行的是 被动关闭。主动关闭的一方会进入TIME_WAIT 状态,并且在此状态停留两倍的 MSL maximum segment lifetime(最大分节生命期最大报文存活时间,这是一个IP数据包能在互联网上生存的最长时间,超过这个时间IP数据包将在网络中消失 。MSL在RFC 1122上建议是2分钟,而源自berkeley的TCP实现传统上使用30秒。一般Linux内核设置30秒 )时长。TIME_WAIT 状态维持时间是两个MSL时间长度,也就是在1-4分钟。Windows操作系统就是4分钟。

等待 2MSL 原因:

TCP目的是可靠传输,主动关闭的一方发出 FIN,被动方回复ACK,接着被动方发送 FIN ,主动方收到被动关闭的一方发出的 FIN 包后,回应 ACK 包,同时进入 TIME_WAIT 状态。但是因为网络原因,主动关闭的一方发送的这个 ACK 包很可能延迟,从而触发被动连接一方重传 FIN 包。极端情况下,这一去( ACK 去被动方)一回(重传 FIN 回来),就是两倍的 MSL 时长。

如果主动关闭的一方跳过 TIME_WAIT 直接进入 CLOSED ,或者在 TIME_WAIT 停留的时长不足两倍的 MSL ,那么当被动关闭的一方早先发出的 FIN 延迟包到达或者重传 FIN 包到达后,就可能出现类似下面的问题:

  • 主动方旧的TCP连接已经不存在了,主动方只能返回RST包
  • 主动方新的TCP连接被建立起来了,延迟包可能干扰新的连接

减少TIME_WAIT

TIME_WAIT 期间,资源不会释放,现在都追求高性能高并发,快速释放资源是躲不掉的.对于客户端因为有端口 65535 问题,TIME_WAIT 过多直接影响处理能力. 对于服务器,无端口数量限制的问题,Linux优化也很给力,每个处于 TIME_WAIT 状态下连接内存消耗很少, 而且也能通过 tcp_max_tw_buckets = ${你要的阈值} 配置最大上限,但是对于短连接为主的web服务器,几十万的连接,基数很大,耗得内存也不小,快速释放总是好的。

tcp_tw_recycle:回收TIME_WAIT连接

对客户端和服务器同时起作用,开启后在 3.5*RTO 内回收,RTO 200ms~ 120s 具体时间视网络状况。RTO(Retransmission TimeOut)重传超时时间。内网状况比 tcp_tw_reuse 稍快,公网尤其移动网络大多要比 tcp_tw_reuse 慢,优点就是能够回收服务端的 TIME_WAIT 数量。

但是,需要注意的是:当多个客户端通过NAT方式联网并与服务端交互时,服务端看到的是同一个IP,也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异,于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃。客户端处于NAT很常见,基本公司家庭网络都走NAT。

tcp_tw_reuse:复用 TIME_WAIT 连接 只对客户端起作用,1秒后才能复用,当创建新连接的时候,如果可能的话会考虑复用相应的 TIME_WAIT 连接。通常认为 tcp_tw_reuse tcp_tw_recycle 安全一些,这是因为一来 TIME_WAIT 创建时间必须超过一秒才可能会被复用;二来只有连接的时间戳是递增的时候才会被复用。

客户端请求服务器,服务器响应后主动关闭连接,TIME_WAIT 存在于服务器,服务器是被连接者,没有复用一说,所以只对客户端起作用.如果是客户端主动关闭, TIME_WAIT 存在于客户端,这个时候再次连接服务器,可以复用之前 TIME_WAIT 留下的半废品。

tcp_timestamps:以上两点,必须在客户端和服务端 timestamps 开启时才管用(默认开启) 需要根据 timestamp 的递增性来区分是否新连接

总结

客户端 tcp_tw_reuse 复用连接管用, tcp_tw_recycle 有用,但是客户端主要不是接受连接,用处不大
服务器 tcp_tw_recycle 回收连接管用,tcp_tw_reuse 复用无效.为了减少 TIME_WAIT 留在服务器,可以在服务器开启 KeepAlive ,尽量不让服务器主动关闭,而是客户端主动关闭,减少TIME_WAIT 产生。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 表示开启SYN Cookies功能,当出现SYN等待队列溢出时,启用Cookies来处理,可防范少量SYN攻击,
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_syncookies,默认为1,表示开启
net.ipv4.tcp_syncookies = 1

# 表示当keepalive启用时,TCP发送keepalive消息的频度,默认是2小时,建议更改为5分钟,
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_keepalive_time,默认为7200秒
net.ipv4.tcp_keepalive_time = 300

# 该选项用来设定允许系统打开的端口范围,用于向外链接的端口范围,
# 每个TCP客户端连接都要占用一个唯一的本地端口号(此端口号在系统的本地端口号范围限制中),
# 如果现有的TCP客户端连接已将所有的本地端口号占满。将不能创建新的TCP连接。
# 该参数对应系统路径为:/proc/sys/net/ipv4/ip_local_port_range 默认,32768 60999
# 理论上单独一个进程最多可以同时建立60000多个TCP客户端连接。
# 影响 CLOSE_WAIT 数量
net.ipv4.ip_local_port_range = 1024 65000

# 表示SYN队列的长度,默认为1024,建议加大队列的长度,为8182或更多,这样可以容纳更多等待链接的网络连接数,
# 该参数为服务器端用于记录那些尚未收到客户端确认信息的链接请求的最大值,
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_max_syn_backlog
net.ipv4.tcp_max_syn_backlog = 262144

# 该选项默认值是128,这个参数用于调节系统同时发起的TCP连接数,
# 在高并发的请求中,默认的值可能会导致链接超时或重传,因此,需要结合并发请求数来调节此值,
# 该参数对应系统路径为:/proc/sys/net/ipv4/somaxconn 128
# 默认没有这个配置,需要自己生成,somaxconn值不应超过65535
net.core.somaxconn = 32768

listen方法指定的backlog是在用户态指定的,内核态的参数优先级高于用户态的参数,所以即使在listen方法里面指定backlog是一个大于somaxconn的值,socket在内核态运行时还会检查一次somaxconn,如果连接数超过somaxconn就会等待。

在没有调优的centOS7.4版本的服务器上,由于受到系统级别的限制,在该服务器上运行的服务端程序,在同一时间,最大只能接受128个客户端发起持久连接,并且只能处理128个客户端的数据通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 表示系统同时保持 TIME_WAIT 套接字的最大数量,如果超过这个数值,TIME_WAIT 套接字将立刻被清除并打印警告信息,
# 对于Aapache,Nginx等服务器来说可以将其调低一点,如改为 5000-30000,不用业务的服务器也可以给大一点,
# 比如LVS,Squid,该参数对应系统路径为:/proc/sys/net/ipv4/tcp_max_tw_buckets
# #1st低于此值,TCP没有内存压力,2nd进入内存压力阶段,3rdTCP拒绝分配socket(单位:内存页)
net.ipv4.tcp_max_tw_buckets = 30000

# 外向syn握手重试次数
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_syn_retries,默认是6
net.ipv4.tcp_syn_retries = 1

# 为了打开对端的连接,内核需要发送一个 SYN 并附带一个回应前面一个 SYN 的 ACK。也就是所谓三次握手中的第二次握手。
# 该参数对应系统路径为:/proc/sys/net/ipv4/tcp_synack_retries,默认是5
# syn-ack握手状态重试次数,默认5,遭受SYN Flood [(SYN洪水) 是种典型的DoS (Denial of Service,拒绝服务)]攻击时改为1或2
net.ipv4.tcp_synack_retries = 1

# 网卡设备将请求放入队列的长度
# 表示当每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许发送到队列的数据包最大数,
# 该参数对应系统路径为:/proc/sys/net/ipv4/netdev_max_backlog
# 默认没有这个配置,需要自己生成
net.core.netdev_max_backlog = 2000

# 用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上,
# 如果超过这个数值,孤立链接将立即被复位并打印出警号信息,这个限制只是为了防止简单的DoS攻击,不能过分依靠这个限制甚至
# 人为减小这个值,更多的情况是增加这个值,该参数对应系统路径为:/proc/sys/net/ipv4/tcp_max_orphans
net.ipv4.tcp_max_orphans = 3276800

#开启窗口缩放功能,要支持超过64KB的TCP窗口,必须启用该值,TCP连接双方都启用时才生效
net.ipv4.tcp_window_scaling = 1

# 表示套接字接收缓冲区的内存最大值
net.core.rmem_max = 5242880

# 表示套接字发送缓冲区大小的最大值,会覆盖 net.ipv4.tcp_wmem的MAX值
net.core.wmem_max = 5242880

# 接受缓冲的大小:MIN,DEFAULT,MAX
# 即TCP读取缓冲区,单位为字节byte
net.ipv4.tcp_rmem = 16384 32768 5242880

# socket的发送缓存区分配的MIN,DEFAULT,MAX
# 发送缓冲区,单位是字节byte
net.ipv4.tcp_wmem = 16384 32768 5242880

# 1低于此值,TCP没有内存压力,2在此值下,进入内存压力阶段,3高于此值,TCP拒绝分配socket.
# net.ipv4.tcp_mem[0]:低于此值,TCP没有内存压力。
# net.ipv4.tcp_mem[1]:在此值下,进入内存压力阶段。
# net.ipv4.tcp_mem[2]:高于此值,TCP拒绝分配socket。
# 内存单位是页,1页等于4096字节,1 Page = 4096 Bytes
# 32GB内存机器,最小值、压力值、最大值:8G 12G 16G
net.ipv4.tcp_mem = 2097152 3145728 4194304

# 禁用时间戳,时间戳可以避免序列号的卷绕
net.ipv4.tcp_timestamps = 0

# 定义SYN重试次数
# 避免重复发送数据包
net.ipv4.tcp_sack = 1

# 单独一个进程最多可以同时建立20000多个TCP客户端连接
# 不建议自行设置
net.ipv4.ip_conntrack_max = 20000

/etc/sysctl.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.ip_local_port_range = 1024 65000
net.ipv4.tcp_max_syn_backlog = 262144
net.core.somaxconn = 65535
net.ipv4.tcp_max_tw_buckets = 30000
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_synack_retries = 1
net.core.netdev_max_backlog = 2000
net.ipv4.tcp_window_scaling = 1
net.core.rmem_max = 5242880
net.core.rmem_default = 256960
net.core.wmem_max = 5242880
net.core.wmem_default = 256960
net.ipv4.tcp_rmem = 16384 32768 5242880
net.ipv4.tcp_wmem = 16384 32768 5242880
net.ipv4.tcp_mem = 2097152 3145728 4194304
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_sack = 1

查看系统级文件句柄修改,是否生效

1
sysctl -p

备忘录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 获取操作系统参数的类型
sysctl -a|awk -F "." '{print $1}'|sort -k1|uniq

# 获取net类型下的子类型
sysctl -a|grep "^net."|awk -F "[.| ]" '{print $2}'|sort -k1|uniq

# 获取有关服务器套接字缓冲区的信息
sysctl -a|grep "^net."|grep "[r|w|_]mem[_| ]"

# 查看当前的连接数状况
# SYN_RECV表示正在等待处理的请求数;ESTABLISHED表示正常数据传输状态;TIME_WAIT表示处理完毕,等待超时结束的请求数
netstat -nat|awk '{print awk $NF}'|sort|uniq -c|sort -n

# 查看IP连接数状况
netstat -nat|grep ":8011"|awk '{print $5}' |awk -F: '{print $1}' | sort| uniq -c|sort -n

# 查看活动连接数
ss -n | grep ESTAB | wc -l

# 获取当前socket连接状态统计信息
cat /proc/net/sockstat

# 统计当前各种状态的连接的数量的命令
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

# 返回结果如下:
LAST_ACK 14
SYN_RECV 348
ESTABLISHED 70
FIN_WAIT1 229
FIN_WAIT2 30
CLOSING 33
TIME_WAIT 18122

# 对上述结果的解释:
CLOSED:无连接是活动的或正在进行
LISTEN:服务器在等待进入呼叫
SYN_RECV:一个连接请求已经到达,等待确认
SYN_SENT:应用已经开始,打开一个连接
ESTABLISHED:正常数据传输状态
FIN_WAIT1:应用说它已经完成
FIN_WAIT2:另一边已同意释放
ITMED_WAIT:等待所有分组死掉
CLOSING:两边同时尝试关闭
TIME_WAIT:另一边已初始化一个释放
LAST_ACK:等待所有分组死掉

参考:

Linux内核 TCP/IP、Socket参数调优

Linux系统优化实现高并发

Linux内核优化

Linux 下高并发系统内核优化

centos7之系统优化方案

Linux 内核优化-调大TCP最大连接数

这个错是链接时报的错,要链接必须启动。修复的时候首先要启动mysql。

首先来了解一下 mysql.sock 的作用:

Mysql有两种连接方式:

(1)TCP/IP
(2)socket

mysql.sock来说,其作用是程序与 mysql server 处于同一台机器,发起本地连接时可用。
例如你无须定义连接 host 的具体IP,只要为空或 localhost 就可以。
在此种情况下,即使你改变 mysql 的外部 port 也是一样可能正常连接。
因为你在 my.ini 中或 my.cnf 中改变端口后,mysql.sock 是随每一次 mysql server启动生成的。已经根据你在更改完 my.cnf 后重启 mysql 时重新生成了一次,信息已跟着变更。

那么对于外部连接,必须是要变更port才能连接的。
mysql.sock 的作用是 serverclient 在同一台服务器,并且使用 localhost 进行链接的时候,就会使用socket来进行连接——仅此而已
也就是:为主机名为 localhost 建立的MySQL连接,该连接过程通过一个套接字文件 mysql.socket 实现的。所以该文件被删后,用 localhost 用户是连接不到MySQL服务器的。

必须建立一条 tcp/ip 连接,即使用 127.0.0.1 而不是 localhost 作为-h的参数去连接MySQL服务器,如:mysqladmin -h 127.0.0.1 -u root -p shutdown,强制地建立一条 tcp/ip 连接;
关闭MySQL服务器,再重新以 localhost 为主机名启动MySQL服务器,它就会重新创建一个套接字文件。

注意:mysql.sock 是一个临时文件,启动mysql后才会生成。
报错的原因:MySQL将其放在 /tmp 目录,而linux将其放在 /var/mysql 目录。所以我们只需要创建一个软链接,输入以下两个命令即可:
如果 /var/ 下没有 mysql目录,则需创建

创建目录:sudo mkdir /var/mysql

创建软链接:sudo ln -s /var/mysql/mysql.sock /tmp/mysql.sock

如果提示: ln: creating symbolic link /var/lib/mysql/mysql.sock’: File exists删除之前的mysql.sock` 文件。

参考:

ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/lib/mysql/mysql.sock’ (2)

MySql 报错ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (2)

中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using Model.Base;
using Service.MonitorLog;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Diagnostics;
using System.IO;

namespace Test
{
public static class CustomLoggingMiddleware
{
public static void UseCustomLogging(this IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
var requestContent = "";
var contentType = context.Request.ContentType;
context.Request.EnableBuffering();
// 只接受json格式参数,防止文件流等参数超长
if (!string.IsNullOrWhiteSpace(contentType) && contentType.Contains("json", StringComparison.OrdinalIgnoreCase))
{
var requestReader = new StreamReader(context.Request.Body);
requestContent = await requestReader.ReadToEndAsync();
}
context.Request.Body.Position = 0;

monitorlog ml = new monitorlog();

var dt = DateTime.Now;

ml.id = 0;
ml.jkmc = context.Request.Path;
ml.qqfs = context.Request.Method;
ml.qqcs_txt = requestContent;

Stream originalBody = context.Response.Body;
try
{
await using var memStream = new MemoryStream();
context.Response.Body = memStream;
await next();
memStream.Position = 0;
string responseBody = await (new StreamReader(memStream)).ReadToEndAsync();
ml.xyjg_txt = responseBody;

memStream.Position = 0;
await memStream.CopyToAsync(originalBody);
}
finally
{
context.Response.Body = originalBody;
}

ml.statuscode = context.Response.StatusCode;
if (ml.statuscode == 200)
await MonitorLog.SaveMonitorLog(ml);
});
}
}
}

使用

Startup.csConfigure 方法添加如下代码:

1
app.UseCustomLogging();

支持IPV4端口

/conf/context.xml

1
2
3
4
<Connector port="80" maxHttpHeaderSize="8192" 
maxThreads="300" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />

添加: address="0.0.0.0"

1
2
3
4
<Connector port="80" maxHttpHeaderSize="8192" address="0.0.0.0"
maxThreads="300" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" />

只支持IP4

linux平台

<tomcat>/bin 目录下 catalina.sh,添加如下内容:

vim catalina.sh,然后输入 / 搜索 JAVA_OPTS,

n 向下查找
N 向上查找

微信截图_20200831141600.png

1
2
# 添加以下内容
JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv4Addresses=true "

windows

编辑 bin 目录下的 catalina.bat 文件,改成以下内容:

1
set "JAVA_OPTS=%JAVA_OPTS% -Djava.net.preferIPv4Stack=true %JSSE_OPTS%"

参考

如何让tomcat只支持ipv4

简介

Linux cp命令主要用于复制文件或目录。

语法

1
2
3
4
cp [options] source dest

# 或
cp [options] source... directory

参数说明:

  • -a:此选项通常在复制目录时使用,它保留链接、文件属性,并复制目录下的所有内容。其作用等于dpR参数组合。
  • -d:复制时保留链接。这里所说的链接相当于Windows系统中的快捷方式。
  • -f:覆盖已经存在的目标文件而不给出提示。
  • -i:与-f选项相反,在覆盖目标文件之前给出提示,要求用户确认是否覆盖,回答”y”时目标文件将被覆盖。
  • -p:除复制文件的内容外,还把修改时间和访问权限也复制到新文件中。
  • -r:若给出的源文件是一个目录文件,此时将复制该目录下所有的子目录和文件。
  • -l:不复制文件,只是生成链接文件。

实例

使用指令 cp 将当前目录 test/ 下的所有文件复制到新目录 newtest 下,输入如下命令:

cp –r test/ newtest

注意:用户使用该指令复制目录时,必须使用参数 -r 或者 -R

参考

Linux cp命令

下载

https://tomcat.apache.org/

安装

1
2
3
4
5
6
7
8
9
10
11
# 解压的 /usr/local
tar -zxvf apache-tomcat-8.5.40.tar.gz -C /usr/local

# 进入 目录
cd /usr/local/apache-tomcat-8.5.40/bin

# 启动
./startup.sh

# 停止
./shutdown.sh

验证

1
2
3
# 查看监听的端口
# Tomcat默认8080端口
netstat -lnpt
0%