Hike News
Hike News

istio官方示例bookinfo

istio版本:1.4.5

部署bookinfo

部署资源

1
kubectl apply -f <(istioctl kube-inject -f samples/bookinfo/platform/kube/bookinfo.yaml)

确认资源创建

1
2
3
4
5
6
7
$ kubectl get services
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details 10.0.0.31 <none> 9080/TCP 6m
kubernetes 10.0.0.1 <none> 443/TCP 7d
productpage 10.0.0.120 <none> 9080/TCP 6m
ratings 10.0.0.15 <none> 9080/TCP 6m
reviews 10.0.0.170 <none> 9080/TCP 6m

镜像加载很慢

1
2
3
4
5
6
7
8
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-1520924117-48z17 2/2 Running 0 6m
productpage-v1-560495357-jk1lz 2/2 Running 0 6m
ratings-v1-734492171-rnr5l 2/2 Running 0 6m
reviews-v1-874083890-f0qf0 2/2 Running 0 6m
reviews-v2-1343845940-b34q5 2/2 Running 0 6m
reviews-v3-1813607990-8ch52 2/2 Running 0 6m

访问productpage

1
2
$ kubectl exec -it $(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

部署bookinfo-gateway

部署资源

1
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

确认资源创建

1
2
3
$ kubectl get gateway
NAME AGE
bookinfo-gateway 32s

获取IP端口

1
2
3
4
5
6
7
#IP
$ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
#PORT
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
# IP:PORT
$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

访问productpage

服务器上访问

1
2
$ curl -s http://${GATEWAY_URL}/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>

浏览器上访问

获取地址

1
2
$ echo $GATEWAY_UR
10.22.19.14:24804

打开页面

1
http://10.22.19.14:24804/productpage

刷新页面,发现评价有时星星是红色的,有时是黑色的,有时没有星星。说明有三个版本在负载均衡。

只访问V1版本

创建destination rule

1
2
3
4
5
6
7
$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
$ kubectl get destinationrules.networking.istio.io
NAME HOST AGE
details details 162m
productpage productpage 162m
ratings ratings 162m
reviews reviews 162m

创建V1版本的virtual service

1
$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

此时刷新页面,显示的内容中不包含带星的评价信息。

指定用户访问V2版本

配置V2版本的reviews virtual service

1
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml

登录jason/jason后,显示的内容变成了黑色星星的评价信息

基于权重的流量比例

配置V1V2权重

1
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-80-20.yaml

80%流量到V1版本,20%流量到V2版本

注入延迟故障

配置ratings virtual service

1
$ kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml

普通用户访问正常,jason用户加载评论失败

注入500故障

配置ratings virtual service

1
$ kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-abort.yaml

普通用户访问正常,jason用户提示Ratings service is currently unavailable

卸载

1
$ samples/bookinfo/platform/kube/cleanup.sh

参考

https://istio.io/docs/examples/bookinfo/

在K8S集群中安装istio

istio版本:1.4.5

k8s版本:1.14.8

docker版本:18.6.1

内核版本:4.19.12-1.el7.elrepo.x86_64

安装

下载安装包

方式一:在线下载

1
curl -L https://istio.io/downloadIstio | sh -

方式二:离线下载

https://github.com/istio/istio/releases

下载安装包后上传到服务器并解压

进入安装包并设置环境变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ cd istio-1.4.5
# istioctl在/bin目录下
# K8S安装yaml文件在/install/kubernetes目录下
# 示例程序在/samples下
$ ll
total 28
drwxr-x--- 2 root root 21 Feb 14 01:23 bin
drwxr-xr-x 6 root root 74 Feb 14 01:23 install
-rw-r--r-- 1 root root 11348 Feb 14 01:23 LICENSE
-rw-r----- 1 root root 657 Feb 14 01:23 manifest.yaml
-rw-r--r-- 1 root root 6080 Feb 14 01:23 README.md
drwxr-xr-x 19 root root 4096 Feb 14 01:23 samples
drwxr-x--- 3 root root 132 Feb 14 01:23 tools

$ export PATH=$PWD/bin:$PATH

安装istio

安装demo示例(不适用生产环境)

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
$ istioctl manifest apply --set profile=demo
- Applying manifest for component Base...
✔ Finished applying manifest for component Base.
- Applying manifest for component Tracing...
- Applying manifest for component Policy...
- Applying manifest for component Galley...
- Applying manifest for component Citadel...
- Applying manifest for component EgressGateway...
- Applying manifest for component Pilot...
- Applying manifest for component Telemetry...
- Applying manifest for component Injector...
- Applying manifest for component IngressGateway...
- Applying manifest for component Prometheus...
- Applying manifest for component Kiali...
- Applying manifest for component Grafana...
✔ Finished applying manifest for component Injector.
✔ Finished applying manifest for component Galley.
✔ Finished applying manifest for component Citadel.
✔ Finished applying manifest for component Prometheus.
✔ Finished applying manifest for component IngressGateway.
✔ Finished applying manifest for component Kiali.
✔ Finished applying manifest for component Pilot.
✔ Finished applying manifest for component Policy.
✔ Finished applying manifest for component Tracing.
✔ Finished applying manifest for component EgressGateway.
✔ Finished applying manifest for component Grafana.
✔ Finished applying manifest for component Telemetry.


✔ Installation complete

查看安装情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 172.21.92.238 <none> 3000/TCP 117s
istio-citadel ClusterIP 172.21.219.100 <none> 8060/TCP,15014/TCP 119s
istio-egressgateway ClusterIP 172.21.132.59 <none> 80/TCP,443/TCP,15443/TCP 117s
istio-galley ClusterIP 172.21.181.69 <none> 443/TCP,15014/TCP,9901/TCP,15019/TCP 119s
istio-ingressgateway LoadBalancer 172.21.147.170 <pending> 15020:34070/TCP,80:24804/TCP,443:38932/TCP,15029:23713/TCP,15030:30635/TCP,15031:34451/TCP,15032:30379/TCP,15443:39703/TCP 118s
istio-pilot ClusterIP 172.21.121.250 <none> 15010/TCP,15011/TCP,8080/TCP,15014/TCP 118s
istio-policy ClusterIP 172.21.178.10 <none> 9091/TCP,15004/TCP,15014/TCP 117s
istio-sidecar-injector ClusterIP 172.21.223.149 <none> 443/TCP 119s
istio-telemetry ClusterIP 172.21.49.247 <none> 9091/TCP,15004/TCP,15014/TCP,42422/TCP 116s
jaeger-agent ClusterIP None <none> 5775/UDP,6831/UDP,6832/UDP 2m
jaeger-collector ClusterIP 172.21.159.105 <none> 14267/TCP,14268/TCP,14250/TCP 119s
jaeger-query ClusterIP 172.21.203.16 <none> 16686/TCP 118s
kiali ClusterIP 172.21.207.47 <none> 20001/TCP 118s
prometheus ClusterIP 172.21.71.218 <none> 9090/TCP 118s
tracing ClusterIP 172.21.49.79 <none> 80/TCP 118s
zipkin ClusterIP 172.21.13.237 <none> 9411/TCP 117s

镜像下载速度很慢,需要加速

使用指定仓库

1
2
> istioctl manifest apply --set hub=harbor.apeng.tech/istio
>

1
2
3
4
5
6
7
8
9
10
11
12
13
$ kubectl get pods -n istio-system
grafana-5f798469fd-hm5vs 1/1 Running 0 142m
istio-citadel-58bb67f9b8-bkwkm 1/1 Running 0 142m
istio-egressgateway-6fd57475b5-wdqck 1/1 Running 0 142m
istio-galley-7d4b9874c8-jk495 1/1 Running 0 142m
istio-ingressgateway-7d65bf7fdf-jbqst 1/1 Running 0 142m
istio-pilot-65f8557545-kbs75 1/1 Running 0 142m
istio-policy-6c6449c56f-btzpd 1/1 Running 0 142m
istio-sidecar-injector-774969d686-lgnjb 1/1 Running 0 142m
istio-telemetry-585cc965f7-vjwwn 1/1 Running 8 142m
istio-tracing-cd67ddf8-wpdqr 1/1 Running 0 142m
kiali-7964898d8c-4z88n 1/1 Running 0 142m
prometheus-586d4445c7-wv9qv 1/1 Running 0 142m

注入Sidecar

方式一:指定namespace自动注入

1
$ kubectl label namespace <namespace> istio-injection=enabled

方式二:指定pod注入

1
2
3
4
#三种方式
$ istioctl kube-inject -f resource.yaml | kubectl apply -f -
$ kubectl apply -f <(istioctl kube-inject -f <resource.yaml>)
$ kubectl get deployment deploy -o yaml | istioctl kube-inject -f - | kubectl apply -f -

istioctl kube-inject 命令用于在创建部署之前修改yaml 文件,把 Envoy 注入到 Kubernetes 资源。

卸载

1
$ istioctl manifest generate --set profile=demo | kubectl delete -f -

参考

https://istio.io/docs/setup/getting-started/

设置istioctl自动补全

istio版本:1.4.5

安装bash-completion

ubuntu

1
$ apt-get install bash-completion

centos

1
$ yum install bash-completion

配置~/.bash_profile

1
$ echo '[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"' >> ~/.bash_profile

启用istioctl.bash

1
2
3
4
$ cp istio-1.4.5/tools/istioctl.bash ~/istioctl.bash
$ source ~/istioctl.bash
$ echo 'source ~/istioctl.bash' >> .bashrc
$ source .bashrc

验证

1
2
$ istioctl proxy-<TAB>
proxy-config proxy-status

参考

https://istio.io/docs/ops/diagnostic-tools/istioctl/#enabling-auto-completion

将ECS上的应用集成到istio

网格拓展Mesh Expansion

Mesh Expansion是指部署在Kubernetes之中的Istio服务网格提供的一种将虚拟机或物理裸机集成进入到服务网格的方法。

Mesh Expansion对于用户从遗留系统往云上迁移过程中有着非常重要的作用,在微服务体系结构中,无法要求所有的工作负载都在Kubernetes中运行,用户的一些应用程序可能在Kubernetes中运维,而另外一些可能在虚拟机或物理裸机中运行。

通过一套Istio控制面板就可以管理跨Kubernetes与虚拟机或物理裸机的若干服务。这样既能保证原有业务的正常运转,又能实现Kubernetes与虚拟机上的应用服务混合编排的能力。

如图所示,details组件和数据库运行在Kubernetes之外的ECS上。

把一个VM等同于一个Pod,部署业务服务和Sidecar,然后交给istio编排。

参考

https://help.aliyun.com/document_detail/90707.html

https://istio.io/docs/examples/virtual-machines/single-network/

https://istio.io/docs/examples/virtual-machines/multi-network/

MySQL开发规范

表结构设计

1、每张表都必须有三个字段:idgmt_creategmt_modify,代表主键ID,记录创建时间,记录修改时间。

  • id:必须是唯一并且递增的非负数数字类型,数据量小并发写入量不高用数据库自增Id,并发写入高或者数据量大有分表需求用雪花算法等id生成器生成。
1
2
> `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id'
>
  • gmt_create:顺序递增,存储每条记录的创建时间,一般场景用datatime类型,有跨时区的需求用timestamp类型。
1
2
> `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
>
  • gmt_modify:存储每条记录的修改时间,一般场景用datatime类型,有跨时区的需求用timestamp类型。
1
2
> `gmt_modify` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间'
>

2、没有特殊需求都使用innodb存储引擎,并设置id为主键索引PRIMARY KEY

1
2
> PRIMARY KEY (`id`)
>

​ 因为id字段是innodb的聚簇索引,使用id查询记录的速度最快。

3、主键id字段的长度不宜太大,因为二级索引都会存储主键的值,而且值越大,比较大小就越耗时。

一般用无符号自增主键int(10)即可,最大值4,294,567,294‬2,147,283,647‬*2)。需要存储超过该长度的记录可以用bigint(20)。其中int(N)中的N只是显示长度,详见:https://dev.mysql.com/doc/refman/8.0/en/integer-types.html

4、数据量大的表不要物理删除,使用字段is_deleted来做逻辑删除,1 表示删除,0 表示未删除。

innodb在磁盘中是分页存储的,如果在记录中间插入或者删除数据都要移动后面的数据。

重要数据也可以使用逻辑删除。

逻辑删除不适合有唯一约束的表。

5、需要并发修改的数据使用version字段做乐观锁,每次修改都对版本号+1

比如库存、余额等。

6、 长度超过 2000 字符的大字段用blobtext类型,并和主记录分开存储,可以提高查询速度。

mysql已页为单位存储,每个页的大小为16k,如果单条记录内容太大则会影响范围查询。

7、如果存的都是数字就不要用字符类型的字段,存储空间和排序比较时数字都优于字符串。

8、数字类型如果不存负数就用无符号unsigned,可以增加存储大小。

int(10):-2,147,283,647‬~2,147,283,646

int(10) unsigned:0~4,294,567,294

9、 小数类型为 decimal,禁止使用 float 和 double。

float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。

10、没有特殊需求,所有字段都不允许为null

11、指定表字符集为utf8mb4,不要用utf8,mysql中utf8mb4才是正宗的UTF-8编码。

12、保证所有表使用同样的排序规则。

排序规则utf8mb4_unicode_ciutf8mb4_general_ci更精确,推荐都使用utf8mb4_unicode_ci,参考:https://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci

13、禁止使用外键、 一切外键概念在应用层解决 。

索引设计

1、 唯一索引名为uk_字段名;普通索引名则为 idx_字段名

2、根据业务的唯一特性,尽量给表加上唯一索引。

3、 在长度大于50的 varchar字段上建立索引时,必须指定索引长度,不然会对全部内容建立索引,浪费索引存储空间。

4、 建组合索引的时候,区分度最高的在最左边。

5、 索引需要建立在重复率低的字段上,重复率高的字段建立索引没有太大作用;。

SQL语句

1、 禁止使用存储过程和触发器,存储过程和触发器难以调试和扩展,更没有移植性。

2、 超过三个表禁止 join;需要 join 的字段,数据类型必须绝对一致;多表关联查询时,保证被关联的字段有索引。

3、除了countsummaxmin等少数几个函数,将计算工作放在应用层来做,把计算和存储分离。

无状态应用迁移、扩容简单,有状态应用迁移、扩容复杂。

参考

https://github.com/jly8866/archer/blob/master/src/docs/mysql_db_design_guide.md

MySQL服务端配置

[client]
port = 3306
socket = /tmp/mysql.sock
default_character_set = utf8
#default-collation = utf8_general_ci
default-collation = utf8_unicode_ci

[mysqld]
port = 3306
socket = /tmp/mysql.sock
basedir = /app/data/mysql
datadir = /data/mysql
pid-file = /data/mysql/mysql.pid
user = mysql
bind-address = 0.0.0.0
character_set_server = utf8
server-id = 1 #表示是本机的序号为1,一般来讲就是master的意思
skip-name-resolve
# 禁止MySQL对外部连接进行DNS解析,使用这一选项可以消除MySQL进行DNS解析的时间。但需要注意,如果开启该选项,
# 则所有远程主机连接授权都要使用IP地址方式,否则MySQL将无法正常处理连接请求
#skip-networking
back_log = 600
# MySQL能有的连接数量。当主要MySQL线程在一个很短时间内得到非常多的连接请求,这就起作用,
# 然后主线程花些时间(尽管很短)检查连接并且启动一个新线程。back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中。
# 如果期望在一个短时间内有很多连接,你需要增加它。也就是说,如果MySQL的连接数据达到max_connections时,新来的请求将会被存在堆栈中,
# 以等待某一连接释放资源,该堆栈的数量即back_log,如果等待连接的数量超过back_log,将不被授予连接资源。
# 另外,这值(back_log)限于您的操作系统对到来的TCP/IP连接的侦听队列的大小。
# 你的操作系统在这个队列大小上有它自己的限制(可以检查你的OS文档找出这个变量的最大值),试图设定back_log高于你的操作系统的限制将是无效的。
max_connections = 1000
# MySQL的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。可以过’conn%’通配符查看当前状态的连接数量,以定夺该值的大小。
max_connect_errors = 6000
# 对于同一主机,如果有超出该参数值个数的中断错误连接,则该主机将被禁止连接。如需对该主机进行解禁,执行:FLUSH HOST。
open_files_limit = 65535
# MySQL打开的文件描述符限制,默认最小1024;当open_files_limit没有被配置的时候,比较max_connections5和ulimit -n的值,哪个大用哪个,
# 当open_file_limit被配置的时候,比较open_files_limit和max_connections
5的值,哪个大用哪个。
table_open_cache = 12800
# MySQL每打开一个表,都会读入一些数据到table_open_cache缓存中,当MySQL在这个缓存中找不到相应信息时,才会去磁盘上读取。默认值64
# 假定系统有200个并发连接,则需将此参数设置为200*N(N为每个连接所需的文件描述符数目);
# 当把table_open_cache设置为很大时,如果系统处理不了那么多文件描述符,那么就会出现客户端失效,连接不上
max_allowed_packet = 40M
# 接受的数据包大小;增加该变量的值十分安全,这是因为仅当需要时才会分配额外内存。例如,仅当你发出长查询或MySQLd必须返回大的结果行时MySQLd才会分配更多内存。
# 该变量之所以取较小默认值是一种预防措施,以捕获客户端和服务器之间的错误信息包,并确保不会因偶然使用大的信息包而导致内存溢出。
binlog_cache_size = 1M
# 一个事务,在没有提交的时候,产生的日志,记录到Cache中;等到事务提交需要提交的时候,则把日志持久化到磁盘。默认binlog_cache_size大小32K
max_heap_table_size = 8M
# 定义了用户可以创建的内存表(memory table)的大小。这个值用来计算内存表的最大行数值。这个变量支持动态改变
tmp_table_size = 16M
# MySQL的heap(堆积)表缓冲大小。所有联合在一个DML指令内完成,并且大多数联合甚至可以不用临时表即可以完成。
# 大多数临时表是基于内存的(HEAP)表。具有大的记录长度的临时表 (所有列的长度的和)或包含BLOB列的表存储在硬盘上。
# 如果某个内部heap(堆积)表大小超过tmp_table_size,MySQL可以根据需要自动将内存中的heap表改为基于硬盘的MyISAM表。还可以通过设置tmp_table_size选项来增加临时表的大小。也就是说,如果调高该值,MySQL同时将增加heap表的大小,可达到提高联接查询速度的效果
read_buffer_size = 2M
# MySQL读入缓冲区大小。对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。
# 如果对表的顺序扫描请求非常频繁,并且你认为频繁扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能
read_rnd_buffer_size = 8M
# MySQL的随机读缓冲区大小。当按任意顺序读取行时(例如,按照排序顺序),将分配一个随机读缓存区。进行排序查询时,
# MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要排序大量数据,可适当调高该值。但MySQL会为每个客户连接发放该缓冲空间,所以应尽量适当设置该值,以避免内存开销过大
sort_buffer_size = 8M
# MySQL执行排序使用的缓冲大小。如果想要增加ORDER BY的速度,首先看是否可以让MySQL使用索引而不是额外的排序阶段。
# 如果不能,可以尝试增加sort_buffer_size变量的大小
join_buffer_size = 8M
# 联合查询操作所能使用的缓冲区大小,和sort_buffer_size一样,该参数对应的分配内存也是每连接独享
thread_cache_size = 8
# 这个值(默认8)表示可以重新利用保存在缓存中线程的数量,当断开连接时如果缓存中还有空间,那么客户端的线程将被放到缓存中,
# 如果线程重新被请求,那么请求将从缓存中读取,如果缓存中是空的或者是新的请求,那么这个线程将被重新创建,如果有很多新的线程,
# 增加这个值可以改善系统性能.通过比较Connections和Threads_created状态的变量,可以看到这个变量的作用。(–>表示要调整的值)
# 根据物理内存设置规则如下:
# 1G —> 8
# 2G —> 16
# 3G —> 32
# 大于3G —> 64
query_cache_size = 8M
#MySQL的查询缓冲大小(从4.0.1开始,MySQL提供了查询缓冲机制)使用查询缓冲,MySQL将SELECT语句和查询结果存放在缓冲区中,
# 今后对于同样的SELECT语句(区分大小写),将直接从缓冲区中读取结果。根据MySQL用户手册,使用查询缓冲最多可以达到238%的效率。
# 通过检查状态值’Qcache_%’,可以知道query_cache_size设置是否合理:如果Qcache_lowmem_prunes的值非常大,则表明经常出现缓冲不够的情况,
# 如果Qcache_hits的值也非常大,则表明查询缓冲使用非常频繁,此时需要增加缓冲大小;如果Qcache_hits的值不大,则表明你的查询重复率很低,
# 这种情况下使用查询缓冲反而会影响效率,那么可以考虑不用查询缓冲。此外,在SELECT语句中加入SQL_NO_CACHE可以明确表示不使用查询缓冲
query_cache_limit = 2M
#指定单个查询能够使用的缓冲区大小,默认1M
key_buffer_size = 4M
#指定用于索引的缓冲区大小,增加它可得到更好处理的索引(对所有读和多重写),到你能负担得起那样多。如果你使它太大,
# 系统将开始换页并且真的变慢了。对于内存在4GB左右的服务器该参数可设置为384M或512M。通过检查状态值Key_read_requests和Key_reads,
# 可以知道key_buffer_size设置是否合理。比例key_reads/key_read_requests应该尽可能的低,
# 至少是1:100,1:1000更好(上述状态值可以使用SHOW STATUS LIKE ‘key_read%’获得)。注意:该参数值设置的过大反而会是服务器整体效率降低
ft_min_word_len = 4
# 分词词汇最小长度,默认4
transaction_isolation = REPEATABLE-READ
# MySQL支持4种事务隔离级别,他们分别是:
# READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, SERIALIZABLE.
# 如没有指定,MySQL默认采用的是REPEATABLE-READ,ORACLE默认的是READ-COMMITTED
log_bin = mysql-bin
binlog_format = mixed
expire_logs_days = 30 #超过30天的binlog删除
log_error = /data/mysql/mysql-error.log #错误日志路径
slow_query_log = 1
long_query_time = 1 #慢查询时间 超过1秒则为慢查询
slow_query_log_file = /data/mysql/mysql-slow.log
performance_schema = 0
explicit_defaults_for_timestamp
#lower_case_table_names = 1 #不区分大小写
skip-external-locking #MySQL选项以避免外部锁定。该选项默认开启
default-storage-engine = InnoDB #默认存储引擎
innodb_file_per_table = 1
# InnoDB为独立表空间模式,每个数据库的每个表都会生成一个数据空间
# 独立表空间优点:
# 1.每个表都有自已独立的表空间。
# 2.每个表的数据和索引都会存在自已的表空间中。
# 3.可以实现单表在不同的数据库中移动。
# 4.空间可以回收(除drop table操作处,表空不能自已回收)
# 缺点:
# 单表增加过大,如超过100G
# 结论:
# 共享表空间在Insert操作上少有优势。其它都没独立表空间表现好。当启用独立表空间时,请合理调整:innodb_open_files
innodb_open_files = 500
# 限制Innodb能打开的表的数据,如果库里的表特别多的情况,请增加这个。这个值默认是300
innodb_buffer_pool_size = 64M
# InnoDB使用一个缓冲池来保存索引和原始数据, 不像MyISAM.
# 这里你设置越大,你在存取表里面数据时所需要的磁盘I/O越少.
# 在一个独立使用的数据库服务器上,你可以设置这个变量到服务器物理内存大小的80%
# 不要设置过大,否则,由于物理内存的竞争可能导致操作系统的换页颠簸.
# 注意在32位系统上你每个进程可能被限制在 2-3.5G 用户层面内存限制,
# 所以不要设置的太高.
innodb_write_io_threads = 4
innodb_read_io_threads = 4
# innodb使用后台线程处理数据页上的读写 I/O(输入输出)请求,根据你的 CPU 核数来更改,默认是4
# 注:这两个参数不支持动态改变,需要把该参数加入到my.cnf里,修改完后重启MySQL服务,允许值的范围从 1-64
innodb_thread_concurrency = 0
# 默认设置为 0,表示不限制并发数,这里推荐设置为0,更好去发挥CPU多核处理能力,提高并发量
innodb_purge_threads = 1
# InnoDB中的清除操作是一类定期回收无用数据的操作。在之前的几个版本中,清除操作是主线程的一部分,这意味着运行时它可能会堵塞其它的数据库操作。
# 从MySQL5.5.X版本开始,该操作运行于独立的线程中,并支持更多的并发数。用户可通过设置innodb_purge_threads配置参数来选择清除操作是否使用单
# 独线程,默认情况下参数设置为0(不使用单独线程),设置为 1 时表示使用单独的清除线程。建议为1
innodb_flush_log_at_trx_commit = 2
# 0:如果innodb_flush_log_at_trx_commit的值为0,log buffer每秒就会被刷写日志文件到磁盘,提交事务的时候不做任何操作(执行是由mysql的master thread线程来执行的。
# 主线程中每秒会将重做日志缓冲写入磁盘的重做日志文件(REDO LOG)中。不论事务是否已经提交)默认的日志文件是ib_logfile0,ib_logfile1
# 1:当设为默认值1的时候,每次提交事务的时候,都会将log buffer刷写到日志。
# 2:如果设为2,每次提交事务都会写日志,但并不会执行刷的操作。每秒定时会刷到日志文件。要注意的是,并不能保证100%每秒一定都会刷到磁盘,这要取决于进程的调度。
# 每次事务提交的时候将数据写入事务日志,而这里的写入仅是调用了文件系统的写入操作,而文件系统是有 缓存的,所以这个写入并不能保证数据已经写入到物理磁盘
# 默认值1是为了保证完整的ACID。当然,你可以将这个配置项设为1以外的值来换取更高的性能,但是在系统崩溃的时候,你将会丢失1秒的数据。
# 设为0的话,mysqld进程崩溃的时候,就会丢失最后1秒的事务。设为2,只有在操作系统崩溃或者断电的时候才会丢失最后1秒的数据。InnoDB在做恢复的时候会忽略这个值。
# 总结
# 设为1当然是最安全的,但性能页是最差的(相对其他两个参数而言,但不是不能接受)。如果对数据一致性和完整性要求不高,完全可以设为2,如果只最求性能,例如高并发写的日志服务器,设为0来获得更高性能
innodb_log_buffer_size = 2M
# 此参数确定些日志文件所用的内存大小,以M为单位。缓冲区更大能提高性能,但意外的故障将会丢失数据。MySQL开发人员建议设置为1-8M之间
innodb_log_file_size = 32M
# 此参数确定数据日志文件的大小,更大的设置可以提高性能,但也会增加恢复故障数据库所需的时间
innodb_log_files_in_group = 3
# 为提高性能,MySQL可以以循环方式将日志文件写到多个文件。推荐设置为3
innodb_max_dirty_pages_pct = 90
# innodb主线程刷新缓存池中的数据,使脏数据比例小于90%
innodb_lock_wait_timeout = 120
# InnoDB事务在被回滚之前可以等待一个锁定的超时秒数。InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒
bulk_insert_buffer_size = 8M
# 批量插入缓存大小, 这个参数是针对MyISAM存储引擎来说的。适用于在一次性插入100-1000+条记录时, 提高效率。默认值是8M。可以针对数据量的大小,翻倍增加。
myisam_sort_buffer_size = 8M
# MyISAM设置恢复表之时使用的缓冲区的尺寸,当在REPAIR TABLE或用CREATE INDEX创建索引或ALTER TABLE过程中排序 MyISAM索引分配的缓冲区
myisam_max_sort_file_size = 10G
# 如果临时文件会变得超过索引,不要使用快速排序索引方法来创建一个索引。注释:这个参数以字节的形式给出
myisam_repair_threads = 1
# 如果该值大于1,在Repair by sorting过程中并行创建MyISAM表索引(每个索引在自己的线程内)
interactive_timeout = 28800
# 服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在mysql_real_connect()中使用CLIENT_INTERACTIVE选项的客户端。默认值:28800秒(8小时)
wait_timeout = 28800
# 服务器关闭非交互连接之前等待活动的秒数。在线程启动时,根据全局wait_timeout值或全局interactive_timeout值初始化会话wait_timeout值,
# 取决于客户端类型(由mysql_real_connect()的连接选项CLIENT_INTERACTIVE定义)。参数默认值:28800秒(8小时)
# MySQL服务器所支持的最大连接数是有上限的,因为每个连接的建立都会消耗内存,因此我们希望客户端在连接到MySQL Server处理完相应的操作后,
# 应该断开连接并释放占用的内存。如果你的MySQL Server有大量的闲置连接,他们不仅会白白消耗内存,而且如果连接一直在累加而不断开,
# 最终肯定会达到MySQL Server的连接上限数,这会报’too many connections’的错误。对于wait_timeout的值设定,应该根据系统的运行情况来判断。
# 在系统运行一段时间后,可以通过show processlist命令查看当前系统的连接状态,如果发现有大量的sleep状态的连接进程,则说明该参数设置的过大,

default-time_zone = ‘+8:00’ #时间区设置北京时间

character_set_server = utf8
#default-collation = utf8_general_ci
#default-collation = utf8_unicode_ci
collation-server = utf8_unicode_ci

# 可以进行适当的调整小些。要同时设置interactive_timeout和wait_timeout才会生效。
[mysqldump]
quick
max_allowed_packet = 16M #服务器发送和接受的最大包长度
[myisamchk]
key_buffer_size = 8M
sort_buffer_size = 8M
read_buffer = 4M
write_buffer = 4M

Web开发规范

API设计

1、遵循RESTFul规范。

使用请求方法区分动作,使用URI区分资源。

比如用户user

  • 增:POST /users
  • 删:DELETE /users/{id}
  • 改:PUT /users/{id}
  • 查:GET /users/{id}

2、所有接口必须是幂等的。

失败重试或者重复操作时保证系统的健壮性。新增操作视情况而定,尽量幂等。

MQ消费也需要幂等。

3、基于以上两点,构建声明式API,即用户只需要关注做什么,而不需要关注怎么做。

4、前后端分离开发时,前端负责渲染和交互,后端负责数据和逻辑,不能把逻辑放在前端处理。

5、后端开发时禁止使用Map作为请求参数和数据库返回值。

微服务设计

1、为每个微服务定义一个唯一的应用编码(AppId),服务注册调用、资源管理等都要用到。

可以统一由三个字母组成,最多包含17676个微服务。

2、如果有虚拟机混部的场景,保证每个服务的端口是唯一的。

3、每次需求都有对应版本号,需求文档、产品方案、代码、部署的版本号要一致。

版本号一般构成为[大版本.小版本.修复版本]。

  • 如果不兼容之前的功能,或者功能变动较大,需要增加大版本号;
  • 如果兼容之前的功能,但是有新功能增加,加小版本号即可;
  • 如果没有增加新功能而是修复Bug,加修复版本号。

4、抛出异常的提示信息里需要携带当前服务的AppId,否则一整条调用链路排查太耗时耗力。

5、警惕上游调用方,对C端接口做好限流工作,防止被大流量压垮。

6、怀疑下游提供方,做好熔断和降级,防止被慢响应拖垮。

使用Arthas ognl执行表达式

Arthas ognl命令介绍

https://alibaba.github.io/arthas/ognl.html

使用方法

命令格式:

1
ognl 'express'

调用静态函数

1
2
$ ognl '@System@getProperty("java.home")'
@String[/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre]

执行多行表达式,赋值给临时变量,返回一个List

1
2
3
4
5
$ ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
@ArrayList[
@String[/opt/java/8.0.181-zulu/jre],
@String[OpenJDK Runtime Environment],
]

使用Arthas jad命令反编译源代码

Arthas jad命令介绍

https://alibaba.github.io/arthas/jad.html

将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码

使用方法

命令格式:

1
jad class

示例:

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
[arthas@30]$ jad java.lang.String

ClassLoader:

Location:


/*
* Decompiled with CFR.
*/
package java.lang;

import java.io.ObjectStreamField;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class String
implements Serializable,
Comparable<String>,
CharSequence {
private final char[] value;
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();

public String(byte[] bytes, int offset, int length) {
String.checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
}

public String(byte[] bytes, Charset charset) {
this(bytes, 0, bytes.length, charset);
}
...

使用Arthas thread命令查看线程堆栈

Arthas thread命令介绍

https://alibaba.github.io/arthas/thread.html

查看当前Java进程的线程信息和线程的堆栈信息。

使用方法

命令格式:

1
thread [id] [-n 5]

示例:

显示所有线程的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ thread
Threads Total: 16, NEW: 0, RUNNABLE: 7, BLOCKED: 0, WAITING: 5, TIMED_WAITING: 4, TERMINATED: 0
ID NAME GROUP PRIORITY STATE %CPU TIME INTERRUPTE DAEMON
30 as-command-execute-daemon system 9 RUNNABLE 72 0:0 false true
23 as-session-expire-daemon system 9 TIMED_WAIT 27 0:0 false true
22 Attach Listener system 9 RUNNABLE 0 0:0 false true
11 pool-2-thread-1 main 5 TIMED_WAIT 0 0:0 false false
12 Thread-2 main 5 RUNNABLE 0 0:0 false true
13 pool-3-thread-1 main 5 TIMED_WAIT 0 0:0 false false
25 as-selector-daemon system 9 RUNNABLE 0 0:0 false true
14 Thread-3 main 5 TIMED_WAIT 0 0:0 false false
26 pool-5-thread-1 system 5 WAITING 0 0:0 false false
15 Thread-4 main 5 RUNNABLE 0 0:0 false false
1 main main 5 WAITING 0 0:2 false false
2 Reference Handler system 10 WAITING 0 0:0 false true
3 Finalizer system 8 WAITING 0 0:0 false true
4 Signal Dispatcher system 9 RUNNABLE 0 0:0 false true
20 NonBlockingInputStreamThread main 5 WAITING 0 0:0 false true
21 Thread-8 main 5 RUNNABLE 0 0:0 false true

显示指定线程的运行堆栈

1
2
3
4
5
6
7
8
9
$ thread 1
"main" Id=1 WAITING on java.util.concurrent.CountDownLatch$Sync@29fafb28
at sun.misc.Unsafe.park(Native Method)
- waiting on java.util.concurrent.CountDownLatch$Sync@29fafb28
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)

显示当前最忙的前N个线程并打印堆栈

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
thread -n 3
"as-command-execute-daemon" Id=29 cpuUsage=75% RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:440)
at com.taobao.arthas.core.command.monitor200.ThreadCommand$1.action(ThreadCommand.java:58)
at com.taobao.arthas.core.command.handler.AbstractCommandHandler.execute(AbstractCommandHandler.java:238)
at com.taobao.arthas.core.command.handler.DefaultCommandHandler.handleCommand(DefaultCommandHandler.java:67)
at com.taobao.arthas.core.server.ArthasServer$4.run(ArthasServer.java:276)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)

Number of locked synchronizers = 1
- java.util.concurrent.ThreadPoolExecutor$Worker@6cd0b6f8

"as-session-expire-daemon" Id=25 cpuUsage=24% TIMED_WAITING
at java.lang.Thread.sleep(Native Method)
at com.taobao.arthas.core.server.DefaultSessionManager$2.run(DefaultSessionManager.java:85)

"Reference Handler" Id=2 cpuUsage=0% WAITING on java.lang.ref.Reference$Lock@69ba0f27
at java.lang.Object.wait(Native Method)
- waiting on java.lang.ref.Reference$Lock@69ba0f27
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)