Senlin's Blog


  • 分类

  • 归档

  • 标签

  • 关于

Envoy Proxy 与微服务实践

发表于 2017-12-25   |   分类于 微服务   |   阅读次数

微服务介绍

  在传统模式下,如果微服务之间要进行通信,那么程序需要自己处理各种通信的细节,这就包括服务发现、熔断机制、超时重试和 tracing 等功能。这些功能通常实现为与某种编程语言相关的 library,这也导致了这样的 library 无法在不同的编程语言之间共享。


  更进一步,如果我们可以将这部分功能抽取出来,形成一个独立的进程,这样的进程称为 Sidecar。通常来说,我们会将应用程序和 Sidecar 部署在一起,那么程序的入口流量和出口流量都会由这个 Sidecar 去代理,这样就可以通过 Sidecar 去实现服务发现、熔断机制、超时重试等功能了。

Envoy Proxy 介绍

  Envoy Proxy 可以用来充当 Sidecar 进程。通常来说,我们会将应用程序和 Envoy 部署在一起,形成一个微服务。另一方面,为了实现高可用,通常一个微服务会部署多份副本,这些副本加在一起,就形成了 Service Cluster。下图显示的就是服务与服务之间的通信:


  除了可以充当 Sidecar 进程之外,Envoy Proxy 还可以充当反向代理,将流量转发给后端的 Service Cluster。充当反向代理的 Envoy,通常也可以称为 Edge Envoy。

构建程序镜像

  在部署应用程序之前,需要先构建 Docker 镜像,下面是一个简单的 Flask 程序app.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import socket
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World!'
@app.route('/healthy_check')
def healthy_check():
service = socket.gethostname()
ip = socket.gethostbyname(service)
return 'I am fine! <service_name: {}, ip: {}>'.format(service, ip)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)

  具体的 Dockerfile 以及构建镜像需要用到的命令,可以见这里。

阅读全文 »

MySQL 分区表

发表于 2017-12-18   |   分类于 数据库   |   阅读次数

水平分区

  在 MySQL 中,如果一张表的数据量太大(例如包含百万行数据),为了让表变得方便管理,可以将表拆分成多个分区。MySQL 只支持水平分区,不支持垂直分区。如果使用水平分区,那么 MySQL 会根据用户定义的规则,将表中不同的行拆分到不同的分区。

分区的好处

  通常来说,如果打算让一张表存储大量的数据,那么才值得对它进行分区,分区会带来一些好处:

  • 分区表的数据可以分布在文件系统的不同位置,甚至是多个磁盘,这使得分区表可以容纳更多数据。
  • 可以通过删除没有用的分区来删除数据,这种情况下可以很快地删除数据。
  • 可以加快查询的执行速度,因为对于某些查询来说,只需要查询某个分区即可。

分区的限制

  在 MySQL 中,创建分区表时候有一个限制条件:分区表中的每个唯一索引(包括主键),都必须包含分区表达式中的所有列。让我们举个例子:

1
2
3
4
5
6
7
8
9
10
CREATE TABLE userslogs (
id INT NOT NULL AUTO_INCREMENT,
username VARCHAR(20) NOT NULL,
logdata BLOB NOT NULL,
created DATETIME NOT NULL,
PRIMARY KEY(id),
UNIQUE KEY (username, created)
)
PARTITION BY HASH(TO_DAYS(created))
PARTITIONS 10;

  执行这个 SQL 语句将会报错:

1
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function

  这个错误说的是,主键id并没有包含分区列created,所以导致建表失败。下面的建表语句则可以执行成功:

1
2
3
4
5
6
7
8
CREATE TABLE userslogs (
username VARCHAR(20) NOT NULL,
logdata BLOB NOT NULL,
created DATETIME NOT NULL,
PRIMARY KEY(username, created)
)
PARTITION BY HASH( TO_DAYS(created) )
PARTITIONS 10;

  这个表的主键(username, created)包含了分区列created,所以建表可以成功。

阅读全文 »

MySQL 性能剖析

发表于 2017-12-16   |   分类于 数据库   |   阅读次数

分析慢查询日志

  在分析慢查询日志之前,需要先让 MySQL 开启慢查询日志。首先,创建目录用于存放慢查询日志:

1
2
3
$ mkdir -p /home/ubuntu/log/mysql
$ chmod 755 /home/ubuntu/log/mysql/
$ sudo chown mysql:mysql /home/ubuntu/log/mysql/

  下面是和慢查询相关的配置:

1
2
3
4
5
6
7
8
9
10
11
$ cat /etc/mysql/conf.d/mysql.cnf
[mysqld]
slow_query_log = ON
slow_query_log_file = /home/ubuntu/log/mysql/mysql-slow.log
# 若查询的耗时超过 2 秒,并且至少需要分析 100 行记录,才会被判定为慢查询
long_query_time = 2
min_examined_row_limit = 100
# 若查询没有使用到索引,也会被判定为慢查询
log-queries-not-using-indexes

  在开启慢查询日志之后,可以借助pt-query-digest工具分析慢查询日志,生成剖析报告:

1
$ pt-query-digest mysql-slow.log

  生成的报告会对慢查询进行排序,比较严重的慢查询会排在前面:

1
2
3
4
5
# Profile
# Rank Query ID Response time Calls R/Call V/M Item
# ==== ================== ============= ===== ====== ===== ==============
# 1 0x9F602236FBB89FCB 0.0169 98.7% 1 0.0169 0.00 SELECT payment
# 2 0x5665CD6BAE86EAEC 0.0002 1.3% 1 0.0002 0.00 SELECT actor

  如何解读这份报告呢?

  • Response:查询的响应时间。
  • time:查询占总时间的百分比。
  • Calls:查询的执行次数。
  • R/Call:单次查询的平均响应时间。
  • V/M:方差与平均值的比值。如果这个值较大,表示查询对应的执行时间变化较大。
阅读全文 »

Kubernetes 的服务发现与负载均衡

发表于 2017-12-10   |   分类于 虚拟化   |   阅读次数

Service 的作用

  在 如何在 Kubernetes 部署应用 中,我们讲到了如何部署应用程序,但还有几个问题没有解决:

  • 服务发现:由于 Kubernetes 的调度机制,在 Kubernetes 中,Pod 的 IP 不是固定的。如果其它程序需要访问这个 Pod,要怎么知道这个 Pod 的 IP 呢?
  • 负载均衡:由于 Deployment 管理着多个 Pod 的副本,如果其它程序需要访问这些 Pod,显然需要一个 proxy 为这些 Pod 做负载均衡。
  • 外部路由:如果应用程序运行在 Kubernetes 外部,如何访问 Kubernetes 内部的 Pod 呢?

  Kubernetes 提供了 Service 功能,用来解决这些问题。

服务发现与负载均衡

  Service 通常会和 Deployment 结合在一起使用,首先通过 Deployment 部署应用程序,然后再使用 Service 为应用程序提供服务发现、负载均衡和外部路由的功能。
  首先,让我们创建一个 Deployment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat nginx-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-server # 这个 Deployment 管理着那些拥有这个标签的 Pod
template:
metadata:
labels:
app: nginx-server # 为所有 Pod 都打上这个标签
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
$ kubectl apply -f nginx-deployment.yaml

  接着,为这个 Deployment 创建一个 Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat nginx-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
name: nginx-service
spec:
ports:
- port: 5000
targetPort: 80
selector:
app: nginx-server
$ kubectl apply -f nginx-service.yaml

  这里我们创建了一个名为nginx-service的 Service,它监听的端口是 5000,同时它会把全部的流量都转发给它代理的所有 Pod(这些 Pod 都必须拥有app: nginx-server这个标签)。
  Service 提供了两种服务发现的方式,第一种是环境变量,第二种是 DNS。先说第一种,上面我们创建了nginx-service这个 Service,接着如果我们再创建另外一个 Pod,那么在这个 Pod 中,可以通过环境变量知道nginx-service的地址。

阅读全文 »

如何在 Kubernetes 部署应用

发表于 2017-12-08   |   分类于 虚拟化   |   阅读次数

部署的难题

  对开发人员来说,在部署程序的新版本之前,需要考虑很多事情:

  • 如何在多台机器实现自动部署?
  • 在部署的过程,如何保证服务的高可用?
  • 如何知道新版本是否出现问题,健康检查要怎么做?
  • 如果新版本出现问题,能够做到回滚?

  很幸运,Kubernetes 提供了 Deployment 功能,帮助开发人员解决这些问题。

如何部署应用

  下面的配置文件定义了一个 Deployment,其中包含两个 Nginx Pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cat nginx-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-server # 这个 Deployment 管理着那些拥有这个标签的 Pod
template:
metadata:
labels:
app: nginx-server # 为所有 Pod 都打上这个标签
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

  接着,创建这个 Deployment:

1
2
3
4
$ kubectl apply -f nginx-deployment.yaml
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 2 2 2 2 5s

  可以观察到,这个 Deployment 管理着两个 Nginx Pod:

1
2
3
4
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-2569060349-2ph84 1/1 Running 0 2m
nginx-deployment-2569060349-4wdsd 1/1 Running 0 2m

比较 Deployment 与 ReplicaSet

  在 Kubernetes 入门指南 我们说到了 ReplicaSet,ReplicaSet 也是用来管理多个 Pod 的副本,那么 Deployment 和 ReplicaSet 的区别在哪里呢?
  当我们创建了 Deployment 之后,实际上也创建了 ReplicaSet,所以说 Deployment 管理着 ReplicaSet(实际上 Deployment 比 ReplicaSet 有着更多功能)。
  这里可以验证一下:

1
2
3
$ kubectl get rs --selector=app=nginx-server
NAME DESIRED CURRENT READY AGE
nginx-deployment-2569060349 2 2 2 26m

  由于 ReplicaSet 可以伸缩 Pod 的数量,因此 Deployment 也可以做到:

1
2
$ kubectl scale deployments nginx-deployment --replicas=3
deployment "nginx-deployment" scaled

  Deployment 管理着 ReplicaSet,因此当 Deployment 伸缩时,由它管理的 ReplicaSet 也会发生伸缩:

1
2
3
$ kubectl get rs --selector=app=nginx-server
NAME DESIRED CURRENT READY AGE
nginx-deployment-2569060349 3 3 3 30m

  但反过来,如果我们直接伸缩 ReplicaSet,那么 Deployment 也会相应发生伸缩吗?答案是不会的。

1
2
3
4
5
$ kubectl scale rs nginx-deployment-2569060349 --replicas=1
replicaset "nginx-deployment-2569060349" scaled
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 38m

滚动更新

  更新版本时,如何保证服务的高可用?可以借助 Deployment 的滚动更新功能,例如下面的例子中,我们将 Nginx 从1.7.9升级到1.9.0版本:

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
$ cat nginx-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
annotations:
kubernetes.io/change-cause: "Update nginx from 1.7.9 to 1.9.0" # 注释
spec:
replicas: 2
selector:
matchLabels:
app: nginx-server
strategy: # 更新策略
rollingUpdate:
maxSurge: 0
maxUnavailable: 1 # 更新过程中,最多有一个 Pod 不可用
type: RollingUpdate # 策略类型: 滚动更新
template:
metadata:
labels:
app: nginx-server
spec:
containers:
- name: nginx
image: nginx:1.9.0
ports:
- containerPort: 80

  上述的配置文件中,我们指定更新策略为RollingUpdate(即滚动更新)。在这种策略下,更新版本的过程是渐进性的,分多次进行,每次都只更新少数几个 Pod,直到所有 Pod 都更新完毕。
  有两个参数可用用来配置滚动更新策略:

  • maxUnavailable表示在更新过程中,最多有多少个 Pod 不可用(这个数值也可以是百分比,例如 20% 表示最多有 20% 的 Pod 不可用)。譬如说,如果设置maxUnavailable为 1,那么更新过程会分多次进行,每次都是先销毁 1 个旧的 Pod,然后创建 1 个新的 Pod 替换它。
  • 在更新的过程,如果需要保证服务的 100% 可用,可以使用maxSurge,同时将maxUnavailable设置为 0。譬如说,将maxSurge设置为 1,同时将maxUnavailable设置为 0,那么更新过程会分多次进行,每次都是先创建 1 个新的 Pod,如果新的 Pod 可用了,这时才会替换掉旧的 Pod。
阅读全文 »
1234…13

高性能

61 日志
13 分类
14 标签
GitHub 知乎
© 2015 - 2022
由 Hexo 强力驱动
主题 - NexT.Mist
  |   总访问量: