Fork me on GitHub

做自己尊重的人

       从物理学来说,无机的原子逆热力学第二定律出现生物是奇迹;从生物学来说,按进化规律产生遗传信息指导组装人类是奇迹。

       超越化学反应结果的每个个体都是值得珍惜的奇迹;超越动物欲望总和的每个个体都应做自己尊重的人。

       过去、现在、将来,能够完全知道个人行为和思想的只有自己;世界上很多文化借助宗教信仰来指导人们生活的信念和世俗行为;而对于无神论者—也就是大多数中国人—来说,自我尊重是重要的正道。

       在我加入社会后看到各种离奇现象,知道自己更多弱点和缺陷,可能还遇到小难大灾后,如何在诱惑和艰难中保持人性的尊严、赢得自己的尊重并非易事,却很值得。

       这不是:自恋、自大、自负、自夸、自欺、自闭、自怜,而是:自信、自豪、自量、自知、自省、自赎、自勉、自强。

       自尊支撑自由之精神、自主之工作、自在之生活。

       我希望:退休之日,我觉得职业中的自己值得尊重;迟暮之年,我感到生活中的自己值得尊重。

       在我所含全部原子再度按热力学第二定律回归自然之前,它们既经历过物性的神奇,也产生过人性的可爱。

理解JavaScript中的对象与new命令

1、对象是什么

     面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。

     每一个对象都是功能中心,具有明确分工,可以完成接受信息、处理数据、发出信息等任务。对象可以复用,通过继承机制还可以定制。因此,面向对象编程具有灵活、代码可复用、高度模块化等特点,容易维护和开发,比起由一系列函数或指令组成的传统的过程式编程(procedural programming),更适合多人合作的大型软件项目。

     那么,“对象”(object)到底是什么?我们从两个层次来理解。

  • 对象是单个实物的抽象。

     一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个远程服务器连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。

  • 对象是一个容器,封装了属性(property)和方法(method)。

     属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是哪一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息等等)。

2、构造函数

     面向对象编程的第一步,就是要生成对象。前面说过,对象是单个实物的抽象。通常需要一个模板,表示某一类实物的共同特征,然后对象根据这个模板生成。

     典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。所谓“类”就是对象的模板,对象就是“类”的实例。但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

     JavaScript 语言使用构造函数(constructor)作为对象的模板。所谓”构造函数”,就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。一个构造函数,可以生成多个实例对象,这些实例对象都有相同的结构。

     构造函数就是一个普通的函数,但具有自己的特征和用法。

1
2
3
var Vehicle = function () {
this.price = 1000;
};

     上面代码中,Vehicle就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。

     构造函数的特点有两个。

  • 函数体内部使用了this关键字,代表了所要生成的对象实例。

  • 生成对象的时候,必须使用new命令。

     下面先介绍new命令。

3、New命令

3.1、基本用法

     new命令的作用,就是执行构造函数,返回一个实例对象。

1
2
3
4
5
6
var Vehicle = function () {
this.price = 1000;
};

var vobj = new Vehicle();
vobj.price // 1000

     上面代码通过new命令,让构造函数Vehicle生成一个实例对象,保存在变量v中。这个新生成的实例对象,从构造函数Vehicle得到了price属性。new命令执行时,构造函数内部的this,就代表了新生成的实例对象,this.price表示实例对象有一个price属性,值是1000。

     使用new命令时,根据需要,构造函数也可以接受参数。

1
2
3
4
5
var Vehicle = function (p) {
this.price = p;
};

var v = new Vehicle(500);

     new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的,但是为了表示这里是函数调用,推荐使用括号。

1
2
3
4
// 推荐的写法
var v = new Vehicle();
// 不推荐的写法
var v = new Vehicle;

     一个很自然的问题是,如果忘了使用new命令,直接调用构造函数会发生什么事?

     这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象,将造成一些意想不到的结果。

1
2
3
4
5
6
7
var Vehicle = function (){
this.price = 1000;
};

var v = Vehicle();
v // undefined
price // 1000

浅述Java对象的内存布局

     Java的实例对象、数组对象在内存中的组成包括如下三部分:对象头Hearder、实例数据、内存填充。示意图如下所示:

对象头结构

  • 对象头:其主要包括两部分数据:Mark Word、Class对象指针。特别地对于数组对象而言,其还包括了数组长度数据。在64位的HotSpot虚拟机下,Mark Word占8个字节,其记录了Hash Code、GC信息、锁信息等相关信息;而Class对象指针则指向该实例的Class对象,在开启指针压缩的情况下占用4个字节,否则占8个字节;如果其是一个数组对象,则还需要4个字节用于记录数组长度信息。这里列出64位HotSpot虚拟机Mark Word的具体含义,以供参考。需要注意的是在下图的Mark Word中,左侧为高字节,右侧为低字节。

对象头细节

  • 实例数据:用于存放该对象的实例数据。

  • 内存填充:64位的HotSpot要求Java对象地址按8字节对齐,即每个对象所占内存的字节数必须是8字节的整数倍。因此Java对象需要通过内存填充来满足对齐要求。

一键部署单机K8S环境

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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
#!/bin/bash
. /etc/init.d/functions

# IP地址,默认为本机第一块网卡IP地址(不包含lo网卡)
ip=
# 主机名称,默认为当前主机名称
hostName=master
# Docker版本
dockerVersion=20.10.6
# Kubernetes版本
k8sVersion=1.23.0
# Pod网段
podSubnet="10.244.0.0/16"
# Service网段
serviceSubnet="10.10.0.0/16"

networkCheck(){
ping -c 1 www.baidu.com > /dev/null 2>&1

if [ $? -eq 0 ];then
action "外网权限检查:"
else
action "外网权限检查:"
echo "此脚本需要访问外网权限才可成功执行,退出脚本"
exit 5
fi
}
cpuCheck(){
cpuCores=$(grep -c ^processor /proc/cpuinfo)
if [[ ${cpuCores} -lt 2 ]];then
action "CPU配置检查:" false
echo -e "\033[32m# 当前主机CPU ${cpuCores}核 < 2核,不满足安装K8s最低需求,请检查配置\033[0m"
exit 5
else
action "CPU配置检查:"
fi
}

menoryCheck(){
menorySize=$(free -m|grep -i mem|awk '{print $2}')

if [[ ${menorySize} -lt 1800 ]];then
action "内存配置检查:" false
echo -e "\033[32m# 当前主机内存 ${menorySize}M < 1800M(2G),不满足安装K8s最低需求,请检查配置\033[0m"
exit 5
else
action "内存配置检查:"
fi
}


stopFirewall(){
systemctl disable firewalld --now &>/dev/null
setenforce 0 &>/dev/null
sed -i.$(date +%F) -r 's/SELINUX=[ep].*/SELINUX=disabled/g' /etc/selinux/config

if (grep SELINUX=disabled /etc/selinux/config) &>/dev/null;then
action "关闭防火墙:"
else
action "关闭防火墙:" false
fi
}

hostName(){
if [[ -z ${ip} ]];then
ip=$(ip addr | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+'|egrep -v "127.0.0.1|172.17.0.1"|awk NR==1)
fi

if [[ -z ${hostName} ]];then
hostName="${HOSTNAME}"
fi

if ! (egrep -w "${ip} +${hostName}" /etc/hosts) &>/dev/null;then
hostnamectl set-hostname ${hostName}
echo "${ip} ${hostName}" >> /etc/hosts
fi

if (egrep -w "${ip} +${hostName}" /etc/hosts) &>/dev/null;then
action "添加本地域名解析:"
else
action "添加本地域名解析:" false
fi
}

timeSync(){
if ! (which ntpdate &>/dev/null);then
echo -e "\033[32m# ntpdate未安装,开始进行安装....\033[0m"
(yum -y install ntpdate) &>/dev/null;sleep 0.3
if (which ntpdate &>/dev/null);then
action "ntpdate安装成功:"
fi
fi

if (ntpdate ntp1.aliyun.com &>/dev/null);then
if ! (egrep "ntpdate +ntp1.aliyun.com" /var/spool/cron/root &>/dev/null);then
echo "0 1 * * * ntpdate ntp1.aliyun.com" >> /var/spool/cron/root
fi
action "时间同步:"
else
action "时间同步:" false
fi
}

swapOff(){
swapoff --all
sed -i -r '/swap/ s/^/#/' /etc/fstab

if [[ $(free | grep -i swap | awk '{print $2}') -eq 0 ]]; then
action "关闭交换分区:"
else
action "关闭交换分区:" false
fi
}

addKernelArg(){
KernelArg=("net.bridge.bridge-nf-call-ip6tables" "net.bridge.bridge-nf-call-iptables" "net.ipv4.ip_forward")

# 判断内核参数是否存在,如果不存在则添加
for ((i=0;i<${#KernelArg[@]};i++))do
if [[ $(sysctl -n ${KernelArg[i]}) -ne 1 ]];then
echo "${KernelArg[i]} = 1" >> /etc/sysctl.d/kubernetes.conf
fi
done
modprobe br_netfilter &>/dev/null
sysctl -p /etc/sysctl.d/kubernetes.conf &>/dev/null

if [[ $(sysctl -n ${KernelArg[0]}) -eq 1 && $(sysctl -n ${KernelArg[1]}) -eq 1 && $(sysctl -n ${KernelArg[2]}) -eq 1 ]]; then
action "添加内核参数:"
else
action "添加内核参数:" false
fi

}

ipvs(){
if (command -v ipset &>/dev/null && command -v ipvsadm &>/dev/null);then
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
chmod +x /etc/sysconfig/modules/ipvs.modules
/etc/sysconfig/modules/ipvs.modules
else
echo -e "\033[32m# ipvs未安装,开始进行安装....\033[0m"
yum -y install ipset ipvsadm &>/dev/null
if (command -v ipset &>/dev/null && command -v ipvsadm &>/dev/null);then
action "ipvs安装成功:"
cat > /etc/sysconfig/modules/ipvs.modules <<EOF
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
EOF
chmod +x /etc/sysconfig/modules/ipvs.modules
/etc/sysconfig/modules/ipvs.modules

fi
fi
modprobe br_netfilter &>/dev/null

if (lsmod | grep -q -e ip_vs -e nf_conntrack_ipv4)&>/dev/null; then
action "启用ipvs模块:"
else
action "启用ipvs模块:" false
fi
}
dockerInstall(){
if ! (command -v docker &>/dev/null);then
echo -e "\033[32m# Docker未安装,开始进行安装....\033[0m"
(curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo) &>/dev/null
(wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo) &>/dev/null
(yum install -y yum-utils) &>/dev/null
(yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo) &>/dev/null
(yum install docker-ce-${dockerVersion} docker-ce-cli-${dockerVersion} -y) &>/dev/null
if (command -v docker &>/dev/null);then
action "Docker安装成功:"
else
action "Docker安装成功:" false
fi
fi


mkdir /etc/docker &>/dev/null
if [[ -f /etc/docker/daemon.json ]];then
mv /etc/docker/daemon.json{,.$(date +%F)}
fi

cat <<EOF > /etc/docker/daemon.json
{
"registry-mirrors": ["https://aoewjvel.mirror.aliyuncs.com"],
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
(systemctl enable docker --now) &>/dev/null

if [[ -f /etc/docker/daemon.json ]];then
action "Docker镜像加速源:"
else
action "Docker镜像加速源:"
fi
}

k8sInstall(){
k8scommand=("kubeadm" "kubelet" "kubectl")

if [[ -f /etc/yum.repos.d/kubernetes.repo ]];then
mv /etc/yum.repos.d/kubernetes.repo{,.$(date +%F)}
fi

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
EOF

echo -e "\033[32m# 正在安装K8S,请耐心等待......\033[0m"
(yum -y install --setopt=obsoletes=0 kubeadm-${k8sVersion} kubelet-${k8sVersion} kubectl-${k8sVersion}) &>/dev/null
systemctl enable kubelet.service --now &>/dev/null

for ((i=0;i<${#k8scommand[@]};i++))do
if (command -v ${k8scommand[i]} &>/dev/null);then
action "安装${k8scommand[i]}组件:"
else
action "安装${k8scommand[i]}组件:" false
fi
done
}

k8sInit(){
# 通过hosts文件获取IP地址
if [[ -z ${ip} ]];then
ip=$(grep ${HOSTNAME} /etc/hosts|awk '{print $1}'| awk NR==1)
fi

if [[ -f /root/kubeadm-config.yaml ]];then
mv /root/kubeadm-config.yaml{,.$(date +%F)}
fi

cat >> /root/kubeadm-config.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: ${ip}
bindPort: 6443
nodeRegistration:
imagePullPolicy: IfNotPresent
name: ${hostName}
taints: null
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: ${k8sVersion}
networking:
dnsDomain: cluster.local
serviceSubnet: ${serviceSubnet}
podSubnet: ${podSubnet}
scheduler: {}
---
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: ipvs
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOF

if [[ -f /root/kubeadm-config.yaml ]];then
action "生成K8s初始化文件:"
else
action "生成K8s初始化文件:" false
fi
echo -e "\033[32m# K8s初始化中,时间可能较长,可以使用 tailf k8s_init.log 可追踪整个过程....\033[0m"
echo
kubeadm init --config /root/kubeadm-config.yaml --ignore-preflight-errors=SystemVerification &>k8s_init.log
if [[ $? -eq 0 ]];then
action "K8s初始化:"
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
else
action "K8s初始化:" false
exit 5
fi
}

k8sNetwork(){
(wget -O /root/calico.yaml https://gitee.com/qinziteng/K8S/raw/master/YMAL/calico.yaml) &>/dev/null
(kubectl apply -f /root/calico.yaml) &>/dev/null

if [[ $? -eq 0 ]];then
action "K8s网络插件:"
else
action "K8s网络插件:" false
fi
}

k8sTaint(){
(kubectl taint nodes --all node-role.kubernetes.io/master-) &>/dev/null

if [[ $? -eq 0 ]];then
action "设置Master节点可调度:"
else
action "设置Master节点可调度:" false
fi
}


confCheck(){
cpuCheck
menoryCheck
networkCheck
}

initEnv(){
clear;echo "一键部署单机版K8S脚本"
hostName
stopFirewall
swapOff
timeSync
ipvs
addKernelArg
dockerInstall
}

k8s(){
clear;k8sInstall
k8sInit
k8sNetwork
k8sTaint

echo
echo -e "\033[32m# K8s单机版部署完成,等待Pod全部运行成功即可使用 使用 kubectl get pods -n kube-system 关注Pod状态...\033[0m"
bash
}
confCheck
initEnv
k8s

三高:高可用、高性能、高扩展

     我们经常被要求设计高可用性、高可扩展性和高性能。上图包含了针对“三高”的常见解决方案。

git 分支模型

高可用性

     这意味着我们需要确保系统高水平的正常运行时间。我们经常将设计目标描述为“3个9”或“4个9”。“4个9”,即99.99%的正常运行时间,意味着服务每天只能停机8.64秒。 为了实现高可用性,我们需要在系统中增加冗余节点。 有以下几种方法可以做到这一点:

  • hot-hot结构:两个实例接收相同的输入并将输出发送到下游服务。如果其中一个实例停机,另一个实例可以立即接管。由于双方都向下游发送输出,下游系统需要进行重复数据删除。

  • hot-warm结构:两个实例接收相同的输入,只有hot实例将输出发送到下游服务。如果hot实例发生故障,warm实例将接管并开始向下游服务发送输出。

  • single-leader Cluster:一个leader实例从上游系统接收数据并复制到其他副本。

  • Leaderless cluster:在这种类型的集群中没有领导者。任何写入操作都会被复制到其他实例。只要写入实例的数量加上读取实例的数量大于实例的总数,我们就会得到有效数据。

高性能

     这意味着服务需要在一段时间内处理大量请求。常用的指标是QPS(每秒查询数)或TPS(每秒事务数)。为了实现高性能,我们经常在架构中添加缓存,这样请求就可以在不命中数据库或磁盘等较慢的I/O设备的情况下返回。我们还可以增加计算密集型任务的线程数量。然而,添加太多线程可能会降低性能。最后,我们需要识别系统中的瓶颈并提高其性能。使用异步处理通常可以有效地隔离繁重的组件。

高可扩展性

     这意味着系统可以快速轻松地扩展以容纳更多容量(横向可扩展性)或更多功能(纵向可扩展性)。通常,我们会观察响应时间以决定是否需要扩展系统。为了实现高可扩展性,重要的是将服务的职责分离。为此,微服务被广泛采用。我们还利用服务注册表和负载均衡器将请求路由到适当的实例。

男人开始变成熟的迹象

  • Copyrights © 2023-2024 杨海波
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信