0%

0x00 阅读源代码

下载源代码

  • 阅读版本号 netty-4.1.33.Final
    • 由于github下载速度是在太慢了,这里用gitee克隆一个镜像。
    • 下载版本git clone -b netty-4.1.33.Final git@gitee.com:Z201/netty.git

查看源代码结构

  • 查看项目主要文件夹
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
tree -d  -L 1    
├── all
├── bom
├── buffer (Core netty定制的buffer)
├── codec (Protocol Support)
├── codec-dns (Protocol Support)
├── codec-haproxy (Protocol Support)
├── codec-http (Protocol Support)
├── codec-http2 (Protocol Support)
├── codec-memcache (Protocol Support)
├── codec-mqtt (Protocol Support 物联网)
├── codec-redis (Protocol Support )
├── codec-smtp (Protocol Support 邮件)
├── codec-socks (Protocol Support)
├── codec-stomp (Protocol Support ws)
├── codec-xml (Protocol Support)
├── common (Core)
├── dev-tools
├── docker
├── example (抄代码的地方)
├── handler (Protocol Support)
├── handler-proxy (Protocol Support)
├── license
├── microbench (测试用的)
├── resolver (Core)
├── resolver-dns (Core)
├── tarball
├── target
├── testsuite
├── testsuite-autobahn
├── testsuite-http2
├── testsuite-osgi
├── testsuite-shading
├── transport (Transport Services)
├── transport-native-epoll (Transport Servicesnative omitted - reserved keyword in Java)
├── transport-native-kqueue (Transport Servicesnative omitted - reserved keyword in Java)
├── transport-native-unix-common Transport Services native omitted - reserved keyword in Java)
├── transport-native-unix-common-tests
├── transport-rxtx (Transport Services 串口编程 作废)
├── transport-sctp (Transport Services )
└── transport-udt (Transport Services 作废)
  • 将项目导入idea中,笔者采用mac系统。这里需要注意需要安装部分软件。
1
2
3
4
5
6
brew install autoconf automake libtool
# 如果安装了国内的镜像出现Error opening archive: Failed to open
# export HOMEBREW_BOTTLE_DOMAIN=''
# 参考文档 https://zhuanlan.zhihu.com/p/383707713
# 如果是mac系统需要手动将pom文件tcnative.classifier修改成对应系统的。
mvn install -Dmaven.test.skip=true

0x01 根据官方文档快速入门

强烈推荐认真阅读netty的官方文档。

Core

  • netty-common模块是 Netty 的核心基础包,其他模块都需要依赖它。常用的包括通用工具类和自定义并发包。
  • netty-buffer 模块中Netty自己实现了的一个更加完备的ByteBuf 工具类,用于网络通信中的数据载体。
  • netty-resover模块主要提供了一些有关基础设施的解析工具,包括 IP Address、Hostname、DNS 等。

Protocol Support

  • netty-codec模块主要负责编解码工作,提供主流协议的编辑码,还提供了抽象编解码类 ByteToMessageDecoder 和 MessageToByteEncoder,通过继承这两个类我们可以轻松实现自定义的编解码逻辑。

Transport Service

  • netty-transport 模块可以说是 Netty 提供数据处理和传输的核心模块,如 Bootstrap、Channel、ChannelHandler、EventLoop、EventLoopGroup、ChannelPipeline 等。其中 Bootstrap 负责客户端或服务端的启动工作,包括创建、初始化 Channel 等;EventLoop 负责向注册的 Channel 发起 I/O 读写操作;ChannelPipeline 负责 ChannelHandler 的有序编排,这些组件在介绍 Netty 逻辑架构的时候都有所涉及。

SQL 常见用法

1. 查找数据的查询

SELECT: 用于从数据库中选择数据

  • SELECT * FROM table_name;

DISTINCT: 用于过滤掉重复的值并返回指定列的行

  • SELECT DISTINCT column_name;

WHERE: 用于过滤记录/行

  • SELECT column1, column2 FROM table_name WHERE condition;
  • SELECT * FROM table_name WHERE condition1 AND condition2;
  • SELECT * FROM table_name WHERE condition1 OR condition2;
  • SELECT * FROM table_name WHERE NOT condition;
  • SELECT * FROM table_name WHERE condition1 AND (condition2 OR condition3);
  • SELECT * FROM table_name WHERE EXISTS (SELECT column_name FROM table_name WHERE condition);

ORDER BY: 用于结果集的排序,升序(ASC)或者降序(DESC)

  • SELECT * FROM table_name ORDER BY column;
  • SELECT * FROM table_name ORDER BY column DESC;
  • SELECT * FROM table_name ORDER BY column1 ASC, column2 DESC;

SELECT TOP: 用于指定从表顶部返回的记录数

  • SELECT TOP number columns_names FROM table_name WHERE condition;
  • SELECT TOP percent columns_names FROM table_name WHERE condition;
  • 并非所有数据库系统都支持SELECT TOP。 MySQL 中是LIMIT子句
  • SELECT column_names FROM table_name LIMIT offset, count;

LIKE: 用于搜索列中的特定模式,WHERE 子句中使用的运算符

  • % (percent sign) 是一个表示零个,一个或多个字符的通配符
  • _ (underscore) 是一个表示单个字符通配符
  • SELECT column_names FROM table_name WHERE column_name LIKE pattern;
  • LIKE ‘a%’ (查找任何以“a”开头的值)
  • LIKE ‘%a’ (查找任何以“a”结尾的值)
  • LIKE ‘%or%’ (查找任何包含“or”的值)
  • LIKE ‘_r%’ (查找任何第二位是“r”的值)
  • LIKE ‘a_%_%’ (查找任何以“a”开头且长度至少为3的值)
  • LIKE ‘[a-c]%’(查找任何以“a”或“b”或“c”开头的值)

IN: 用于在 WHERE 子句中指定多个值的运算符

  • 本质上,IN运算符是多个OR条件的简写
  • SELECT column_names FROM table_name WHERE column_name IN (value1, value2, …);
  • SELECT column_names FROM table_name WHERE column_name IN (SELECT STATEMENT);

BETWEEN: 用于过滤给定范围的值的运算符

  • SELECT column_names FROM table_name WHERE column_name BETWEEN value1 AND value2;
  • SELECT * FROM Products WHERE (column_name BETWEEN value1 AND value2) AND NOT column_name2 IN (value3, value4);
  • SELECT * FROM Products WHERE column_name BETWEEN #01/07/1999# AND #03/12/1999#;

NULL: 代表一个字段没有值

  • SELECT * FROM table_name WHERE column_name IS NULL;
  • SELECT * FROM table_name WHERE column_name IS NOT NULL;

AS: 用于给表或者列分配别名

  • SELECT column_name AS alias_name FROM table_name;
  • SELECT column_name FROM table_name AS alias_name;
  • SELECT column_name AS alias_name1, column_name2 AS alias_name2;
  • SELECT column_name1, column_name2 + ‘, ‘ + column_name3 AS alias_name;

UNION: 用于组合两个或者多个 SELECT 语句的结果集的运算符

  • 每个 SELECT 语句必须拥有相同的列数
  • 列必须拥有相似的数据类型
  • 每个 SELECT 语句中的列也必须具有相同的顺序
  • SELECT columns_names FROM table1 UNION SELECT column_name FROM table2;
  • UNION 仅允许选择不同的值, UNION ALL 允许重复

ANY|ALL: 用于检查 WHERE 或 HAVING 子句中使用的子查询条件的运算符

  • ANY 如果任何子查询值满足条件,则返回 true。
  • ALL 如果所有子查询值都满足条件,则返回 true。
  • SELECT columns_names FROM table1 WHERE column_name operator (ANY|ALL) (SELECT column_name FROM table_name WHERE condition);

GROUP BY: 通常与聚合函数(COUNT,MAX,MIN,SUM,AVG)一起使用,用于将结果集分组为一列或多列

  • SELECT column_name1, COUNT(column_name2) FROM table_name WHERE condition GROUP BY column_name1 ORDER BY COUNT(column_name2) DESC;

HAVING: HAVING 子句指定 SELECT 语句应仅返回聚合值满足指定条件的行。它被添加到 SQL 语言中,因为WHERE关键字不能与聚合函数一起使用。

  • SELECT COUNT(column_name1), column_name2 FROM table GROUP BY column_name2 HAVING COUNT(column_name1) > 5;
阅读全文 »

最近在编写爬虫程序,这里简单的做下笔记。

阅读注意事项

  1. 需要一台服务器(阿里ESC)这种,分配的公网ip。
  2. 这里使用的yum安装,所以环境配置都创建好了,不需要在手动修改。

准备工作

安装Java、maven、git、selenium运行环境

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
# 使用的机器是centos7.4
# 系统环境一个一个来安装。
# 1.检查是否安装jdk
-> yum install java-1.8.0-openjdk-devel.x86_64
-> java -version
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)
-> yum install maven
-> mvn -version
Java version: 1.8.0_262, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-862.el7.x86_64", arch: "amd64", family: "unix"
-> yum install git
git version 1.8.3.1
# 查看是否生成过证书
-> ls -al ~/.ssh
# 这里配置下ssh公钥方便git拉去代码
-> ssh-keygen -t rsa -C “you email@gamil.com”
# 查看证书
-> cat ~/.ssh/id_rsa.pub
# 开始配置 selenium 运行环境
-> wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm
-> yum localinstall google-chrome-stable_current_x86_64.rpm
# 检查版本
-> google-chrome --version
Google Chrome 85.0.4183.83
# 安装 chromedriver
-> yum install chromedriver
-> chromedriver -version
ChromeDriver 84.0.4147.89
# 这里注意 chromedriver 可能与chrome的版本不一致,去官方网站下载后解压复制到/usr/bin中
# 下载地址 https://chromedriver.chromium.org/
  • 注意 google-chrome 和 chromedriver版本是需要对应的具体可以到官方查看。
  • 在centos上运行需要配置下关键参数
1
2
3
4
5
6
7
ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.addArguments("--headless");
chromeOptions.addArguments("--disable-gpu"); // 不配置一定报错
chromeOptions.addArguments("--no-sandbox");
// 创建无界面浏览器对象
chromeOptions.setHeadless(true);
return new ChromeDriver(chromeOptions);
  • 启动代码的需要指定环境变量
1
2
System.setProperty("webdriver.chrome.chromedriver", "/usr/bin/chromedriver");
# 具体可以通过 whereis chromedriver查看。

参考文献

CentOS使用yum安装jdk

最近在搭建测试环境,很久没接触nginx了。

阅读注意事项

  1. 需要一个域名,并且在国内备案过。
  2. 需要一台服务器(阿里ESC)这种,分配的公网ip。
  3. 申请或者购买一张证书。和域名做关联,域名解析到服务器的公网ip。注意开放服务区的80、443端口。
    1. 证书有两个文件
      1. domian.name.key domain.name.pem
    2. 吧证书上传到目标nginx服务器中。
    3. 检查服务器防火墙
1
2
3
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
sudo firewall-cmd --reload

开始步骤

安装nginx

服务器使用的Centos服务器 使用yum安装nginx。

1
2
3
4
5
6
7
8
9
10
11
12
13
-> yum install -y nginx
#检查nginx安装位置信息
-> whereis nginx
nginx: /usr/sbin/nginx /usr/lib64/nginx /etc/nginx /usr/share/nginx /usr/share/man/man3/nginx.3pm.gz /usr/share/man/man8/nginx.8.gz
# 实际上是安装到/etc/nginx里面了
# 设置开机自动启动nginx
-> sudo systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
# 切换到nginx安装目录
-> cd /etc/nginx
# 启动nginx
-> nginx
# 测试nginx 在浏览器里面请求http://ip 就可以了看到nginx页面就算安装成功

配置证书

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
# 创建证书文件并且将证书复制近文件中
-> cd /etc/nginx
-> mkdir cert
-> mv domian.name.key /etc/nginx/cert/
-> mv domian.name.pem /etc/nginx/cert/
# 配置nginx.conf文件使证书生效,并将80端口转发到443端口上。
-> vim nginx.conf
#以下属性中以ssl开头的属性代表与证书配置有关,其他属性请根据自己的需要进行配置。
server {
listen 443; #配置HTTPS的默认访问端口号为443。此处如果未配置HTTPS的默认访问端口,可能会造成Nginx无法启动。Nginx 1.15.0以上版本请使用listen 443 ssl代替listen 443和ssl on。
server_name www.certificatestests.com; #将www.certificatestests.com修改为您证书绑定的域名,例如:www.example.com。如果您购买的是通配符域名证书,要修改为通配符域名,例如:*.aliyun.com。
root html;
index index.html index.htm;
ssl_certificate cert/domain name.pem; #将domain name.pem替换成您证书的文件名称。
ssl_certificate_key cert/domain name.key; #将domain name.key替换成您证书的密钥文件名称。
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; #使用此加密套件。
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #使用该协议进行配置。
ssl_prefer_server_ciphers on;
location / {
root html; #站点目录。
index index.html index.htm;
}
}

server {
# listen 80 default_server;
# listen [::]:80 default_server;
# server_name _;
listen 80;
listen [::]:80;
server_name www.certificatestests.com;
return 301 https://$host$request_uri;
}
# 保存并推出、检查配置nginx配置文件是否合法、并重启nginx
-> nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
-> nginx -s reload

测试域名证书是否生效

1
2
https://domian
http://domian 检查是否安全链接即可。一般浏览器上面会出现一个安全的标志

参考文献

阿里云帮助文档-在Nginx上配置证书

CentOS 7 上安装最新版 Nginx

JMH

JMH(Java Microbenchmark Harness)是由OpenJDK Developer提供的基准测试工具(基准可以理解为比较的基础,我们将这一次性能测试结果作为基准结果,下一次的测试结果将与基准数据进行比较),它是一种常用的性能测试工具,解决了基准测试中常见的一些问题。

JMH结果分析

结果日志解释

  • 基础信息,显示Java路径、Java版本以及JMH基础配置信息
1
2
3
4
5
6
7
8
9
10
11
# JMH version: 1.21
# VM version: JDK 1.8.0_275, OpenJDK 64-Bit Server VM, 25.275-b01
# VM invoker: /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/bin/java
# VM options: -server
# Warmup: 1 iterations, 10 s each
# Measurement: 1 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 8 threads, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: cn.z201.jmh.ListBenchmark.testArrayList
# Parameters: (size = 100)
  • 预热次数。预热测试不会作为最终的统计结果。预热的目的是让 JVM 对被测代码进行足够多的优化,被测代码应该得到了充分的 JIT 编译和优化。
1
2
3
4
5
# Warmup Iteration   1: 0.002 ±(99.9%) 0.001 ms/op
Iteration 1: 0.002 ±(99.9%) 0.001 ms/op

Result "cn.z201.jmh.ListBenchmark.testArrayList":
0.002 ms/op
  • 结果表明,在拼接字符次数越多的情况下,LinkedList.add() 的性能就更好。这是得益于LinkedList双向链表结构,每次add都是在最后一个位置添加元素。
1
2
3
4
5
6
7
8
9
10
Benchmark                               (size)  Mode  Cnt    Score   Error  Units
ListBenchmark.testArrayList 100 avgt 0.002 ms/op
ListBenchmark.testArrayList 1000 avgt 0.018 ms/op
ListBenchmark.testArrayList 10000 avgt 0.194 ms/op
ListBenchmark.testCopyOnWriteArrayList 100 avgt 0.015 ms/op
ListBenchmark.testCopyOnWriteArrayList 1000 avgt 1.386 ms/op
ListBenchmark.testCopyOnWriteArrayList 10000 avgt 148.161 ms/op
ListBenchmark.testLinkedList 100 avgt 0.002 ms/op
ListBenchmark.testLinkedList 1000 avgt 0.017 ms/op
ListBenchmark.testLinkedList 10000 avgt 0.163 ms/op
阅读全文 »

本章只是回顾一次eureka版本升级后tomcat资源占用过高的问题,临时解决。

升级springBoot、SpringCloud版本

  • 升级完成后直接在测试环境测试部署,结果发现eureka的cpu资源占用过高,导致假死。通过arthas发现是tomcat线程阻塞。通过dependepency看了下springboot中内嵌tomcat的版本是9了。之前是8,测试环境一大堆人等着测试接口。首先想着降低tomcat版本。
1
2
3
查看依赖
gradle dependencies
mvn dependency:tree > output.txt # 输出到文件里

排除SpringBoot的Tomcat,指定Tomcat版本

有时候我们需要在特定情况下使用特定的Tomcat版本,这时候总不能因为Tomcat就改变SpringBoot的版本,所以可以采用排除SpringBoot中的Tomcat包,然后手动指定Tomcat的版本,当然还要引入Tomcat相关的包。

Gradle的配置
1
2
3
4
5
6
7
compile('org.springframework.boot:spring-boot-starter-web') {
exclude module: "spring-boot-starter-tomcat"
}
compile 'org.apache.tomcat.embed:tomcat-embed-core:8.5.37'
compile 'org.apache.tomcat.embed:tomcat-embed-el:8.5.37'
compile 'org.apache.tomcat.embed:tomcat-embed-logging-juli:8.5.2'
compile 'org.apache.tomcat.embed:tomcat-embed-websocket:8.5.37'

如果不指定版本,则会使用最新的Tomcat版本, 否则直接指定对应的版本号。

Maven的配置
  1. 在 pom.xml文件里面添加一个标签,添加期望的版本。
1
<tomcat.version>8.5.37</tomcat.version>
  1. 添加必要的Jar包:
1
2
3
4
5
6
7
8
9
10
<dependency> 
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>

重新部署eureka后一切正常。处理时间短暂,没有影响大家工作。时间过了大半年了,也忘记具体是啥原因了。有机会本地复现试试。