先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新软件测试全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注软件测试)
正文
整理下实施ELK最起码要实现的需求:
- 查询条件(精确匹配):一级域名、二级域名、客户真实IP、HTTP状态码、HTTP方法、request_time、response_time、代理IP、body_bytes_sent
- 查询条件(模糊匹配):url(如查找SQL注入关键字)、refere(流量来源)、agent(如查找搜索引擎)
- 近期(1周、1个月)内整体请求量走势情况;
- 如果发现总体走势异常,要很方便找到那个域名走势异常;
- 过去一个周期内(1天、1周、1月)所有请求构成,按不同域名出饼图;
- 实时监控爬虫IP过高的频率访问(如单个IP1分钟请求超过100次报警);
- 实时监控500状态请求情况(如单个域名1分钟出现30个500就报警);
- ……
2.拓扑
nginx需要配置syslog协议输出;
logstash作为syslog服务器,收集日志,输出2个方向:elastersearch入库,本地文件;
elasticsearch需要设计好模型,目的:支持不同字段的查找需求(精确或模糊,甚至某个字段同时要支持精确+模糊,不过我没用到)、空间不浪费;
kibana可视化,主要是配置Discovery\Visualize;
elastalert,配置各种规则,实现实时监控需求。
3.nginx配置
nginx.conf
日志以json格式输出,方便logstash解析;
因为syslog协议一条消息最大2K,因此有些变了做了阶段(_short后缀的变量);
level1domain、level2domain分别指一级域名、二级域名;
log_format main_json ‘{“project”:“
l
e
v
e
l
1
d
o
m
a
i
n
"
,
"
d
o
m
a
i
n
"
:
"
{level1domain}","domain":"
level1domain","domain":"{level1domain}_
l
e
v
e
l
2
d
o
m
a
i
n
"
,
"
r
e
a
l
i
p
"
:
"
{level2domain}","real_ip":"
level2domain","realip":"real_ip”,“http_x_forwarded_for”:“KaTeX parse error: Double subscript at position 7: http_x_̲forwarded_for",…time_iso8601”,"
request":“
r
e
q
u
e
s
t
s
h
o
r
t
"
,
"
r
e
q
u
e
s
t
b
o
d
y
"
:
"
request_short","request_body":"
requestshort","requestbody":"request_body_short”,“status”:
s
t
a
t
u
s
,
"
b
o
d
y
b
y
t
e
s
s
e
n
t
"
:
"
status,"body_bytes_sent":"
status,"bodybytessent":"body_bytes_sent",“http_referer”:“
h
t
t
p
r
e
f
e
r
e
r
s
h
o
r
t
"
,
"
u
p
s
t
r
e
a
m
r
e
s
p
o
n
s
e
t
i
m
e
"
:
"
http_referer_short","upstream_response_time":"
httpreferershort","upstreamresponsetime":"upstream_re
sponse_time”,“request_time”:“
r
e
q
u
e
s
t
t
i
m
e
"
,
"
h
t
t
p
u
s
e
r
a
g
e
n
t
"
:
"
request_time","http_user_agent":"
requesttime","httpuseragent":"http_user_agent”}’;
location.conf
#取前750个字节
if ( $request ~ “^(.{0,750})” ) {
set $request_short $1;
}
#取前750个字节
if ( $request_body ~ “^(.{0,750})” ) {
set $request_body_short $1;
}
#取前100个字节
set $http_referer_short “-”;
if ( $http_referer ~ “^(.{1,100})” ) {
set $http_referer_short KaTeX parse error: Expected 'EOF', got '}' at position 4: 1; }̲ #从http_x_forward_for中获取第一个IP,作为客户端实际IP
set $real_ip $remote_addr;
if ( $http_x_forwarded_for ~ “^(\d+.\d+.\d+.\d+)” ) {
set $real_ip KaTeX parse error: Expected 'EOF', got '}' at position 4: 1; }̲ #server_name的格…level1domain
#解析一级域名之前的部分为$level2domain
set $level1domain unparse;
set $level2domain unparse;
if (
s
e
r
v
e
r
n
a
m
e
"
(
.
+
)
(
˙
[
0
−
9
a
−
z
A
−
Z
]
+
)
(
˙
c
o
m
∣
c
n
)
server_name ~ "^(.+)\.([0-9a-zA-Z]+)\.(com|cn)
servername "(.+)(˙[0−9a−zA−Z]+)(˙com∣cn)" ) {
set $level1domain $2;
set $level2domain $1;
}
if (
s
e
r
v
e
r
n
a
m
e
"
(
[
0
−
9
a
−
z
A
−
Z
]
+
)
(
˙
c
o
m
∣
c
n
)
server_name ~ "^([0-9a-zA-Z]+)\.(com|cn)
servername "([0−9a−zA−Z]+)(˙com∣cn)" ) {
set $level1domain $1;
set $level2domain none;
}
#syslog输出配置
access_log syslog:local7:info:logstash_ip:515:nginx main_json;
4.logstash配置
安装:
安装jdk8
解压logstash-6.2.1.tar.gz
查看插件:
./logstash-plugin list | grep syslog
安装非默认插件
./logstash-plugin install logstash-filter-alter
测试:
./logstash -e ‘input { stdin { } } output { stdout {} }’
启动:
启动logstash:nohup ./bin/logstash -f mylogstash.conf & disown
配置:
mylogstash.conf
input {
syslog {
type => “system-syslog”
port => 515
}
}
filter {
#在json化之前,使用mutte对\x字符串进行替换,防止以下错误:ParserError: Unrecognized character escape ‘x’ (code 120)
mutate {
gsub => [“message”, “\x”, “\\x”]
}
json {
source => “message”
#删除无用字段,节约空间
remove_field => “message”
remove_field => “severity”
remove_field => “pid”
remove_field => “logsource”
remove_field => “timestamp”
remove_field => “facility_label”
remove_field => “type”
remove_field => “facility”
remove_field => “@version”
remove_field => “priority”
remove_field => “severity_label”
}
date {
#用nginx请求时间替换logstash生成的时间
match => [“time_local”, “ISO8601”]
target => “@timestamp”
}
grok {
#从时间中获取day
match => { “time_local” => “(?.{10})” }
}
grok {
#将request解析成2个字段:method\url
match => { “request” => “%{WORD:method} (?.* )” }
}
grok {
#截取http_referer问号前的部分,问号后的信息无价值,浪费空间
match => { “http_referer” => “(?-|%{URIPROTO}😕/(?:%{USER}(?::[^@]*)?@)?(?:%{URIHOST})?)” }
}
mutate {
#解析出新的字段后,原字段丢弃
remove_field => “request”
remove_field => “http_referer”
rename => { “http_user_agent” => “agent” }
rename => { “upstream_response_time” => “response_time” }
rename => { “host” => “log_source” }
rename => { “http_x_forwarded_for” => “x_forwarded_for” }
#以下2个字段以逗号分隔后,以数组形式入库
split => { “x_forwarded_for” => ", " }
split => { “response_time” => ", " }
}
alter {
#不满足elasticsearch索引模型的,入库会失败,因此做以下数据转换
condrewrite => [
“x_forwarded_for”, “-”, “0.0.0.0”,
“x_forwarded_for”, “unknown”, “0.0.0.0”,
“response_time”, “-”, “0”,
“real_ip”, “”, “0.0.0.0”
]
}
}
output {
#入库,以template指定的模型作为索引模型
elasticsearch {
hosts => [“elasticsearch_ip:9200”]
index => “nginx-%{day}”
manage_template => true
template_overwrite => true
template_name => “mynginx”
template => “/root/logstash/mynginxtemplate.json”
codec => json
}
#本地文件放一份,作为ELK的补充
file {
flush_interval => 600
path => ‘/nginxlog/%{day}/%{domain}.log’
codec => line { format => ‘<%{time_local}> <%{real_ip}> <%{method}> <%{url}> <%{status}> <%{request_time}> <%{response_time}> <%{body_bytes_sent}> <%{request_body}> <%{referer}> <%{x_f
orwarded_for}> <%{log_source}> <%{agent}>’}
}
}
mynginxtemplate.json
{
“template”: “nginx-*”,
“settings”: {
“index.number_of_shards”: 8,
“number_of_replicas”: 0,
“analysis”: {
“analyzer”: {
#自定义stop关键字,不收集http等字段的索引
“stop_url”: {
“type”: “stop”,
“stopwords”: [“http”,“https”,“www”,“com”,“cn”,“net”]
}
}
}
},
“mappings” : {
“doc” : {
“properties” : {
index:true 分词、生产搜索引擎
analyzer:指定索引分析器
“referer”: {
“type”: “text”,
“norms”: false,
“index”: true,
“analyzer”: “stop_url”
},
“agent”: {
“type”: “text”,
“norms”: false,
“index”: true
},
IP字段类型
“real_ip”: {
“type”: “ip”
},
“x_forwarded_for”: {
“type”: “ip”
},
keyword,作为完整字段索引,不可分词索引
“status”: {
“type”: “keyword”
},
“method”: {
“type”: “keyword”
},
“url”: {
“type”: “text”,
“norms”: false,
“index”: true,
“analyzer”: “stop_url”
},
“status”: {
“type”: “keyword”
},
“response_time”: {
“type”: “half_float”
},
“request_time”: {
“type”: “half_float”
},
“domain”: {
“type”: “keyword”
},
“project”: {
“type”: “keyword”
},
“request_body”: {
“type”: “text”,
“norms”: false,
“index”: true
},
“body_bytes_sent”: {
“type”: “long”
},
“log_source”: {
“type”: “ip”
},
“@timestamp” : {
“type” : “date”,
“format” : “dateOptionalTime”,
“doc_values” : true
},
“time_local”: {
“enabled”: false
},
“day”: {
“enabled”: false
}
}
}
}
}
5.elasticsearch配置
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注软件测试)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
y": {
“enabled”: false
}
}
}
}
}
5.elasticsearch配置
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注软件测试)
[外链图片转存中…(img-1Pu9DnFg-1713300920603)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!