使用Kubernetes进行ProxySQL本机群集
自v1.4.2起,ProxySQL支持本机群集。这意味着多个ProxySQL实例可识别群集; 他们了解彼此的状态,并能够通过根据配置版本,时间戳和校验和值同步最新的配置来自动处理配置更改。
ProxySQL是一个分散的代理,建议更靠近应用程序部署。这种方法甚至可以扩展到数百个节点,因为它可以在运行时轻松重新配置。为了有效地管理多个ProxySQL节点,必须确保在其中一个节点上执行的任何更改都应该应用于服务器场中的所有节点。如果没有本机群集,则必须手动导出配置并将其导入其他节点(尽管您可以自行进行自动化)。
使用ConfigMap中的集中配置方法,这种方法或多或少非常有效。无论加载到ConfigMap中的是什么都将被安装到pod中。更新配置可以通过版本控制(修改proxysql.cnf内容并将其加载到另一个名称的ConfigMap),然后根据部署方法调度和更新策略推送到pod。
但是,在快速变化的环境中,这种ConfigMap方法可能不是最好的方法,因为为了加载新配置,需要重新安排pod重新安排ConfigMap卷,这可能会危及整个ProxySQL服务。例如,假设在我们的环境中,我们的严格密码策略要求每7天强制MySQL用户密码过期,我们必须每周更新ProxySQL ConfigMap以获取新密码。另外,ProxySQL中的MySQL用户需要用户和密码才能匹配后端MySQL服务器上的用户和密码。这就是我们应该开始在Kubernetes中使用ProxySQL本机群集支持的地方,自动应用配置更改,而无需ConfigMap版本控制和pod重新安排的麻烦。
在这篇博文中,我将向您展示如何在Kubernetes上运行具有无头服务的ProxySQL本机群集。我们的高级架构可以说明如下:
我们在ClusterControl部署和管理的裸机基础设施上运行了3个Galera节点:
- 192.168.0.21
- 192.168.0.22
- 192.168.0.23
我们的应用程序都在Kubernetes中作为pod运行。我们的想法是在应用程序和数据库集群之间引入两个ProxySQL实例作为反向代理。然后,应用程序将通过Kubernetes服务连接到ProxySQL pod,这将在多个ProxySQL副本之间进行负载平衡和故障转移。
以下是我们的Kubernetes设置的摘要:
1
2
3
4
5
|
root@kube1:~ # kubectl get nodes -o wide<font></font> NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME<font>< /font > kube1 Ready master 5m v1.15.1 192.168.100.201 <none> Ubuntu 18.04.1 LTS 4.15.0-39-generic docker: //18 .9.7<font>< /font > kube2 Ready <none> 4m1s v1.15.1 192.168.100.202 <none> Ubuntu 18.04.1 LTS 4.15.0-39-generic docker: //18 .9.7<font>< /font > kube3 Ready <none> 3m42s v1.15.1 192.168.100.203 <none> Ubuntu 18.04.1 LTS 4.15.0-39-generic docker: //18 .9.7 |
通过ConfigMap进行ProxySQL配置
让我们首先准备我们的基本配置,它将被加载到ConfigMap中。创建一个名为proxysql.cnf的文件并添加以下行:
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
|
datadir= "/var/lib/proxysql" <font></font> <font></font> admin_variables=<font></font> {<font></font> admin_credentials= "proxysql-admin:adminpassw0rd;cluster1:secret1pass" <font></font> mysql_ifaces= "0.0.0.0:6032" <font></font> refresh_interval=2000<font></font> cluster_username= "cluster1" <font></font> cluster_password= "secret1pass" <font></font> cluster_check_interval_ms=200<font></font> cluster_check_status_frequency=100<font></font> cluster_mysql_query_rules_save_to_disk= true <font></font> cluster_mysql_servers_save_to_disk= true <font></font> cluster_mysql_users_save_to_disk= true <font></font> cluster_proxysql_servers_save_to_disk= true <font></font> cluster_mysql_query_rules_diffs_before_sync=3<font></font> cluster_mysql_servers_diffs_before_sync=3<font></font> cluster_mysql_users_diffs_before_sync=3<font></font> cluster_proxysql_servers_diffs_before_sync=3<font></font> }<font></font> <font></font> mysql_variables=<font></font> {<font></font> threads=4<font></font> max_connections=2048<font></font> default_query_delay=0<font></font> default_query_timeout=36000000<font></font> have_compress= true <font></font> poll_timeout=2000<font></font> interfaces= "0.0.0.0:6033;/tmp/proxysql.sock" <font></font> default_schema= "information_schema" <font></font> stacksize=1048576<font></font> server_version= "5.1.30" <font></font> connect_timeout_server=10000<font></font> monitor_history=60000<font></font> monitor_connect_interval=200000<font></font> monitor_ping_interval=200000<font></font> ping_interval_server_msec=10000<font></font> ping_timeout_server=200<font></font> commands_stats= true <font></font> sessions_sort= true <font></font> monitor_username= "proxysql" <font></font> monitor_password= "proxysqlpassw0rd" <font></font> monitor_galera_healthcheck_interval=2000<font></font> monitor_galera_healthcheck_timeout=800<font></font> }<font></font> <font></font> mysql_galera_hostgroups =<font></font> (<font></font> {<font></font> writer_hostgroup=10<font></font> backup_writer_hostgroup=20<font></font> reader_hostgroup=30<font></font> offline_hostgroup=9999<font></font> max_writers=1<font></font> writer_is_also_reader=1<font></font> max_transactions_behind=30<font></font> active=1<font></font> }<font></font> )<font></font> <font></font> mysql_servers =<font></font> (<font></font> { address= "192.168.0.21" , port=3306 , hostgroup=10, max_connections=100 },<font></font> { address= "192.168.0.22" , port=3306 , hostgroup=10, max_connections=100 },<font></font> { address= "192.168.0.23" , port=3306 , hostgroup=10, max_connections=100 }<font></font> )<font></font> <font></font> mysql_query_rules =<font></font> (<font></font> {<font></font> rule_id=100<font></font> active=1<font></font> match_pattern= "^SELECT .* FOR UPDATE" <font></font> destination_hostgroup=10<font></font> apply=1<font></font> },<font></font> {<font></font> rule_id=200<font></font> active=1<font></font> match_pattern= "^SELECT .*" <font></font> destination_hostgroup=20<font></font> apply=1<font></font> },<font></font> {<font></font> rule_id=300<font></font> active=1<font></font> match_pattern= ".*" <font></font> destination_hostgroup=10<font></font> apply=1<font></font> }<font></font> )<font></font> <font></font> mysql_users =<font></font> (<font></font> { username = "wordpress" , password = "passw0rd" , default_hostgroup = 10, transaction_persistent = 0, active = 1 },<font></font> { username = "sbtest" , password = "passw0rd" , default_hostgroup = 10, transaction_persistent = 0, active = 1 }<font></font> )<font></font> <font></font> proxysql_servers =<font></font> (<font></font> { hostname = "proxysql-0.proxysqlcluster" , port = 6032, weight = 1 },<font></font> { hostname = "proxysql-1.proxysqlcluster" , port = 6032, weight = 1 }<font></font> ) |
以下部分解释了上面的一些配置行:
admin_variables
注意admin_credentials变量,我们使用非默认用户“proxysql-admin”。ProxySQL仅通过localhost为本地连接保留默认的“admin”用户。因此,我们必须使用其他用户远程访问ProxySQL实例。否则,您将收到以下错误:
1
|
ERROR 1040 (42000): User 'admin' can only connect locally |
我们还在admin_credentials行中附加了cluster_username和cluster_password值,以分号分隔以允许自动同步发生。所有以cluster_ *为前缀的变量都与ProxySQL本机群集相关,并且不言自明。
mysql_galera_hostgroups
这是为ProxySQL 2.x引入的新指令(我们的ProxySQL映像在2.0.5上运行)。如果您想在ProxySQL 1.x上运行,请删除此部分并改为使用调度程序表。我们已经在这篇博文中解释了配置细节,如何在Docker上运行和配置针对MySQL Galera Cluster的ProxySQL 2.0“对Galera集群的 ProxySQL 2.x支持”。
mysql_servers
所有行都是不言自明的,它基于在MySQL Galera Cluster中运行的三个数据库服务器,如以下从ClusterControl获取的拓扑截图中所概述:
proxysql_servers
这里我们定义一个ProxySQL对等列表:
- hostname - 对等方的主机名/ IP地址
- port - Peer的管理端口
- 重量 - 目前未使用,但在未来增强的路线图中
- 评论 - 免费表单评论字段
在Docker / Kubernetes环境中,有多种方法可以发现和链接容器主机名或IP地址,并将它们插入到此表中,方法是使用ConfigMap,手动插入,通过entrypoint.sh脚本,环境变量或其他方法。在Kubernetes中,根据所使用的ReplicationController或Deployment方法,在高级中猜测pod的可解析主机名有点棘手,除非您在StatefulSet上运行。
查看有关StatefulState pod序数索引的本教程,该索引为创建的pod提供稳定的可解析主机名。将此与无头服务相结合(进一步解释),可解析的主机名格式为:
{APP_NAME} - {index_number} {}服务。
其中{service}是无头服务,它解释了“proxysql-0.proxysqlcluster”和“proxysql-1.proxysqlcluster”的来源。如果要包含2个以上的副本,请通过附加相对于StatefulSet应用程序名称的升序索引号来相应地添加更多条目。
现在我们准备将配置文件推送到ConfigMap,它将在部署期间安装到每个ProxySQL pod中:
1
|
$ kubectl create configmap proxysql-configmap --from- file =proxysql.cnf |
验证我们的ConfigMap是否正确加载:
1
2
3
|
$ kubectl get configmap<font>< /font > NAME DATA AGE<font>< /font > proxysql-configmap 1 7h57m |
创建ProxySQL监控用户
开始部署之前的下一步是在数据库集群中创建ProxySQL监控用户。由于我们在Galera集群上运行,因此在其中一个Galera节点上运行以下语句:
1
2
|
mysql> CREATE USER 'proxysql' @ '%' IDENTIFIED BY 'proxysqlpassw0rd' ;<font></font> mysql> GRANT USAGE ON *.* TO 'proxysql' @ '%' ; |
如果您还没有创建MySQL用户(如上面mysql_users部分所述),我们也必须创建它们:
1
2
3
4
|
mysql> CREATE USER 'wordpress' @ '%' IDENTIFIED BY 'passw0rd' ;<font></font> mysql> GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress' @ '%' ;<font></font> mysql> CREATE USER 'sbtest' @ '%' IDENTIFIED BY 'passw0rd' ;<font></font> mysql> GRANT ALL PRIVILEGES ON sbtest.* TO 'proxysql' @ '%' ; |
而已。我们现在准备开始部署。
部署StatefulSet
我们将首先使用StatefulSet为冗余目的创建两个ProxySQL实例或副本。
让我们首先创建一个名为proxysql-ss-svc.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
|
apiVersion: apps /v1 <font>< /font > kind: StatefulSet<font>< /font > metadata:<font>< /font > name: proxysql<font>< /font > labels:<font>< /font > app: proxysql<font>< /font > spec:<font>< /font > replicas: 2<font>< /font > serviceName: proxysqlcluster<font>< /font > selector:<font>< /font > matchLabels:<font>< /font > app: proxysql<font>< /font > tier: frontend<font>< /font > updateStrategy:<font>< /font > type : RollingUpdate<font>< /font > template:<font>< /font > metadata:<font>< /font > labels:<font>< /font > app: proxysql<font>< /font > tier: frontend<font>< /font > spec:<font>< /font > restartPolicy: Always<font>< /font > containers:<font>< /font > - image: severalnines /proxysql :2.0.4<font>< /font > name: proxysql<font>< /font > volumeMounts:<font>< /font > - name: proxysql-config<font>< /font > mountPath: /etc/proxysql .cnf<font>< /font > subPath: proxysql.cnf<font>< /font > ports:<font>< /font > - containerPort: 6033<font>< /font > name: proxysql-mysql<font>< /font > - containerPort: 6032<font>< /font > name: proxysql-admin<font>< /font > volumes:<font>< /font > - name: proxysql-config<font>< /font > configMap:<font>< /font > name: proxysql-configmap<font>< /font > ---<font>< /font > apiVersion: v1<font>< /font > kind: Service<font>< /font > metadata:<font>< /font > annotations:<font>< /font > labels:<font>< /font > app: proxysql<font>< /font > tier: frontend<font>< /font > name: proxysql<font>< /font > spec:<font>< /font > ports:<font>< /font > - name: proxysql-mysql<font>< /font > port: 6033<font>< /font > protocol: TCP<font>< /font > targetPort: 6033<font>< /font > - name: proxysql-admin<font>< /font > nodePort: 30032<font>< /font > port: 6032<font>< /font > protocol: TCP<font>< /font > targetPort: 6032<font>< /font > selector:<font>< /font > app: proxysql<font>< /font > tier: frontend<font>< /font > type : NodePort |
上面定义有两个部分 - StatefulSet和Service。StatefulSet是从proxysql-configmap加载的pods或副本以及ConfigMap卷的挂载点的定义。下一节是服务定义,我们在其中定义如何为内部或外部网络公开和路由pod。
验证pod和服务状态:
1
2
3
4
5
6
7
8
|
$ kubectl get pods,svc<font>< /font > NAME READY STATUS RESTARTS AGE<font>< /font > pod /proxysql-0 1 /1 Running 0 4m46s<font>< /font > pod /proxysql-1 1 /1 Running 0 2m59s<font>< /font > <font>< /font > NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE<font>< /font > service /kubernetes ClusterIP 10.96.0.1 <none> 443 /TCP 10h<font>< /font > service /proxysql NodePort 10.111.240.193 <none> 6033:30314 /TCP ,6032:30032 /TCP 5m28s |
如果你看一下pod的日志,你会发现我们被这个警告淹没了:
1
2
3
|
$ kubectl logs -f proxysql-0<font>< /font > ...<font>< /font > 2019-08-01 19:06:18 ProxySQL_Cluster.cpp:215:ProxySQL_Cluster_Monitor_thread(): [WARNING] Cluster: unable to connect to peer proxysql-1.proxysqlcluster:6032 . Error: Unknown MySQL server host 'proxysql-1.proxysqlcluster' (0) |
以上只是意味着proxysql-0无法解析“proxysql-1.proxysqlcluster”并连接到它,这是预料之中的,因为我们还没有为代理SQL间通信所需的DNS记录创建无头服务。
Kubernetes无头服务
为了使ProxySQL pod能够解析预期的FQDN并直接连接到它,解析过程必须能够查找分配的目标pod IP地址而不是虚拟IP地址。这是无头服务进入画面的地方。通过设置“ clusterIP = None ” 创建无头服务时,不会配置负载平衡,也不会为此服务分配集群IP(虚拟IP)。仅自动配置DNS。当您为无头服务运行DNS查询时,您将获得pod IP地址的列表。
如果我们查找“proxysqlcluster”的无头服务DNS记录(在此示例中我们有3个ProxySQL实例),这就是它的样子:
1
2
3
4
|
$ host proxysqlcluster<font>< /font > proxysqlcluster.default.svc.cluster. local has address 10.40.0.2<font>< /font > proxysqlcluster.default.svc.cluster. local has address 10.40.0.3<font>< /font > proxysqlcluster.default.svc.cluster. local has address 10.32.0.2 |
同时,以下输出显示名为“proxysql”的标准服务的DNS记录,该记录解析为clusterIP:
1
2
|
$ host proxysql<font>< /font > proxysql.default.svc.cluster. local has address 10.110.38.154 |
要创建无头服务并将其附加到pod,必须在StatefulSet声明中定义ServiceName,并且Service定义必须具有“ clusterIP = None ”,如下所示。创建一个名为proxysql-headless-svc.yml的文本文件,并添加以下行:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
apiVersion: v1<font>< /font > kind: Service<font>< /font > metadata:<font>< /font > name: proxysqlcluster<font>< /font > labels:<font>< /font > app: proxysql<font>< /font > spec:<font>< /font > clusterIP: None<font>< /font > ports:<font>< /font > - port: 6032<font>< /font > name: proxysql-admin<font>< /font > selector:<font>< /font > app: proxysql |
创建无头服务:
1
|
$ kubectl create -f proxysql-headless-svc.yml |
仅用于验证,此时,我们运行以下服务:
1
2
3
4
5
|
$ kubectl get svc<font>< /font > NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE<font>< /font > kubernetes ClusterIP 10.96.0.1 <none> 443 /TCP 8h<font>< /font > proxysql NodePort 10.110.38.154 <none> 6033:30200 /TCP ,6032:30032 /TCP 23m<font>< /font > proxysqlcluster ClusterIP None <none> 6032 /TCP 4s |
现在,查看我们的pod日志之一:
1
2
3
4
5
|
$ kubectl logs -f proxysql-0<font>< /font > ...<font>< /font > 2019-08-01 19:06:19 ProxySQL_Cluster.cpp:215:ProxySQL_Cluster_Monitor_thread(): [WARNING] Cluster: unable to connect to peer proxysql-1.proxysqlcluster:6032 . Error: Unknown MySQL server host 'proxysql-1.proxysqlcluster' (0)<font>< /font > 2019-08-01 19:06:19 [INFO] Cluster: detected a new checksum for mysql_query_rules from peer proxysql-1.proxysqlcluster:6032, version 1, epoch 1564686376, checksum 0x3FEC69A5C9D96848 . Not syncing yet ...<font>< /font > 2019-08-01 19:06:19 [INFO] Cluster: checksum for mysql_query_rules from peer proxysql-1.proxysqlcluster:6032 matches with local checksum 0x3FEC69A5C9D96848 , we won't sync . |
您会注意到Cluster组件能够通过名为“proxysqlcluster”的无头服务从端口6032上的其他对等端proxysql-1.proxysqlcluster解析,连接和检测新的校验和。请注意,此服务仅在Kubernetes网络中公开端口6032,因此无法从外部访问。
此时,我们的部署现已完成。
连接到ProxySQL
有几种方法可以连接到ProxySQL服务。负载均衡的MySQL连接应从Kubernetes网络内发送到端口6033,如果客户端从外部网络连接,则使用端口30033。
要从外部网络连接到ProxySQL管理界面,我们可以连接到NodePort部分30032下定义的端口(192.168.100.203是主机kube3.local的主IP地址):
1
|
$ mysql -uproxysql-admin -padminpassw0rd -h192.168.100.203 -P30032 |
如果要从Kubernetes网络中的其他pod访问,请在端口6032上使用clusterIP 10.110.38.154(在“proxysql”服务下定义)。
然后根据需要执行ProxySQL配置更改并将其加载到运行时:
1
2
|
mysql> INSERT INTO mysql_users (username, password ,default_hostgroup) VALUES ( 'newuser' , 'passw0rd' ,10);<font></font> mysql> LOAD MYSQL USERS TO RUNTIME; |
您将注意到其中一个窗格中的以下行指示配置同步完成:
1
2
3
4
5
6
|
$ kubectl logs -f proxysql-0<font>< /font > ...<font>< /font > 2019-08-02 03:53:48 [INFO] Cluster: detected a peer proxysql-1.proxysqlcluster:6032 with mysql_users version 2, epoch 1564718027, diff_check 4. Own version: 1, epoch: 1564714803. Proceeding with remote sync <font>< /font > 2019-08-02 03:53:48 [INFO] Cluster: detected peer proxysql-1.proxysqlcluster:6032 with mysql_users version 2, epoch 1564718027<font>< /font > 2019-08-02 03:53:48 [INFO] Cluster: Fetching MySQL Users from peer proxysql-1.proxysqlcluster:6032 started<font>< /font > 2019-08-02 03:53:48 [INFO] Cluster: Fetching MySQL Users from peer proxysql-1.proxysqlcluster:6032 completed |
请记住,只有在ProxySQL运行时中发生配置更改时才会发生自动同步。因此,在看到动作之前运行“ LOAD ... TO RUNTIME ”语句至关重要。不要忘记将ProxySQL更改保存到磁盘中以保持持久性:
1
|
mysql> SAVE MYSQL USERS TO DISK; |
局限性
请注意,此设置存在限制,因为ProxySQL不支持将活动配置保存/导出到文本配置文件中,以后我们可以将其加载到ConfigMap中以保持持久性。有一个功能要求。同时,您可以手动将修改推送到ConfigMap。否则,如果意外删除了pod,则会丢失当前配置,因为新的pod将由ConfigMap中定义的任何内容引导。
特别感谢Sampath Kamineni,他引发了这篇博客文章的想法,并提供了有关用例和实现的见解。
欢迎关注公众号:“Java架构师学习”
你会喜欢的!
使用Kubernetes进行ProxySQL本机群集的更多相关文章
- kubernetes之node 宕机,pod驱离问题解决
背景: 当node宕机时,希望该node节点上的pod能够快速疏散到其他节点,并提供服务.测试发现,要等待5分钟,上面的pod才会疏散. 网上介绍通过修改 /etc/kubernetes/manife ...
- ProxySQL Cluster 高可用集群环境部署记录
ProxySQL在早期版本若需要做高可用,需要搭建两个实例,进行冗余.但两个ProxySQL实例之间的数据并不能共通,在主实例上配置后,仍需要在备用节点上进行配置,对管理来说非常不方便.但是Proxy ...
- ProxySQL Cluster 高可用集群 + MySQL MGR环境部署 (多写模式) 部署记录
文章转载自:https://blog.51cto.com/u_6215974/4937192 ProxySQL 在早期版本若需要做高可用,需要搭建两个实例,进行冗余.但两个ProxySQL实例之间的数 ...
- ProxySQL+MGR实现读写分离和主节点故障无感知切换 - 完整操作记录
前面的文章介绍了ProxySQL用法,这里说下ProxySQL中间件针对Mysql组复制模式实现读写分离以及主节点故障时能够自动切换到新的主节点,而应用对此过程无感知的功能.Mysql组复制(MGR) ...
- ProxySQL 配置详解及读写分离(+GTID)等功能说明 (完整篇)
ProxySQL是灵活强大的MySQL代理层, 是一个能实实在在用在生产环境的MySQL中间件,可以实现读写分离,支持 Query 路由功能,支持动态指定某个 SQL 进行 cache,支持动态加载配 ...
- kubernetes学习:CKA考试认证
考点 CKA认证针对考核成为当业界的Kubernetes管理员所需的技能. CKA认证考试包括这些一般领域及其在考试中的权重: 应用程序生命周期管理 - 8% 安装.配置和验证 - 12% 核心概 ...
- Kubernetes Clusters
1. 创建集群 Kubernetes集群 Kubernetes协调一个高可用的计算机集群,作为一个单独的单元来一起工作.有了这种抽象,在Kubernetes中你就可以将容器化的应用程序部署到集群中, ...
- Kubernetes 开船记-脚踏两只船:用 master 服务器镜像克隆出新集群
自从2020年2月23日 园子全站登船 之后,我们一边感叹"不上船不知道,一上船吓一跳" -- kubernetes 比 docker swarm 强大太多,一边有一个杞人忧天的担 ...
- K8S概念理解
Master 负责管理集群 负责协调集群中的所有活动,例如调度应用程序,维护应用程序的状态,扩展和更新应用程序. Worker节点是VM(虚拟机)或物理计算机,充当k8s集群中的工作计算机. 每个Wo ...
随机推荐
- hadoop伪分布模式的配置和一些常用命令
大数据的发展历史 3V:volume.velocity.variety(结构化和非结构化数据).value(价值密度低) 大数据带来的技术挑战 存储容量不断增加 获取有价值的信息的难度:搜索.广告.推 ...
- JavaScript 基于HTML5 canvas 获取文本占用的像素宽度
基于HTML5 canvas 获取文本占用的像素宽度 by:授客 QQ:1033553122 直接上代码 // 获取单行文本的像素宽度 getTextPixelWith(text, fontS ...
- 最近学习了Http连接池
起因 6.1大促值班发现的一个问题,一个rpc接口在0~2点用户下单高峰的时候表现rt高(超过1s,实际上针对性优化过的接口rt超过这个值也是有问题的,通常rpc接口里面即使逻辑复杂,300ms应该也 ...
- Newifi-mini OpenWrt 下 EAP-PEAP,EAP-TLS 企业级无线认证及 FreeRadius3
Newifi-mini OpenWrt 下 EAP-PEAP,EAP-TLS 企业级无线认证及 FreeRadius3 转载注明来源: 本文链接 来自osnosn的博客,写于 2019-07-15. ...
- SpringBoot系列——Jackson序列化
前言 Spring Boot提供了与三个JSON映射库的集成: Gson Jackson JSON-B Jackson是首选的默认库. 官网介绍: https://docs.spring.io/spr ...
- How to: Use XPO Upcasting in XAF 如何:在 XAF 中使用 XPO 强制转换
In this topic, you will learn how to use the Upcasting feature of XPO in XAF. It is useful when you ...
- markdown简单使用
Markdown介绍: Markdown是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档.使用Markdown编写的文档可以导出为HTML.Word.图像.PDF等多种格式的文档. ...
- 剑指offer笔记面试题8----二叉树的下一个节点
题目:给定一棵二叉树和其中的一个节点,如何找出中序遍历序列的下一个节点?树中的节点除了有两个分别指向左.右子节点的指针,还有一个指向父节点的指针. 测试用例: 普通二叉树(完全二叉树,不完全二叉树). ...
- 嵌入Canvas App到Dynamics 365 Customer Engagement(Model-Driven App)中,创造更多可能!
我是微软Dynamics 365 & Power Platform方面的工程师罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面 ...
- Dynamics CRM通过定制应用程序功能区为符合条件的实体表单增加按钮
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复167或者20151029可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 前面的博文都是为一个实体添加按钮 ...