把服务包部署到多台设备
多台机器一起向外提供服务,合并在一起的软件:niginx
多台机器合并在一起:集群
nginx负载均衡,反向代理
nginx里面记录不同机器的ip,配置不同的分配策略
nginx:web服务器,并不一定是一般理解的前台服务
前后分离:front+server
负载均衡
最典型的软件是nginx
也可以是硬件F5
阿里云的SLB,也是一个软件负载均衡
tomcat
需要有jdk
目录
bin:启动、关闭tomcat的文件。startup、shutdown为启动文件,catalina文件为配置文件
conf:配置文件。server.xml为最重要的配置文件
logs:项目运行时,默认日志路径。在没有修改默认日志路径时,运行日志记录在该路径下
webapps:项目包防止路径。把wat包,放在这个路径下,启动tomcat会自动解压
catalina.bat「Windows」、catalina.sh「Linux」
在执行startup文件启动tomcat时,会去执行catalina文件
catalina文件中, 设置堆栈信息
JAVA_OPTS="-server -Xms256m -Xmx512m -Xss256k -XX:PermSize=128m"
-server:第一个参数,指定为服务,多核时使用
-Xms:启动时,初始堆大小;没有配置时,从最小逐步增加到最大值
-Xmx:运行时分配的最大堆大小;默认64M
-Xmn:新生代堆大小
-Xss:每个线程栈大小
-XX:PermSize:初始化非内存大小
-XX:MaxPermSize:永久代(非堆)最大内存大小
-XX:MaxNewSize:新生代最大大小
catalina文件中, 设置GC
JAVA_OPTS="-verbose:gc -XX+PrintGC -XX:PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:filename"
-verbose:gc:显示垃圾回收信息
-XX:+UseParNewGC:设置minor收集的时间
-XX:+UseConcMarkSweepGC:设置major收集时间
设置并行收集器:
-XX:ParallelGCThreads=n:设置并行收集器收时使用的CPU数,并行收集线程数。
-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间
-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比
设置并发收集器:
-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况
-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数,并行收集线程数
写GC日志,是要消耗IO的,所以在生成环境,一般不配置这个
conf/server.xml
Tomcat中最顶层的是server,代表整个服务器,一个server可以包含至少一个service,每个service可以包含多个connector和一个container。Connector用于处理连接相关的事情,并提供Socket与Request和Response相关的转化;Container用于封装和管理Servlet,以及具体Request请求;多个connector就可以配置多种类型连接,如http、https
不同的protocol
Connector在处理HTTP请求时,会使用不同的protocol,典型的有:
BIO:BlockingIO阻塞(tomcat7支持,8支持NIO2,8.5\9去掉了BIO)默认值为maxThreads值
NIO:Non-blockingIO非阻塞IO,默认值10000
APR:ApachePortableRuntime Apache可移植运行库,是高并发的首选模式;默认值8192,需要安装apr、apr_utils、tomcat-native包
Protocol默认是HTTP/1.1,不同版本,会自动选择上面的模式(APR模式需要有相应的包才会自动选择)
Connector重要参数
connectionsTimeout:连接超时时间,单位毫秒
acceptCount:能接收的队列长度,队列满了,再有连接就会拒绝,默认100
maxConnections:任意时刻能接受和处理的最大连接数。达到最大值,就会阻塞accept连接。如果设置为-1,则连接数不受限制
maxThreads:请求处理线程的最大数量。默认为200
minSpareThreads:tomcat初始化默认时默认创建的线程数,也是以后线程增加时一次增加的最小数量
maxSpareThreads:这个参数标识,一旦创建的线程数量超过了这个值,Tomcat就会关闭不活动的线程
连接数不够
修改如下内容:
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/>
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" acceptCount="1000"/>
name:线程池的标记
namePrefix:线程名字前缀
maxThreads:线程池中最大活跃线程数,默认200
minSpareThreads:线程池中保存的最小线程数,也是线程每次增加的最小值,默认25
connectionTimrout:连接超时时间,单位毫秒
accepCount:最大可接受的排队数量
maxSpareThreads:一旦创建的线程数量超过这个数值,Tomcat就会关闭不活动的线程
tomcat监控环境搭建
gragana + prometheus监控tomcat
下载jvm_exporter.jar
下载地址:https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/
将jvm_exporter.jar
放到tomcat的bin文件夹下
配置tomcat.yml到tomcat的bin文件夹下
---
lowercaseOutputLabelNames: true
lowercaseOutputName: true
rules:
- pattern: 'Catalina<type=GlobalRequestProcessor, name=\"(\w+-\w+)-(\d+)\"><>(\w+):'
name: tomcat_$3_total
labels:
port: "$2"
protocol: "$1"
help: Tomcat global $3
type: COUNTER
- pattern: 'Catalina<j2eeType=Servlet, WebModule=//([-a-zA-Z0-9+&@#/%?=~_|!:.,;]*[-a-zA-Z0-9+&@#/%=~_|]), name=([-a-zA-Z0-9+/$%~_-|!.]*), J2EEApplication=none, J2EEServer=none><>(requestCount|maxTime|processingTime|errorCount):'
name: tomcat_servlet_$3_total
labels:
module: "$1"
servlet: "$2"
help: Tomcat servlet $3 total
type: COUNTER
- pattern: 'Catalina<type=ThreadPool, name="(\w+-\w+)-(\d+)"><>(currentThreadCount|currentThreadsBusy|keepAliveCount|pollerThreadCount|connectionCount):'
name: tomcat_threadpool_$3
labels:
port: "$2"
protocol: "$1"
help: Tomcat threadpool $3
type: GAUGE
- pattern: 'Catalina<type=Manager, host=([-a-zA-Z0-9+&@#/%?=~_|!:.,;]*[-a-zA-Z0-9+&@#/%=~_|]), context=([-a-zA-Z0-9+/$%~_-|!.]*)><>(processingTime|sessionCounter|rejectedSessions|expiredSessions):'
name: tomcat_session_$3_total
labels:
context: "$2"
host: "$1"
help: Tomcat session $3 total
type: COUNTER
- pattern: ".*"
配置catalina.sh
JAVA_OPTS="-javaagent:./jmx_prometheus_javaagent-0.14.0.jar=3088:./tomcat.yml"
启动tomcat
配置prometheus
配置prometheus.yml文件
- job_name:"tomcat_export"
static_configs:
- targets:["被监控机器IP:3088"]
配置grafana
添加数据源:URL
http://prometheus_ip:9000
引入模版:8563或3457
名称:自定义
job修改为prometheus.yml文件中的job_name
GC分析
https://gceasy.io/
nginx
是一个用C语言编写的高性能HTTP服务器,反向代理web服务器
占用内存小
并发能力强
worker_processes 1;
events {
use epoll;
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream web_app {
server 192.168.114.139:8080 weight=1 max_fails=2 fail_timeout=30;
server 192.168.114.139:8880 weight=1 max_fails=2 fail_timeout=30;
}
server {
listen 80;
server_name 192.168.114.139;
location / {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://web_app;
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
niginx+tomcat负载均衡
轮询
默认策略,如果服务器down掉了,会自动剔除该服务器,此策略适合服务器配置相当,无状态且短平快的服务使用
weight权重
权重越高分配到需要处理的请求越多,此策略可以与least_conn和ip_hash结合使用,此策略比较适合服务器的硬件配置差别比较大的情况
ip_hash依据ip分配
ip_hash不能与backup同时使用,此策略适合有状态服务,比如session,服务器需要剔除,必须手动down掉
least_conn最小连接
此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况
fair响应时间
负载均衡策略的实现需要安装第三方插件,按照服务器端的响应时间来分配请求,响应时间短的优先分配
url_hash依据url分配
按访问url结果来分配请求,使每个url定向到同一个后端服务器,要配合缓存命中来使用
niginx常用配置
对niginx监控
使用nginx-module-vts
与nginx-vts-exporter
nginx-module-vts: Nginx virtual host traffic status module,nginx的监控模块,能够提供json、html、prometheus格式的数据产出。
nginx-vts-exporter: Simple server that scrapes Nginx vts stats and exports them via HTTP for Prometheus consumption。主要用于收集nginx的监控数据,并给Prometheus提供监控接口,默认端口号9913。
如何测试集群的性能
首先,需要有一个集群,就要安装项目的集群环境搭建的标准,搭建一套集群环境,只是此时,集群规模不需要做那么大,自己搭建一套最小的集群(至少是两个相同服务构成的一个集群)
然后,对该集群进行性能测试,得到最小规模的集群的性能指标
然后,再在集群中,添加服务,此时集群有3个服务,然后再对集群进行一次性能测试,此时3个服务构成的集群的性能指标tps增加了多少,并发用户增加了多少,那么理论上,可以计算出增加服务后tps等指标的增加情况
数据库
数据:描述事物的符号记录,符号可以是数字,文字,图片,图像,声音,语言
数据库:存放数据的仓库,这个仓库是计算机存储设备,而且数据是按一定的格式存放的
在企业项目中,数据库的读操作更频繁
dbms
关系型数据库
采用关系模型来组织数据库的数据,以行+列方式存储数据
结构化方式存储数据库
标准的结构化查询语句「SQL」标准的增删改查
事物性,寻找ACID规则「原子性、一致性、隔离性、持久性」
sql有四种
DCL数据库控制语言「Data Control Language」用来确认或取消数据库用户和角色权限变更
DDL数据库定义语言「Data Definition Language」用来创建或删除数据库以及表
DML数据库操作语言「Data Mainpulation Language」用来变更表数据记录
DQL数据库查询语言「Data Query Language」用来查询表中的记录
非关系型数据库NoSQL「Not only SQL」
选择数据库需要注意
IO性能比较好的
磁盘空间比较大
稳定性
数据库缓存
数据库的缓存有两部分
数据库本身的缓存
专门做缓存的数据库
数据库拆分
直接拆数据库
分表分区
存储引擎
mysql数据库建表的时候,有一个存储引擎,可以选择,默认为InnoDB
数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据库引擎进行创建,查询,更新和删除数据操作。
存储引擎就是指表的类型。数据库的存储引擎决定了表在计算机中的存储方式。不同的存储引擎提供不同的存储机制,索引技巧,锁定水平等功能,使用不同的存储引擎还可以获得特定的功能
例如,存在两张表:一个配置表,一个用户表
配置表,一般在项目启动的时候,读取一次,在项目运行过程中,一般都不会去修改
用户信息表:在项目启动时,不会去读取,但是在项目运行过程中,随时都有可能修改
所以,它们的使用场景不一样,创建表时会选择不同的搜索引擎
配置表一般选用MyISM
存储引擎
用户信息表一般选用InnoDB
mysql数据库5.5版本及以前
默认存储引擎为
MyISM
追求存储数据的速度,存储数据不准
锁,表锁,会锁定整张表
索引:B树索引
mysql数据库5.5版本及以后
默认存储引擎为
InnoDB
追求存储数据的准确性,事务一致性
锁,行锁,会锁定当前行
索引:默认B+树索引
B+树的优点:
树的层次更低,IO次数更少
每次查询的结果都是在叶子节点,查询性能稳定
叶子节点形成链表,范围查询更方便
索引
是一种数据结构,用于帮助我们在大量数据中快速定位我们要查找的数据
建索引:使用空间换时间,索引有一定大小,占磁盘、内存空间,以此来换取时间更少。是为了提升查询数据的速度,它会降低修改速度
主键索引:有且仅有一个
create index 索引名 on 表名(字段); ALTER TABLE 表名 ADD INDEX 索引名(字段);
唯一索引:不可重复,但是可以存储NULL
create unique index 索引名 on 表名(字段);
复合索引:由表的多列按照顺序组合成为索引,使用时,按照组合顺序使用索引,也可以使用组合索引中部分索引字段
create index 索引名 on 表名(字段1,字段2....)
create index index_name on name(id,co3,co2);
select * from tb_name where id=?,co3=? 使用了索引
select * from tb_name where id=?,co2=?
select * from tb_name where co3=?,co2=?
select * from tb_name where co2=?,co3=?
select * from tb_name where id=?,co3=?,co2=? 使用了索引
select * from tb_name where id=?,co2=?,co3=?
select * from tb_name where id=? 使用了索引
索引的弊端
索引本身很大,通常存放在磁盘或内存
不是索引情况都可以用索引,数据库很少,列值比频繁变更,列很少使用
索引会降低增删改的效率,但是一般会提升查的效率
索引的优势
降低IO、CPU使用率
索引列,可以保证行的唯一性
可以有效缩短数据检索时间
加快表与表之间的连接
Select
语法
SELECT {*|字段列名} 查询要显示的列名
FROM <表名1>,<表名2> join, on 数据来源表
WHERE <表达式> 限制条件
GROUP BY<字段> 查询的结果,按照条件字段分组
HAVING <expression> 过滤分组
ORDER BY <字段> 按照字段排序
LIMIT <offset>[<row count>] 显示数据条数
sql语句的执行顺序,与编写顺序会不一致
sql执行过程:
输入数据库的ip,端口,账号,密码「连接层」
提供各种接口,CRUD,对脚本进行优化「服务层」
执行你的sql「引擎层」
数据交换「存储层」
数据库管理系统dbms,写数据时,把你的数据,转化为日志文件,对日志文件进行解读,还原你的日志过程
select的解析过程
from table_name 数据源中捞取数据
where 条件 对捞取的数据进行条件过滤
group by 分组
根据上面的条件字段来分组「建议where条件字段」
不按照上面的条件字段来分组「会产生临时表」
having 分组过滤
select 字段
order by 建议使用select 字段来排序
limit 数据量
数据库性能优化
数据库库层面的优化「os」
sysctl
ulimit
数据库配置文件
/etc/my.cnf
SHOW VARIABLES;
SHOW VARIABLES LIKE '%slow_query_log%' 查看慢查询的开关与日志路径 默认10秒为慢查询
SHOW VARIABLES LIKE 'long_query_time' 慢查询的阈值默认10秒
SHOW VARIABLES LIKE 'max_connections%' 查看系统配置的最大连接数
SHOW VARIABLES LIKE 'Max_used_connections' 查看当前用户已经建立的连接数
当出现ERROR 1040:Too many connections
可以通过修改连接数来解决
定位慢查询日志
开启慢查询的开关
因为,数据中慢查询日志,一般情况下都是关闭的,因为慢查询的开启,就要写日志,会消耗IO。
所以在生产数据库中,建议千万不要去开启
我们用jmeter做性能测试,设计了一个性能场景,运行,发现在一定量的并发用户时,平均响应时间,已经超过了1秒钟,那么,我们可以说,可能存在了慢查询日志。
响应时间都没有超过1秒(阈值),那么肯定没有慢查询日志。
SQL优化
explain sql语句
id:编号
id相同时,从上往下执行
id不同时,从大到小
select type:查询语句
SIMPLE:简单的SELECT,不使用union或子查询
PRIMARY:查询中包含复杂的子查询,最外层的select被标记为PRIMARY
UNION:union中第二个或后面的select语句
DEPENDENT UNION:union中的第二个或后面的select语句,取决于外面的查询
UNION RESULT:union的结果
SUBQUERY:子查询的第一个select
DEPENDENT SUBQUERY:子查询中的第一个select,取决于外面的查询
DERIVD:衍生查询,使用临时表(select from子句的子查询)
UNCACHEABLE SUBQUERY:一个子查询的结果不能被缓存,必须重新评估外链接的第一行
table:表
type:类型
All:全表扫描Full table scan
index:遍历索引数据 Full index scan
range:使用一个索引来检索给定范围的行
ref:使用了索引列上值进行查询
eq_ref:类似ref,只是使用的索引为唯一索引
const,system:MySQL对查询某部分进行优化,并转化为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转化为一个常量,system上const类型的特例,当查询的表只有一行的情况下,使用system
Null:MySQl在优化过程中分解语句,执行时甚至不用访问表或索引
性能效率:system > const > eq_ref > ref > range > index > all 左边效率高于右边
possible_keys:预测用到的索引
key:实际用到的索引
key_len:实际使用索引的长度
ref:表之间的匹配条件
rows:通过索引查询到的数据量
filtered:
Extra:额外的信息
Using where:显示的字段不在索引(select 的字段,有的不再索引中,要从源table表中查询)
Using index:使用了索引,不用回表查询,能够起到性能提升
Using temporary:使用了临时表,性能消耗比较大,常见于group by语句
Using fileSort:使用文件排序,无法利用索引完成排序操作,性能消耗非常大,常见于order by语句
Using join buffer:mysql引擎使用了链接缓存
Impossible where:where子句永远为false
Select tables optimized away:仅通过使用索引,优化器可能仅从聚合函数结果返回一行
NULL:
using where 使用where条件过滤,但是where条件不在索引,那我们就要考虑用和where后面的字段来建索引
优化方法
在写on语句时,将数据量小的表放在左边
where后面的条件尽可能用索引字段,复合索引时,最好按复合索引顺序写where条件
where后面有in语句,in字段的索引,最好放复合索引的后面,因为in的字段索引可能会失效
模糊查询时,尽量用常量开头,不要用%开头,用%开头查询索引将失效
尽量不要使用or,否则索引失效
尽量不要使用类型转化(显式、隐式),否则索引失效
如果主查询数据量大,则使用in
如果子查询数据量大,则使用exists
查询哪些列,就根据哪些列group by,不然会产生一个临时表
库优化
os配置修改
数据库的配置参数
数据库 <=> 应用程序 <=> 配置文件
表优化
表存储引擎
表结构(拆表)
表建立索引
慢sql:根据分析结果调整索引,开发人员修改自己的sql
主从同步
分表分区
主从同步
数据同步
读写分离
在主数据库中做任何操作,在从数据库中,都会重复一次
在从数据库中修改,主数据库是不会变化的
所以主数据库进行写操作,从数据库进行读操作
可以手动设置同步时间间隔
分表分区
分表
拆列:一张表多列,被拆到多张表「垂直分表」
表字段变少,行数不变
拆行:一张表某些行,被拆到另外行「水平分表」
表字段不变,行数变少
分区
把数据存到不同地方