认识SOAP

认识SOAP

Prometheus+Grafana部署实践笔记

Prometheus+Grafana部署实践笔记

参考

https://prometheus.io/docs/instrumenting/writing_exporters/
https://grafana.com/docs/grafana/latest/getting-started/build-first-dashboard/
https://grafana.com/docs/grafana/latest/alerting/alerting-rules/create-grafana-managed-rule/


安装

下载软件包

Prometheushttps://prometheus.io/download/
Grafanahttps://grafana.com/grafana/download

prometheus-2.41.0.windows-amd64.zip
grafana-9.3.2.windows-amd64.zip

Prometheus Exporter:
windows_exporterhttps://github.com/prometheus-community/windows_exporter
blackbox_exporterhttps://github.com/prometheus/blackbox_exporter

WinSW封装

Config File:

配置

Prometheus

prometheus.yml
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# my global config
global:
scrape_interval: 60s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 60s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).

# Alertmanager configuration
# alerting:
# alertmanagers:
# - static_configs:
# - targets:
# - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"

# 一个仅包含一个要抓取的端点的抓取配置:
# 这是普罗米修斯本身。
scrape_configs:
# The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
- job_name: "prometheus"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090"]

# 79服务器节点状态监控数据
- job_name: 'ServerNodeStatus_79'
static_configs:
- targets: ['10.170.10.79:9182']
# 79服务器节点状态监控数据

# 78服务器节点状态监控数据
- job_name: 'ServerNodeStatus_78'
static_configs:
- targets: ['10.170.10.78:9182']

# 82服务器节点状态监控数据
- job_name: 'ServerNodeStatus_82[DB]'
static_configs:
- targets: ['10.170.10.82:9182']

# 10.170.10.78 服务器上的应用Http状态监控
- job_name: "AppStatus_78"
metrics_path: /probe #获取指标的访问路径
params:
module: [http_2xx] #使用GET http 200模块
file_sd_configs:
- refresh_interval: 1m #探测目标配置文件刷新间隔,修改AppStatus*.yml后无需重启blackbox。
files:
- "D:/A_Prometheus/Probe_*_78.yml"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.170.10.79:9115 #blackbox 开放地址

# 10.170.10.79 服务器上的应用Http状态监控
- job_name: "AppStatus_79"
metrics_path: /probe #获取指标的访问路径
params:
module: [http_2xx] #使用GET http 200模块
file_sd_configs:
- refresh_interval: 1m #探测目标配置文件刷新间隔,修改AppStatus*.yml后无需重启blackbox。
files:
- "D:/A_Prometheus/Probe_*_79.yml"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.170.10.79:9115 #blackbox 开放地址

# LIS平台接入的接口http GET状态监控
- job_name: "ServiceStatus_LIS"
metrics_path: /probe #获取指标的访问路径
params:
module: [http_2xx] #使用GET http 200模块
file_sd_configs:
- refresh_interval: 1m #探测目标配置文件刷新间隔,修改AppStatus*.yml后无需重启blackbox。
files:
- "D:/A_Prometheus/Probe_ServiceStatus_LIS.yml"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.170.10.79:9115 #blackbox 开放地址

# LIS平台接入的接口http POST状态监控
- job_name: "ServiceStatus_LIS_POST"
metrics_path: /probe #获取指标的访问路径
params:
module: [http_post_2xx] #使用POST http 200模块
file_sd_configs:
- refresh_interval: 1m #探测目标配置文件刷新间隔,修改AppStatus*.yml后无需重启blackbox。
files:
- "D:/A_Prometheus/Probe_ServiceStatus_LIS_POST.yml"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.170.10.79:9115 #blackbox 开放地址

# 采集信息的接口Http GET状态监控
- job_name: "ServiceStatus_COLL"
metrics_path: /probe #获取指标的访问路径
params:
module: [http_2xx] #使用GET http 200模块
file_sd_configs:
- refresh_interval: 1m #探测目标配置文件刷新间隔,修改AppStatus*.yml后无需重启blackbox。
files:
- "D:/A_Prometheus/Probe_ServiceStatus_COLL.yml"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.170.10.79:9115 #blackbox 开放地址

# 检验报告/采集信息中间库 TCP监控
- job_name: "DBStatus_LIS"
metrics_path: /probe #获取指标的访问路径
params:
module: [tcp_connect] #使用tcp_connect模块
file_sd_configs:
- refresh_interval: 1m #探测目标配置文件刷新间隔,修改AppStatus*.yml后无需重启blackbox。
files:
- "D:/A_Prometheus/Probe_DBStatus_LIS.yml"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 10.170.10.79:9115 #blackbox 开放地址

windows_exporter

config.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
collectors:
enabled: "[defaults],memory,iis,process"
#仅启用服务收集器
collector:
service:
services-where: "Name='nginx' OR Name='Redis'"
iis:
site-whitelist: "Plat|PatLis"
app-whitelist: "Plat|PatLis"
process:
whitelist: "(dbprobe-local|afw|Enjoyor|enjoyor|PushDataWorkService|Redis|nginx).*"
log:
level: warn
telemetry:
addr: ":9182"
path: /metrics
#最大并发请求数。0禁用。
max-requests: 5

blackbox_exporter

blackbox.yml
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
modules:
http_2xx:
prober: http
timeout: 60s
http:
method: GET
preferred_ip_protocol: "ip4"
no_follow_redirects: false
tls_config:
insecure_skip_verify: true
# fail_if_ssl: false
# fail_if_not_ssl: false
# fail_if_body_matches_regexp:
# - "Could not connect to database"
# fail_if_body_not_matches_regexp:
# - "Download the latest version here"
# fail_if_header_matches: # 验证未设置任何 Cookie
# - header: Set-Cookie
# allow_missing: true
# regexp: '.*'
# fail_if_header_not_matches:
# - header: Access-Control-Allow-Origin
# regexp: '(\*|example\.com)'
# ip_protocol_fallback: false # no fallback to "ip6"
http_post_2xx:
prober: http
http:
method: POST
preferred_ip_protocol: "ip4"
no_follow_redirects: false
tls_config:
insecure_skip_verify: true
headers:
Content-Type: application/json
body: '{}'
tcp_connect:
prober: tcp
pop3s_banner:
prober: tcp
tcp:
query_response:
- expect: "^+OK"
tls: true
tls_config:
insecure_skip_verify: false
grpc:
prober: grpc
grpc:
tls: true
preferred_ip_protocol: "ip4"
grpc_plain:
prober: grpc
grpc:
tls: false
service: "service1"
ssh_banner:
prober: tcp
tcp:
query_response:
- expect: "^SSH-2.0-"
- send: "SSH-2.0-blackbox-ssh-check"
irc_banner:
prober: tcp
tcp:
query_response:
- send: "NICK prober"
- send: "USER prober prober prober :prober"
- expect: "PING :([^ ]+)"
send: "PONG ${1}"
- expect: "^:[^ ]+ 001"
icmp:
prober: icmp
icmp_ttl5:
prober: icmp
timeout: 5s
icmp:
preferred_ip_protocol: "ip4"
ttl: 5

Probe Type

web application :

Probe_AppStatus_78.yml
1
2
3
- targets:
#web application
- https://10.170.10.78:8466

database :

Probe_DBStatus_LIS.yml
1
2
3
- targets:
#数据库地址
- 10.110.10.110:1433

webservice:

Probe_ServiceStatus_COLL.yml
1
2
3
- targets:
#webservice
- http://192.168.33.99:8060/WebService/WebServce.asmx

http POST WebAPI :

Probe_ServiceStatus_LIS_POST.yml
1
2
3
- targets:
# http POST WebAPI
- http://192.134.24.120:8902/Interface/GetIndex

Grafana

配置访问协议和端口地址

custom.ini
1
2
3
4
5
6
7
[server]
# Protocol (http, https, h2, socket)
protocol = https

# The http port to use
http_port = 7070

配置Grafana默认主题

custom.ini
1
2
3
4
5
# Default UI theme ("dark" or "light")
default_theme = light

# Default locale (supported IETF language tag, such as en-US)
default_locale = zh-CN

Grafana SSL Config

Grafana Config:

Custom.ini
1
2
3
4
5
6
7
8
#################################### Server ####################################
[server]
# Protocol (http, https, h2, socket)
protocol = https
......
# https certs & key file
cert_file = D:\A_Prometheus\grafana-oss\cert\Grafana.crt
cert_key = D:\A_Prometheus\grafana-oss\cert\Grafana.key

如果是使用自建CA根证书签署Grafana自签名证书的,需要将根证书的CRT内容合并到Grafana的CRT中。

1
cat ROOTCA.crt > Grafana.crt

Grafana 通知模板配置

Grafana 自定义中文Alert模板

Grafana面板

地址:https://github.com/YuanjianZhang/Grafana_Deploy

Node.js常识和误区笔记

Node.js常识和误区笔记

Node.js的底层原理

https://juejin.cn/post/7008504029277847565

https://jameshfisher.com/2020/10/15/how-does-require-work-in-electron/

https://jameshfisher.com/2020/09/27/what-does-the-require-function-do-in-nodejs/

Node.js和JavaScript区别

本质:

Javascript是一种web前端语言,主要用于web开发中,由浏览器解析执行

Node.js是一个可以快速构建网络服务及应用的平台,是用Javascript语言构建的服务平台,可用于后端建立服务器

区别:

Javascript主要应用前端 是编程语言 客户端编程语言(需要浏览器的JavaScript解释器进行解释执行)

Node.js主要应用后端 1个平台 运行环境(一个基于Chrome JavaScript运行时建立的平台,它是对Google V8引擎进行了封装的运行环境)

顶层对象不同,在Ecmascript部分Node.jsJavascript其实是一样的,比如与数据类型的定义、语法结构,内置对象。但在Javascript中的顶层对象是window对象,但是在Node.js中没有什么window对象,Node.js中的顶层对象是global对象。这就是二者的差异性。

在window对象中,定义一个var a全局变量是可以通过Window来访问的(window.a),但是在Node.js中是不能通过global.a来访问的

简单的说node.js就是把浏览器的解释器封装起来作为服务器运行平台,用类似javascript的结构语法进行编程,在node.js上运行。

链接:https://www.jianshu.com/p/21d3130ca059

http://www.inode.club/node/errors.html

记录一次Http协议升级Https的经历

记录一次Http协议升级Https的经历

前言

准备工作

获取TLS证书

申请证书
自签证书【这次只做了自签证书尝试】

申请证书

自签证书

配置TLS证书

IIS配置证书

优点
缺点

IIS配置Https后的问题

Nginx代理Https

优点
无需改动太多,而且方便配置TLS版本,方便兼容TLS1 、TLS1.1等过时版本。

缺点

Nginx代理后的问题

进制转换笔记

进制转换笔记

进制转换算法(Convert)

在数字后面加上不同的字母来表示不同的进位制。B(Binary)表示二进制,O(Octal)表示八进制,D(Decimal)或不加表示十进制,H(Hexadecimal)表示十六进制。例如:(101011)B=(53)O=(43)D=(2B)H

十进制 → 二进制

  
方法:除2取余法,即每次将整数部分除以2,余数为该位权上的数,而商继续除以2,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数读起,一直到最前面的一个余数。

例:将十进制的(43)D转换为二进制的步骤如下:

  1. 将商43除以2,商21余数为1;

  2. 将商21除以2,商10余数为1;

  3. 将商10除以2,商5余数为0;

  4. 将商5除以2,商2余数为1;

  5. 将商2除以2,商1余数为0;

  6. 将商1除以2,商0余数为1;

  7. 读数,因为最后一位是经过多次除以2才得到的,因此它是最高位,读数字从最后的余数向前读,101011,即(43)D=(101011)B。

十进制 → 十六进制

  
方法1:除16取余法,即每次将整数部分除以16,余数为该位权上的数,而商继续除以16,余数又为上一个位权上的数,这个步骤一直持续下去,直到商为0为止,最后读数时候,从最后一个余数起,一直到最前面的一个余数。

例:将十进制的(796)D转换为十六进制的步骤如下:

  1. 将商796除以16,商49余数为12,对应十六进制的C;

  2. 将商49除以16,商3余数为1;

  3. 将商3除以16,商0余数为3;

  4. 读数,因为最后一位是经过多次除以16才得到的,因此它是最高位,读数字从最后的余数向前读,31C,即(796)D=(31C)H。

方法2:使用间接法,先将十进制转换成二进制,然后将二进制又转换成十六进制;

二进制 → 十进制

  
方法:二进制数从低位到高位(即从右往左)计算,第0位的权值是2的0次方,第1位的权值是2的1次方,第2位的权值是2的2次方,依次递增下去,把最后的结果相加的值就是十进制的值了。

例:将二进制的(101011)B转换为十进制的步骤如下:

  1. 第0位 1 x 2^0 = 1;

  2. 第1位 1 x 2^1 = 2;

  3. 第2位 0 x 2^2 = 0;

  4. 第3位 1 x 2^3 = 8;

  5. 第4位 0 x 2^4 = 0;

  6. 第5位 1 x 2^5 = 32;

  7. 读数,把结果值相加,1+2+0+8+0+32=43,即(101011)B=(43)D。

二进制转十六进制

从后向前计算,每4位二进制数转换为一位十六进制数。

方法:取四合一法,即从二进制的小数点为分界点,向左(向右)每四位取成一位,接着将这四位二进制按权相加,然后,按顺序进行排列,小数点的位置不变,得到的数字就是我们所求的十六进制数。如果向左(向右)取四位后,取到最高(最低)位时候,如果无法凑足四位,可以在小数点最左边(最右边),即整数的最高位(最低位)添0,凑足四位。

例:将二进制的(11010111)B转换为十六进制的步骤如下:

  1. 0111 = 7;

  2. 1101 = D;

  3. 读数,读数从高位到低位,即(11010111)B=(D7)H。

十六进制转二进制

方法:取一分四法,即将一位十六进制数分解成四位二进制数,用四位二进制按权相加去凑这位十六进制数,小数点位置照旧。

例:将十六进制的(D7)H转换为二进制的步骤如下:

  1. D = 1101;

  2. 7 = 0111;

  3. 读数,读数从高位到低位,即(D7)H=(11010111)B。

参考

八、十、十六进制转换(图解篇)

字符编码笔记

字符编码笔记

字节、字符、字符编码概念

  • 字节:是计算机存储数据的存储单元,是一个8位的二进制数
    • 计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从0000000011111111
  • 字符:指类字形单位或符号,包括字母、数字、运算符号、标点符号和其他符号,以及一些功能性符号,比如”1”, “汉”, “お”,”℃”等等。
    • 字符是电子计算机或无线电通信中字母、数字、符号的统称,其是数据结构中最小的数据存取单位,通常由8个二进制位(一个字节)来表示一个字符。 字符是计算机中经常用到的二进制编码形式,也是计算机中最常用到的信息形式。
  • 字符编码:是大家对计算机如何使用字节来表示一个字符的约定,可分为ASCII编码,ANSI编码(本地化编码),UNICODE编码(国际化编码)三种。
    • 也称字集码,是把字符集中的字符编码为指定集合中某一对象(例如:比特模式、自然数序列、8位组或者电脉冲),以便文本在计算机中存储和通过通信网络的传递。
  • 编码:是信息从一种形式或格式转换为另一种形式的过程,也称为“计算机编程语言的代码”,简称“编码”。
    • 用预先规定的方法将文字、数字或其它对象编成数码,或将信息、数据转换成规定的电脉冲信号。
    • 编码在电子计算机、电视、遥控和通讯等方面广泛使用。

“字节”与“字符”

它们完全不是一个位面的概念,所以两者之间没有“区别”这个说法。不同编码里,字符和字节的对应关系不同:

①ASCII码中,一个英文字母(不分大小写)占一个字节的空间,一个中文汉字占两个字节的空间。一个二进制数字序列,在计算机中作为一个数字单元,一般为8位二进制数,换算为十进制。最小值0,最大值255。

②UTF-8编码中,一个英文字符等于一个字节,一个中文(含繁体)等于三个字节。

③Unicode编码中,一个英文等于两个字节,一个中文(含繁体)等于两个字节。

符号:英文标点占一个字节,中文标点占两个字节。举例:英文句号“.”占1个字节的大小,中文句号“。”占2个字节的大小。

④UTF-16编码中,一个英文字母字符或一个汉字字符存储都需要2个字节(Unicode扩展区的一些汉字存储需要4个字节)。

⑤UTF-32编码中,世界上任何字符的存储都需要4个字节。

ANSI编码有很多种,但是都只是规定自己国家的语言,这时候出现了UNICODE编码,该编码类似于ANSI,使用多个字节表示一个字符,UNICODE编码把世界上各种主要语言都进行了编码,当然UNICDOE编码也出现了很多种编码方案,比如使用8个二进制位的UTF8以及使用16个二进制位的UTF16等等。

编码
字符编码

ASCII 码:单字节编码。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。

ASCII 码一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为0。

ASCII Code - The extended ASCII table

非 ASCII 编码:多字节编码。

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用 ASCII 码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel(ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表示的符号是一样的,不一样的只是128–255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是 GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。

UNICODE编码:宽字节编码

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母AinU+0041表示英语的大写字母AU+4E25表示汉字。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表。

Unicode 的问题

需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:

  1. 出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。
  2. Unicode 在很长一段时间内无法推广,直到互联网的出现。

UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上基本不用。**重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。**

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
  2. 对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的位。

Unicode 和 UTF-8 之间的转换关系表 (字母x表示可用编码的位。 )

码点的位数 码点起值 码点终值 字节序列 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
7 U+0000 U+007F 1 0xxxxxxx
11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
  • 在ASCII码的范围,用一个位元组表示,超出ASCII码的范围就用位元组表示,这就形成了我们上面看到的UTF-8的表示方法,这样的好处是当UNICODE文件中只有ASCII码时,储存的文件都为一个位元组,所以就是普通的ASCII文件无异,读取的时候也是如此,所以能与以前的ASCII文件相容。
  • 大于ASCII码的,就会由上面的第一位元组的前几位表示该unicode字元的长度,比如110xxxxx前三位的二进位表示告诉我们这是个2BYTE的UNICODE字元;1110xxxx是个三位的UNICODE字元,依此类推;xxx的位置由字符编码数的二进制表示的位填入。越靠右的x具有越少的特殊意义。只用最短的那个足够表达一个字符编码数的多字节串。注意在多字节串中,第一个字节的开头”1”的数目就是整个串中字节的数目。

以汉字为例,演示如何实现 UTF-8 编码。

的 Unicode 是4E25100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx
然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5

笔记

  • Unicode编码系统可分为编码方式和实现方式两个层次
  • Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。
  • 一个字节(byte)由8位二进制数组成
  • 一个十六进制数可以转成4位二进制数
  • Unicode编码方式使用两个字节(byte)进行编码和字符的关联,即4位十六进制数,即16位二进制数,
  • UTF-8 是Unicode编码系统的实现方式之一

拓展知识

字符编码方案的演变

摘录:
总结字符编码方案的演变,我们大致上可简单地划分为三个阶段:
  ① ASCII 编码方案阶段 → ② ANSI 编码方案阶段 → ③ Unicode / UCS 编码方案阶段。

ASCII 编码:在第一个阶段的 ASCII 编码方案阶段,ASCII 编码方案主要适用于美国(与美国同文的英国大致上也适用)。

ASCII 编码(本地化编码):后来计算机发展到欧洲各国以及世界各地,开始发展到了作为第二阶段的 ANSI 编码方案阶段,各个国家和地区先后各自制定了既兼容 ASCII 但又互不兼容的 ANSI 编码方案。

UNICODE编码(国际化编码):ANSI 编码方案阶段的各自为政,为世界各个国家和地区基于计算机的信息交流带来了极大的不便,痛定思痛之余,终于通过 Unicode / UCS 编码方案的制定发展到了第三阶段,最终 Unicode 编码方案胜出。

参考:

字符编码(三:Unicode 编码系统与字节序)

Unicode编码系统可分为编码方式和实现方式两个层次

编码方式

统一码的编码方式与ISO 10646的通用字符集概念相对应。目前实际应用的统一码版本对应于UCS-2,使用16位的编码空间。也就是每个字符占用2个字节。这样理论上一共最多可以表示2^16(即65536)个字符。基本满足各种语言的使用。实际上目前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。

上述16位统一码字符构成基本多文种平面。最新(但未实际广泛使用)的统一码版本定义了16个辅助平面,两者合起来至少需要占据21位的编码空间,比3字节略少。但事实上辅助平面字符仍然占用4字节编码空间,与UCS-4保持一致。未来版本会扩充到ISO 10646-1实现级别3,即涵盖UCS-4的所有字符。UCS-4是更大而尚未填充完全的31位字符集,加上恒为0的首位,共需占据32位,即4字节。理论上最多能表示231个字符,完全可以涵盖一切语言所用的符号。

基本多文种平面的字符的编码为U+hhhh,其中每个h代表一个十六进制数字,与UCS-2编码完全相同。而其对应的4字节UCS-4编码后两个字节一致,前两个字节则所有位均为0。

实现方式

Unicode的实现方式不同于编码方式。一个字符的Unicode编码确定。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(Unicode Transformation Format,简称为UTF)。

Little endian 和 Big endian

上一节已经提到,UCS-2 格式可以存储 Unicode 码(码点不超过0xFFFF)。以汉字为例,Unicode 码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25
存储的时候:

4E在前,25在后,这就是 Big endian 方式;

25在前,4E在后,这是 Little endian 方式;

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

第一个字节在前,就是”大头方式”(Big endian),第二个字节在前就是”小头方式”(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做”零宽度非换行空格”(zero width no-break space),用FEFF表示。这正好是两个字节,而且FFFE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

参考资料

字符编码笔记:ASCII,Unicode 和 UTF-8
字节码:ASCII编码:单字节编码,ANSI编码:多字节编码,UNICODE编码:宽字节编码

设计用户认证模块的最佳实践

设计用户认证模块的最佳实践

前言

转载自:Best Practices for Designing a User Authentication Module

摘录

设计身份验证模块的最佳实践将用户帐户和用户身份的概念分开。这种分离允许用户将多个身份验证因素链接到单个用户帐户并随意更改这些因素。

笔记

一、用户认证模块的表设计应该尽可能的将用户账户信息和用户登录的信息区分开来,将用户个人属性和用户认证用到的属性进一步原子化。
二、用户应该在系统中存在内部唯一的标识值(与用户登录信息无关),通过内部标识值去进行登录验证操作的关联,确保数据的一致性。
三、用户权限设计时,尽可能的将授权信息和用户信息表解耦,使用内部标识符进行关联,数据的准确性通过系统代码去控制。
四、应该尽量将各个模块根据实际需求、业务抽象成具体的表,将其按照功能模块建立模型关系或通过程序代码控制;不应该将大量数据属性聚合在一张表中,过于耦合的数据库结构,会降低系统的健壮性,不利于未来的拓展开发。

Demo数据库Sql

服务端性能测试(转载)
sqlserver事务日志增长过快应对策略

sqlserver事务日志增长过快应对策略

SQL Server事务日志处理方法

1. 将数据库恢复模式设置为简单模式

2. 定时收缩数据库日志文件

收缩数据库日志文件大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--需要注意的是在收缩日志文件时,数据库不能有正在活动的备份事务。

--将plat_lis数据库中的日志文件收缩到 1 MB。
USE testDB;
GO
-- 通过将数据库恢复模型更改为 SIMPLE 来截断日志。
ALTER DATABASE testDB
SET RECOVERY SIMPLE;
GO
-- Shrink the truncated log file to 1 MB.
DBCC SHRINKFILE (testDB_log, 1);
GO
-- 重置数据库恢复模式。
ALTER DATABASE testDB
SET RECOVERY FULL;
GO

3. 定时完全(full)备份数据库、截断事务日志

事务日志的截断与收缩

截断事务日志
事务日志会自动截断的操作:
1. 备份事务日志
2. 设置简单模式再设置回来
3. 使用backup log with no_log或 backup log with truncate_only
4. 从未对数据库进行过完全(full)备份
概要总结:所谓的截断(truncated)只是将可恢复状态的VLF转换到可重用状态

参考

事务日志的截断与收缩
完整数据库备份 (SQL Server)
SqlServer日志增长过快应对策略

引用截图:
文章截图
事务日志的截断与收缩

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×