主页

Https配置

2022-05-05
nginx

nginx的https配置 #

配置流程 #

  1. 编译nginx需要带上--with-http_ssl_module选项。编译失败可能是缺少依赖,安装对应依赖即可。
./configure --prefix=/opt/nginx --with-http_ssl_module
make
make install
  1. 生成证书,在控制台中依次执行以下命令,执行完成后将生成的文件移动到/opt/nginx/ssl下。

openssl genrsa -des3 -out uam.key

输入密码:********
再次输入密码:********

openssl req -new -key uam.key -out uam.csr

输入密码:********
依次输入如下
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:shaanxi
Locality Name (eg, city) []:xian
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xiaoxiang
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

openssl rsa -in uam.key -out uam.nopass.key

输入密码:********

openssl req -new -x509 -days 3650 -key uam.nopass.key -out uam.crt

依次输入如下
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:shaanxi
Locality Name (eg, city) []:xian
Organization Name (eg, company) [Internet Widgits Pty Ltd]:xiaoxiang
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:
Email Address []:
  1. nginx中http块中添加如下配置:
    server {
        listen       443 ssl;

        #使用https,证书位置
        ssl_certificate /opt/nginx/ssl/uam.crt;
        ssl_certificate_key /opt/nginx/ssl/uam.nopass.key;

        location /{
            proxy_pass http://localhost:80; 
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        #http转发到https
        error_page 497 https://$host:$server_port$request_uri;
        error_page   500 502 503 504  /50x.html;
     }

配置介绍 #

https配置 #

  • nginx配置https,只有listen后面的sslssl_certificatessl_certificate_key这三个参数是必须的。
server {
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}
  • ssl_protocolsssl_ciphers可以限制SSL/TLS的版本和密码,默认情况下nginx会使用ssl_protocols TLSv1 TLSv1.1 TLSv1.2ssl_ciphers HIGH:!aNULL:!MD5,所以一般情况下不需要手动配置。

https优化 #

  • SSL会消耗额外的CPU资源,在多核的CPU上应该使worker_processes配置为不少于CPU核心数的值(可以将该参数设置为auto,这时nginx会自动调整工作进程数为CPU数量)。
  • CPU最密集的行为是SSL握手,有两种方式可以降低握手次数:
    • 使用keepalive_timeout,使用该参数可以是多个请求通过同一个连接,后面的请求可以复用SSL会话。
    • 通过ssl_session_cache可以将会话存储到工作进程之间共享的SSL会话缓存中,1MB的缓存可以包含大约4000个会话,默认缓存超时时间为5分钟,可以使用ssl_session_timeout来设置超时时间。
worker_processes auto;

http {
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 10m;

    server {
        listen              443 ssl;
        server_name         www.example.com;
        keepalive_timeout   70;

        ssl_certificate     www.example.com.crt;
        ssl_certificate_key www.example.com.key;
        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         HIGH:!aNULL:!MD5;
        ...
}

一个server中包含http和https #

  • 可以在一个server块中处理http请求和https请求
server {
    listen              80;
    listen              443 ssl;
    server_name         www.example.com;
    ssl_certificate     www.example.com.crt;
    ssl_certificate_key www.example.com.key;
    ...
}

无法使用基于server_name的多个HTTPS服务 #

  • 当为一个IP配置了多个域名时,使用server_name并不能区分这些域名所对应的server块。案例如下:
server {
    listen          443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}
  • 这个例子中无论输入哪个域名,浏览器都返回默认的证书(即www.example.com的证书)。因为SSL连接是建立在浏览器发送HTTP请求之前,nginx不能知道当前发送请求的是哪个域名,所以它只能返回默认的服务证书。
  • 目前的解决方法是为每个HTTPS的server分配一个IP地址。
server {
    listen          192.168.1.1:443 ssl;
    server_name     www.example.com;
    ssl_certificate www.example.com.crt;
    ...
}

server {
    listen          192.168.1.2:443 ssl;
    server_name     www.example.org;
    ssl_certificate www.example.org.crt;
    ...
}

相关链接 Configuring HTTPS servers (nginx.org)

serve_name

2022-04-05
nginx

server_name可以决定使用哪个server块来处理请求,server_name可以是精确的名称、通配符和正则表达式。

server {
    listen       80;
    server_name  example.org  www.example.org;
    ...
}

server {
    listen       80;
    server_name  *.example.org;
    ...
}

server {
    listen       80;
    server_name  mail.*;
    ...
}

server {
    listen       80;
    server_name  ~^(?<user>.+)\.example\.net$;
    ...
}

当按照域名来访问服务时,如果可以匹配多个server_name,就会按照如下的顺序来进行匹配:

  1. 精确的名称。
  2. 以星号开头的最长通配符,如*.exmaple.org
  3. 以星号结束的最长通配符,如mail.*
  4. 第一个匹配的正则表达式(按照在配置文件出现的先后顺序)。

通配符 #

包含星号的通配符只能出现在name的开始或者结束的地方,且只能在点号.的旁边。www.*.example.orgw*.example.org都是非法的。这种情况下可以使用正则表达式。如~^www\..+\.example\.org$~^w.*\.example\.org$。星号可以匹配name的好几个部分,如*.example.org不仅可以匹配www.example.org也可以匹配www.sub.example.org

.example.org这种特殊格式的通配符不仅可以匹配example.org,还可以匹配通配符*.example.org

正则表达式 #

nginx使用的正则表达式和Perl编程语言(即PCRE)兼容。如果要使用正则表达式,server_name必须以波浪线开始。

server_name ~^www\d+\.example\.net$;`

如果不以波浪线开头,它会被认为是一个精确的名称,如果表达式中包含星号,它会被认为是一个通配符名称。^$在逻辑上是必须要有的。域名中的.需要被转义,因为.也是正则的元字符。当正则表达式中包含{}时,正则需要被括起来。

server_name  "~^(?<name>\w\d{1,3}+)\.example\.net$";

否则nginx在启动时会报错。

命名正则表达式捕获组可以当作一个变量使用:

server {
    server_name   ~^(www\.)?(?<domain>.+)$;

    location / {
        root   /sites/$domain;
    }
}

PCRE支持下面这几种语法

  1. ?<name>?'name'Perl5.10兼容语法,自PCRE-7.0开始支持。
  2. ?P<name> Python兼容依法,自PCRE-4.0开始支持。

当nginx启动失败并显示以下错误时:

pcre_compile() failed: unrecognized character after (?< in ...

这表示PCRE库版本太久,可以使用?P<name>语法代替。捕获组也可以使用数字形式。

server {
    server_name   ~^(www\.)?(.+)$;

    location / {
        root   /sites/$2;
    }
}

然而,这种用法仅限于简单的情况,因为数字引用很容易被覆盖。

InnoDB

2022-03-20
数据库

InnoDB #

  • mysql服务器中负责对表中的数据读取和写入工作的部分是存储引擎,真实数据在不同存储引擎中存放的格式一般是不同的。
  • innodb会将数据划分为若干个页,以页作为磁盘和内存交互的基本单位,页也是innodb管理存储空间的基本单位,页的默认大小为16KB。一般情况下,一次最少从磁盘中读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘中。
  • innodb有4中行格式COMPACT、PEDUNDANT、DYNAMIC、COMPRESSED。
CREATE TABLE 表名(列的信息) ROW_FORMAT=行格式名称;
ALTER TABLE 表名 ROW_FORMAT=行格式名称;

COMPACT行格式 #

COMPACT行格式

  1. 记录的额外信息,包含3个部分:变长字段的长度列表、NULL值列表和记录头信息。
    1. mysql支持一些变长的数据类型,如varchar、text和blob,变长数据类型占用的字节数也是不固定的,所以在存储数据时要把这些数据占用的字节数也存起来。一个变长的数据占用的存储空间分为两部分:真正的数据内容和该数据占用的字节数。各变长字段的真实数据占用的字节数按照列的顺序逆序存放。
    2. 当使用定长编码的字符集时(如ascii),CHAR(10)列所占用的字节数不会被加到变长字段长度列表中,而当采用变长编码的字符集时,CHAR(10)列所占用的字节数就会被加到变长字段的长度列表中。此外,采用变长编码字符集的CHAR(M)至少占用M个字节,而VARCHAR(M)没有这个要求。
  • 记录头信息由固定的5字节组成。

名称 大小(bit) 描述
deleted_flag 1 标识该记录是否被删除。所有被删除的记录会组成一个垃圾链表,之后若有新的记录插入到表中,他们就可能覆盖掉这些记录所占用的存储空间。
min_rec_flag 1 B+树每层非叶子节点中的最小的目录项记录都会添加该标记
n_owned 4 一个页面中的记录会被分为多个组,每个组的最后那条记录会在n_owned中记录该组内由几条记录。其他的记录中该字段为0
heap_no 13 表示当前记录在页面堆中的相对位置
record_type 3 表示当前记录的类型,0表示普通记录,1表示B+树非叶节点的目录项,2表示Infimum记录,3表示Supremum记录
next_record 16 表示下一条记录的相对位置。下一条记录指的是按照主键值从小到大的顺序排列的下一条记录。infimum记录的下一条记录就是本页中主键最小的记录,本页中主键最大的记录的下一条记录就是supremum记录。
  • mysql默认会为每个记录添加一些隐藏列。innodb的主键生成策略:优先使用用户自定义的主键作为主键,如果没有主键,就选取一个不允许存储为NULL的UNIQUE键作为主键,如果没有,innodb会为表默认添加一个名为row_id的隐藏列作为主键。

    列名 占用空间 描述
    row_id(DB_ROW_ID) 6字节 非必须,行ID,唯一标识一条记录
    trx_id(DB_TRX_ID) 6字节 必须,事务ID
    roll_pointer(DB_ROLL_PTR) 7字节 必须,回滚指针。
  • innodb是以页为基本单位来管理存储空间的,一个页的大小通常是16KB,有时候一个页存不了一条记录,所以mysql中会有溢出列的概念。

  • COMPACT和REDUNDANT行格式中,对于存储占用的空间非常多的列,在记录的真实数据处只会存储该列的一部分数据,而把剩余的数据分散存储到其他的几个页中,然后在记录真实数据处用20字节存储指向这些页的地址和这些页的数据占用的字节数。溢出列之间是使用链表连接起来的。

  • DYNAMIC和COMPRESSED类似于COMPACT行格式,但是在处理溢出列有点差异,他们不会在记录真实数据处存储列真实数据的前768字节,而是把所有的列都存到溢出页中。COMPRESSED行格式会采用压缩算法对页面进行压缩。

innodb数据页结构 #

  • 一个数据页可以被划分为7个部分,分别如下:
    • File Header:表示页的一些通用信息,占固定的38字节。
    • Page Header:表示数据页专有的一些信息,占固定的56字节。
    • Infimum和Supremum:两个虚拟的伪记录,分别表示页中最小记录和最大记录,占固定的26字节。
    • User Records:真正存储插入的记录,大小不固定。
    • Free Space:页中尚未使用的部分,大小不固定。
    • Page Directory:页中某些记录的相对位置,是各个槽对应的记录在页面中的地址偏移量;大小不固定,插入的记录越多,这部分占用的空间越多。
    • File Trailer:用于检验页是否完整,占固定的8字节。
  • 一条完整的记录时可以比大小的,比较记录的大小就是比较主键的大小。
  • User Records中的记录之间亲密物件的排列,这种结构称为堆(heap)。把一条记录在堆中的相对位置称为heap_no,靠前的heap_no相对较小,innodb会自动给每个页中加上两条记录,这两条记录一条为最小记录(infimum),一条为页面的最大记录(supremum)。这两条记录的heap_no最小。堆中的heap_no在分配之后就不会发生改变了,即使之后删除了堆中的某条记录。
  • 每个记录的头信息中都有一个next_record属性,可以是页面中的所有记录串联成一个单向链表。
  • Innodb会把页中的记录划分为若干个组,每个组的最后一个记录的地址偏移量作为一个槽,存放在Page Directory中,一个槽占用2字节。
  • 在一个页中根据主键查找记录是非常快的,步骤为:通过二分法确定该记录所在分组对应的槽,并找到改槽所在分组中主键值最小的那条记录;通过记录的next_record遍历改槽所在组中的各个记录。
  • 每个数据页的File Header都有上一页和下一页的编号,所有的数据页会组成一个双向链表。

Javascript

2022-01-31
前端

基本语法 #

  • 变量如果只声明而没有赋值,则该变量的值是undefined

  • js是一种动态类型语言,变量的类型没有限制,变量可以随时更改类型。

  • js引擎的工作方式是先解析代码,获取所有被声明的变量,然后再一行行的运行,这会使得所有变量的声明语句,都会被提升到代码的头部。

  • 变量命名规则如下:第一个字符可以是任意Unicode字母以及$_,第二个字符及后面的字符还可以用数字0-9。

if…else #

if (m === 3) {
  // 满足条件时,执行的语句
} else {
  // 不满足条件时,执行的语句
}

switch #

  • switch语句后面的表达式,与case语句后面的表示式比较运行结果时,采用的是严格相等运算符(===),这意味着比较时不会发生类型转换。
switch (x) {
  case 1:
    console.log('x 等于1');
    break;
  case 2:
    console.log('x 等于2');
    break;
  default:
    console.log('x 等于其他值');
}

三元运算符 #

(条件) ? 表达式1 : 表达式2

循环语句 #

while #

var i = 0;

while (i < 100) {
  console.log('i 当前为:' + i);
  i = i + 1;
}

for #

var x = 3;
for (var i = 0; i < x; i++) {
  console.log(i);
}

do…while #

var x = 3;
var i = 0;

do {
  console.log(i);
  i++;
} while(i < x);

break和continue #

for (var i = 0; i < 5; i++) {
  console.log(i);
  if (i === 3)
    break;
}

var i = 0;

while (i < 100){
  i++;
  if (i % 2 === 0) {
      continue;
  }
  console.log('i 当前为:' + i);
}

数据类型 #

六种数据类型 #

  • 数值(number):整数和小数(比如13.14)。
  • 字符串(string):文本(比如Hello World)。
  • 布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假)。
  • undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值。
  • null:表示空值,即此处的值为空。
  • 对象(object):各种值组成的集合。

typeof运算符 #

typeof运算符可以返回一个值的数据类型。

数值、字符串、布尔值分别返回numberstringboolean

typeof 123 // "number"
typeof '123' // "string"
typeof false // "boolean"

函数返回function

function f() {}
typeof f

undefined返回undefined

typeof undefined
// "undefined"

typeof可以用来检查一个没有声明的变量,而不报错。

typeof v
// "undefined"

对象返回object

typeof window // "object"

null返回object

typeof null

空数组([])的类型也是object,在 JavaScript 内部,数组本质上只是一种特殊的对象。

null、undefined和布尔值 #

  • null是一个表示“空”的对象,转为数值时为0;undefined是一个表示"此处无定义"的原始值,转为数值时为NaN。

  • undefined表示“未定义”。

布尔值 #

下面的值都会被转为false

  • undefined
  • null
  • false
  • 0
  • NaN
  • ""''(空字符串)

空数组([])和空对象({})对应的布尔值,都是true

数值 #

整数和浮点数 #

JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,11.0是相同的,是同一个数。

数值的表示方法 #

JavaScript 的数值有多种表示方法,默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制。

  • 十进制:没有前导0的数值。
  • 八进制:有前缀0o0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
  • 十六进制:有前缀0x0X的数值。
  • 二进制:有前缀0b0B的数值。
0xff // 255
0o377 // 255
0b11 // 3

数值也可以采用科学计数法表示,下面是几个科学计数法的例子。

123e3 // 123000
123e-3 // 0.123
-3.1E+12
.1e-23

NaN #

NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合。

5 - 'x' // NaN

NaN不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number,使用typeof运算符可以看得很清楚。

NaN不等于任何值,包括它本身。

NaN === NaN // false

Infinity #

Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到Infinity。

Infinity有正负之分,Infinity表示正的无穷,-Infinity表示负的无穷。

Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。

Infinity的四则运算,符合无穷的数学计算规则。

5 * Infinity // Infinity
5 - Infinity // -Infinity
Infinity / 5 // Infinity
5 / Infinity // 0

相关函数 #

parseInt #

parseInt方法用于将字符串转为整数。

parseInt('123') // 123

如果字符串头部有空格,空格会被自动去除。

parseInt('   81') // 81

如果parseInt的参数不是字符串,则会先转为字符串再转换。

parseInt(1.23) // 1
// 等同于
parseInt('1.23') // 1

字符串转为整数的时候,是一个个字符依次转换,如果遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分。

parseInt('8a') // 8
parseInt('12**') // 12
parseInt('12.34') // 12
parseInt('15e2') // 15
parseInt('15px') // 15

如果字符串的第一个字符不能转化为数字(后面跟着数字的正负号除外),返回NaN

parseInt('abc') // NaN
parseInt('+1') // 1

对于那些会自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,因此导致一些奇怪的结果。

parseInt(1000000000000000000000.5) // 1
// 等同于
parseInt('1e+21') // 1

parseFloat #

parseFloat方法用于将一个字符串转为浮点数。

parseFloat('3.14') // 3.14

如果字符串符合科学计数法,则会进行相应的转换。

parseFloat('314e-2') // 3.14
parseFloat('0.0314E+2') // 3.14

如果字符串包含不能转为浮点数的字符,则不再进行往后转换,返回已经转好的部分。

parseFloat('3.14more non-digit characters') // 3.14

parseFloat方法会自动过滤字符串前导的空格。

parseFloat('\t\v\r12.34\n ') // 12.34

如果参数不是字符串,或者字符串的第一个字符不能转化为浮点数,则返回NaN

parseFloat([]) // NaN
parseFloat('') // NaN

isNaN #

isNaN方法可以用来判断一个值是否为NaN

isNaN(NaN) // true
isNaN(123) // false

但是,isNaN只对数值有效,如果传入其他值,会被先转成数值。比如,传入字符串的时候,字符串会被先转成NaN,所以最后返回trueisNaNtrue的值,有可能不是NaN,而是一个字符串。

判断NaN更可靠的方法是,利用NaN为唯一不等于自身的值的这个特点,进行判断。

function myIsNaN(value) {
  return value !== value;
}

isFinite #

isFinite方法返回一个布尔值,表示某个值是否为正常的数值。

isFinite(Infinity) // false
isFinite(-Infinity) // false
isFinite(NaN) // false
isFinite(undefined) // false
isFinite(null) // true
isFinite(-1) // true

字符串 #

字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。

字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)。但无法改变字符串之中的单个字符。

var s = 'hello';
s[0] // "h"

length #

length属性返回字符串的长度。

var s = 'hello';
s.length // 5

对象 #

对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。

var obj = {
  foo: 'Hello',
  bar: 'World'
};

对象的所有键都是字符串,所以加不加引号都可以。

var obj = {
  'foo': 'Hello',
  'bar': 'World'
};

对象的每一个键又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。

var obj = {
  p: function (x) {
    return 2 * x;
  }
};

obj.p(1) // 2

属性可以动态创建,不必在对象声明时就指定。

var obj = {};
obj.foo = 123;
obj.foo // 123

对象引用 #

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。

对象属性 #

读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。

var obj = {
  p: 'Hello World'
};

obj.p // "Hello World"
//如果使用方括号运算符,键名必须放在引号里面
obj['p'] // "Hello World"

点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。

var obj = {};

obj.foo = 'Hello';
obj['bar'] = 'World';

属性的查看 #

查看一个对象本身的所有属性,可以使用Object.keys方法。

var obj = {
  key1: 1,
  key2: 2
};

Object.keys(obj);

属性的删除 #

delete命令用于删除对象的属性,删除成功后返回true

删除一个不存在的属性,delete不报错,而且返回true

var obj = { p: 1 };
Object.keys(obj) // ["p"]

delete obj.p // true

属性是否存在:in 运算符 #

in运算符用于检查对象是否包含某个属性。

var obj = { p: 1 };
'p' in obj // true
'toString' in obj // true

属性的遍历:for…in 循环 #

for...in循环用来遍历一个对象的全部属性。

var obj = {a: 1, b: 2, c: 3};

for (var i in obj) {
  console.log('键名:', i);
  console.log('键值:', obj[i]);
}

for...in循环有两个使用注意点。

  • 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。
  • 它不仅遍历对象自身的属性,还遍历继承的属性。

函数 #

function #

function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面。

function print(s) {
  console.log(s);
}

函数表达式 #

除了用function命令声明函数,还可以采用变量赋值的写法。

var print = function(s) {
  console.log(s);
};

name属性 #

函数的name属性返回函数的名字。

function f1() {}
f1.name // "f1"

数组 #

var arr = ['a', 'b', 'c'];

//除了在定义时赋值,数组也可以先定义后赋值。
//任何类型的数据,都可以放入数组。
var arr = [];
arr[0] = 'a';
arr[1] = [1, 2, 3];
arr[2] = {a: 1};

数组属于一种特殊的对象。typeof运算符会返回数组的类型是object

Object.keys方法返回数组的所有键名。可以看到数组的键名就是整数0、1、2。

JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。

length 属性 #

数组的length属性,返回数组的成员数量。

['a', 'b', 'c'].length // 3

for…in 循环 #

var a = [1, 2, 3];

for (var i in a) {
  console.log(a[i]);
}

Elasticsearch起步

2022-01-15
java

  • es是面向文档型数据库,一条数据在这里就是一条文档。

索引 #

  • 创建索引PUT http://ip:9200/索引名称
  • 获取索引的相关信息GET http://ip:9200/索引名称
  • 获取所有的索引GET http://ip:9200/_cat/indices?v
  • 删除索引DELETE http://ip:9200/索引名称

文档 #

添加文档 #

POST /索引名称/_doc
{
    "title": "xiaoxiang",
    "url": "xiaoxiang.space"
}

PUT /索引名称/_doc/id
{
    "title": "xiaoxiang",
    "url": "xiaoxiang.space"
}

PUT /<target>/_doc/<_id> 
POST /<target>/_doc/ 
PUT /<target>/_create/<_id> 
POST /<target>/_create/<_id>

查询数据 #

//查询一条数据
GET /索引名称/_doc/id

//全部查询
GET /索引名称/_search?pretty

修改数据 #

POST /索引名称/_update/12
{
    "doc": {
        "title": "xiaoxiangmax"
    }
}

#可以使用PUT进行数据修改,但需要罗列所有的字段
PUT my_goods/_doc/10 
{ 
	"goodsName": "三星 UA55RU7520JXXZ 52 英寸 4K 超高清",
	"skuCode": "skuCode10",
	...
}

删除数据 #

DELETE /索引名称/_doc/id

#查询删除
POST /my_goods/_delete_by_query 
{ 
	"query": { 
		"match": { 
			"shopCode": "sc00002" 
		} 
	} 
}

文档复杂查询 #

添加查询条件 #

//增加条件查询
GET /索引名称/_search
{
    "query": {
        "match": {
            "category": "xiaoxiang"
        }
    }
}

//不拆解搜索字段
GET /gw_audit-*/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "user_name": "zhao fei"
          }
        }
      ]
    }
  }
}

添加高亮显示 #

//对某个条件添加高亮显示
GET /gw_audit-*/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match_phrase": {
            "user_name": "kpf"
          }
        }
      ]
    }
  },
  "highlight": {
    "fields": {
      "user_name": {}
    }
  }
}

多条件查询 #

//多条件查询,(相当于and)
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "category": "xiaoxiang"
          }
        },
        {
          "match": {
            "price": "5999"
          }
        }
      ]
    }
  }
}

//多条件查询,一个字段多个查询的值(相当于or)
GET /gw_audit-*/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "match": {
            "user_name": "kpf"
          }
        },
        {
          "match": {
            "user_name": "zj"
          }
        }
      ]
    }
  },
  "size": 20000
}

区间查询 #

#区间查询
GET /gw_audit-*/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "range": {
            "spent": {
              "gte": 10,
              "lte": 200
            }
          }
        }
      ]
    }
  }
}

分页查询 #

//全量分页查询
GET /gw_audit-*/_search
{
	"query": {
		"match_all": {
		
		}
	},
	"from": 0,
	"size": 10
}

只查询指定字段 #

//只查询指定字段
GET /索引名称/_search
{
	"query": {
		"match_all": {
		
		}
	},
	"from": 0,
	"size": 10,
	"_source": ["title"]
}

对结果排序 #

//对结果排序
GET /索引名称/_search
{
	"query": {
		"match_all": {
		
		}
	},
	"from": 0,
	"size": 10,
	"sort": {
		"price": {
			"order": "desc"
		}
	}
}

聚合操作,求每组的数量 #

#对查询结果进行聚合操作,统计每一组的数量
GET /gw_audit-*/_search
{
  "aggs": {
    "user_name_group": {
      "terms": {
        "field": "user_name"
      }
    }
  },
  "size": 0
}

聚合操作,统计平均值 #

#对查询结果进行聚合操作,统计平均值
GET /gw_audit-*/_search
{
  "aggs": {
    "user_name_avg": {
      "avg": {
        "field": "spent"
      }
    }
  },
  "size": 0
}

设置映射关系 #

//设置映射关系
PUT test/_mapping
{
  "properties": {
    "name": {
      "type": "text", 
      "index": true
    },
    "sex": {
      "type": "keyword", //关键字不会被分开
      "index": "true"
    },
    "tel": {
      "type": "keyword",
      "index": false
    }
  }
}

_reindex #

PUT cpu-2022
{
  "mappings": {
    "dynamic": "false",
    "properties": {
      "cpu": {
        "type": "keyword"
      },
      "host_name": {
        "type": "keyword"
      }
    }
  }
}

POST _reindex
{
  "source": {
    "index": "cpu-2022.07.*"
  },
  "dest": {
    "index": "cpu-2022"
  }
}

DELETE cpu-2022.07.*


GET cpu-2022/_search
{
  "size": 0,
  "track_total_hits": true
}

正则

2022-01-12
java

  • 完整的正则表达式由两种字符构成,特殊字符(元字符)和文字(普通字符)。

egrep命令 #

元字符 案例
^匹配行的开始,$匹配行的结束。 ^cat$ 匹配以c作为一行的第一个字符,紧接着一个a,紧接着以t结尾。
[abc] (字符组)匹配多个字符之一 [-a-cA-D1.?_] 匹配-abcABCD1.?_中的一个。-(连字符)表示一个范围,只有在字符组内他才可能是一个元字符,如果连字符出现在字符组开头,那么它表示的就是一个普通符号。在字符组中,`?.*
[^ABC]排除型字符组 q[^u] 匹配q后面的字符不为u的情况,注意:这要求q后面必须要有一个字符。
[^-中的连字符也不是一个元字符。
.匹配任意字符 注意:在字符组中的.是普通字符。
` ` 表示或
egrep的-i参数表示忽略大小写。
\<\>单词的起始位置和结束位置。 \<cat 匹配以cat开头的单词,cat\> 匹配以cat结尾的单词。
? 表示可选 July?表示y是可选的,该正则可以匹配July和Jul。
July? 4(th)?中的th是可选的,可以匹配July 4July 4th
+ 表示紧邻的元素出现一次或多次
*表示紧邻的元素出现0次或多次
.+ 表示匹配任意字符至少一次。
.* 表示匹配任意字符0次到无数次。
{min,max} 区间量词 允许重现的次数在[min,max]之间。
反向引用 ([a-z]{3})([0-9]).+\1\2 括号()可以记住子表达式的文本,元字符\1\2可以引用这些文本。从而这个正则可以匹配the9 the9
\ 转义:将元字符转义为普通字符 \. 表示一个普通的.
() 限制多选结构、分组、捕获文本 限制多选结构指的是和`
(?:…) 仅用于分组,但是不捕获

Perl #

使用正则匹配文本 #

  • Perl用$variable =~ m/regex/来判断一个正则表达式能否匹配某个字符串,m表示匹配match,可以省略,斜线用来标注正则表达式的边界。
  • 元字符是具有特殊意义的字符,各个语言中对元字符的定义并不是统一的。
  • Perl和其他流派的正则表达式提供了许多有用的简记法。
\b 作为单词起始和单词结束的元字符
\t 制表符
\n 换行符
\r 回车符
\s 任何空白字符,如空格符、制表符等
\S 除了\s外的任何字符
\w [a-zA-Z0-9_]
\W 除了\w外的任何符号
\d [0-9]
\D 除了\d外的任何符号
  • /i修饰符表示此测试不区分大小写。
  • (?:...)表示可以用来分组文本,但是不捕获。
  • 匹配成功后,Perl可以使用$1 $2 $3 之类的变量来保存相对应的(...)括号内的子表达式匹配的文本。
  • 子表达式的编号按照小括号出现的先后排序,从1开始,子表达式可以嵌套。
# perl温度转换
print "enter a temperature(e.g., 32F, 100C):\n";
$input = <STDIN>;	#接收用户输入
chomp($input);	#去掉输入末尾的换行
if ($input =~ m/^([-+]?[0-9]+(\.[0-9]*)?)\s*([CF])$/i)
{
	$InputNum = $1;
	$type = $3;
	if ($type =~ m/c/i) {
		#输入的是摄氏温度,计算华氏温度
		$celsius = $InputNum;
		$fahrenheit = ($celsius * 9 / 5) + 32;
	} else {
		#输入的是华氏温度,计算摄氏温度
		$fahrenheit = $InputNum;
		$celsius = ($fahrenheit - 32) * 5 / 9;
	}
	printf "%.2f C is %.2f F\n", $celsius, $fahrenheit;
} else {
	print "expecting a number followed by \"C\" or \"F\",\n";
	print "so I don't understand \"$input\" .\n";
}

使用正则修改文本 #

  • $var =~ s/regex/replacement/ 当正则表达式能够匹配$var中的某段文本,则将这段文本替换为replacement。此替换只发生一次。
  • /g用于在s/.../.../第一次替换完成后继续搜索更多的匹配文本,进行更多的替换。

环视功能 #

  • 环视是在文本的特定位置上匹配左边或者右边的文本,但是不会占用字符,类似\b ^ $,但是更加通用。
介绍
(?=...)肯定顺序环视 在当前位置向右查看文本,尝试匹配子表达式,如果能匹配,就返回匹配成功信息。
(?!...)否定顺序环视 在当前位置向右查看文本,尝试匹配子表达式,如果不能够匹配,就返回成功信息。
(?<=...)肯定逆序环视 在当前位置向左查看文本,尝试匹配子表达式,如果匹配成功,就返回匹配成功信息。
(?<!...)否定逆序环视 在当前位置向左查看文本,尝试匹配子表达式,如果不能匹配,就返回成功信息。

匹配原理 #

优先选择最左边的匹配结果 #

  • 起始位置最靠左的匹配结果总是优于其他可能的匹配结果。
  • 匹配会从需要查找的字符串的起始位置开始尝试匹配,在起始位置测试正则表达式不能匹配后,就从第二个字符开始测试匹配,直到找到能匹配成功的情况或到了字符串的最后一个字符。
正则:fat|cat|belly|your
文本:the dragging belly indicates that your cat is too fat
结果:belly

标准量词?、*、+、{min,max}是优先匹配的。 #

  • 例:^.*([0-9][0-9])匹配abot24characterslong的过程。
    • .*匹配整个字符串以后,第一个[0-9]的匹配要求.*吐出来一个字符g,但这并不能让[0-9]匹配,所以.*必须继续吐字符,接下来的字符是n,如此循环15次,直到.*吐出来了4
    • 即使第一个[0-9]能匹配4,但是第二个[0-9]仍然不能匹配,为了匹配正则表达式,[.*]必须再次释放一个字符,这次是2,第一个由[0-9]匹配,4能够由[0-9]匹配,所以刺配成功,\1的值是24

传统NFA的多选结构是匹配优先的 #

  • 传统NFA遇到多选结构是,会按照从左到右的顺序检查表达式中的多选分支。如^(subject|date):*,当遇到此选择分支时,首先尝试匹配subject,如果可以匹配,就匹配接下来的:*。如果无法匹配,就尝试其他多选分支(尝试匹配date)。即多选结构既不是匹配优先,也不是忽略优先,而是按照多选结构的顺序。
  • tour|to|tournament来匹配three tournaments时会得到什么呢?

回溯 #

  • NFA最重要的性质是,它会依次处理各个子表达式或组成元素,需要在两个可能成功的可能中进行选择的时候,它会选择其一,同时记住另一个,以备稍后可能的需要。
  • 面对多个选择时,选择哪个分支呢?如果在进行尝试和跳过尝试之间选择,对于匹配优先量词,引擎会优先选择进行尝试,而对于忽略优先量词,会选择跳过尝试。
  • 当发生回溯时,距离当前最近存储的选项就是当本地失败强制回溯返回的,使用的原则是LIFO(后进先出)。
  • 回溯不但需要重新计算正则表达式和文本的对应位置,也需要维护括号内的子表达式所匹配的文本的状态。

固化分组 #

  • 固化分组可能会放弃某些可能的路径,使用(?>...)
  • 使用固化分组与正常的匹配毫无差别,但是当匹配到固化分组结构之后,在固化分组中的所有备用状态都会被放弃。在固化分组匹配结束时,他已匹配的文本已经固化为一个单元,只能作为整体而保留或放弃。
  • (?>.*?)永远无法匹配任何字符。

占有优先量词?= *+ ++ {m,n}+ #

  • 占有优先量词和匹配优先量词很相似,但是占有优先量词从不归还已匹配的字符。
  • 占有优先量词和固化分组非常相似,如w++(?>w+)的匹配结果完全相同。

Log4j2

2022-01-07
java

log4j2文件加载顺序 #

  1. 检查是否配置了log4j2.configurationFile系统属性,如果设置了,就会尝试使用匹配文件后缀的ConfigurationFactory去加载配置。该配置不限制为本地文件,也可以包含URL。
  2. 在classpath路径下找log4j2-test.properties。
  3. 在classpath路径下找log4j2-test.ymal 或log4j2-test.yml文件。
  4. 在classpath路径下找log4j2-test.json或Log4j2.jsn文件。
  5. 在classpath路径下找log4j2-test.xml。
  6. 在classpath路径下找log4j2.properties文件。
  7. 在classpath路径下找log4j2.ymal或log4j2.yml文件。
  8. 在classpath路径下找log4j2.json或log4j2.jsn文件。
  9. 在classpath路径下找log4j2.xml文件。
  10. 如果没有找到配置文件,则会使用默认配置,将日志输出到控制台。

Syslog

2022-01-07
java

rfc5424 #

介绍 #

格式:PRI VERSION TIMESTAMP HOSTNAME APP-NAME PROCID MSGID STRUCTURED-DATA MSG

  • 消息头
    • PRI 优先级
    • VERSION 版本
    • TIMESTAMP 时间
    • HOSTNAME 主机名
    • APP-NAME APP名称
    • PROCID 进程的ID
    • MSGID 消息ID
  • STRUCTURED-DATA
  • 消息体

PRI #

  • PRI(priority)代表两个值(Facility)和日志级别(serverity)。PRI必须是类似<14>的格式。中间的值的计算公式为priority = facility x 8 + serverity
  • Facility的值是[0,23]。各个值的含义如下:
数字 介绍
0 内核消息
1 用户级别消息
2 邮件系统
3 系统守护进程
4 安全/认证消息
5 syslogd内部生成的消息
6 line printer subsystem
7 network news subsystem
8 UUCP subsystem
9 时钟守护程序
10 安全/认证消息
11 FTP守护程序
12 NTF子系统
13 log audit
14 log alert
15 clock daemon (note 2)
16 本地用户0(LOCAL0)
17 本地用户1(LOCAL1)
18 本地用户2(LOCAL2)
19 本地用户3(LOCAL3)
20 本地用户4(LOCAL4)
21 本地用户5(LOCAL5)
22 本地用户6(LOCAL6)
23 本地用户7(LOCAL7)

Serverity #

数字 介绍
0 emergency紧急,系统无法使用
1 alert警告,必须立即采取措施
2 critical
3 error
4 warning
5 notice;正常但是重要的情况
6 informational;普通信息
7 debug;

例子 #

<165>1 2003-08-24T05:14:15.000003-07:00 192.0.2.1 myproc 8710 - - %% It's time to make the do-nuts
<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"] BOMAn
<165>1 2003-10-11T22:14:15.003Z mymachine.example.com evntslog - ID47 [exampleSDID@32473 iut="3" eventSource="Application" eventID="1011"][examplePriority@32473 class="high"]

log4j2配置 #

<Syslog name="RFC5424" format="RFC5424" host="10.2.4.31" port="5140" protocol="UDP" 
appName="auditSyslogDemo" facility="LOCAL0" newLine="true" messageId="Audit" id="App"/>

参考链接: RFC 5424: The Syslog Protocol (rfc-editor.org)

参考链接: Log4j – Log4j 2 Appenders (apache.org)