采用Atlas+Keepalived实现MySQL读写分离、读负载均衡【转载】

文章 原始出处 :http://sofar.blog.51cto.com/353572/1601552

==========================================================================================

一、基础介绍

==========================================================================================

1、背景描述

目前我们的高可用DB的代理层采用的是360开源的Atlas,从上线以来,已稳定运行2个多月。无论是从性能上,还是稳定性上,相比其他开源组件(amoeba、cobar、MaxScale、MySQL-Proxy等),还是很出色的。

 

当初我们之所以选择Atlas,主要看中它有以下优点:

(1)、基于mysql-proxy-0.8.2进行修改,代码完全开源;

(2)、比较轻量级,部署配置也比较简单;

(3)、支持DB读写分离;

(4)、支持从DB读负载均衡,并自动剔除故障从DB;

(5)、支持平滑上下线DB;

(6)、具备较好的安全机制(IP过滤、账号认证);

(7)、版本更新、问题跟进、交流圈子都比较活跃。

 

在测试期间以及线上问题排查过程中,得到了360 Atlas作者朱超的热心解答,在此表示感谢。有关更多Atlas的介绍,我就不一一例举,可以参考以下链接:

https://github.com/Qihoo360/Atlas/blob/master/README_ZH.md

 

2、总体架构图

wKioL1Sw6iagbaHjAAJX6OZk-GM940.jpg

 

3、系统环境

CentOS 6.3 x86_64

 

==========================================================================================

二、安装部署

==========================================================================================

1、需注意的地方

(1)、本次安装不使用系统默认的glib库,之前的yum安装只是为了先解决依赖库的问题;

(2)、LUA库的版本不能太高,为5.1.x即可;

(3)、glib库的版本也不能太高,为glib-2.32.x即可;

(4)、对于编译不成功的情况,注意查看下面的说明。

 

2GLIB依赖的基础库安装

# yum -y install *glib*

 

3LUA库安装

http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz

# tar xvzf ncurses-5.9.tar.gz

# cd ncurses-5.9

# ./configure --prefix=/usr/local

# make && make install

 

ftp://ftp.gnu.org/gnu/readline/readline-6.2.tar.gz

# tar xvzf readline-6.2.tar.gz

# cd readline-6.2

# ./configure --prefix=/usr/local

# make && make install

 

http://www.lua.org/ftp/lua-5.1.5.tar.gz

# tar xvzf lua-5.1.5.tar.gz

# cd lua-5.1.5

# make linux install

 

注意:

修改当前目录下的“Makefile”中的 INSTALL_TOP= /usr/local为 INSTALL_TOP= /usr/local/lua

主要是为了避免与系统自带的lua库发生冲突的可能

 

在“src/Makefile”文件中加入“-lncurses”,完整内容如下:

linux:

        $(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_LINUX" SYSLIBS="-Wl,-E -ldl -lncurses -lreadline"

 

4GLIB库安装

ftp://sourceware.org/pub/libffi/libffi-3.0.13.tar.gz

# tar xvzf libffi-3.0.13.tar.gz

# cd libffi-3.0.13

# ./configure --prefix=/usr/local

# make && make install

 

http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz

# tar xvzf libiconv-1.14.tar.gz

# cd libiconv-1.14

# ./configure --prefix=/usr/local

# make && make install

 

http://tukaani.org/xz/xz-5.0.5.tar.gz

# tar xvzf xz-5.0.5.tar.gz

# cd xz-5.0.5

# ./configure --prefix=/usr/local

# make && make install

# /sbin/ldconfig

 

http://ftp.gnome.org/pub/gnome/sources/glib/2.32/glib-2.32.4.tar.xz

# xz -d glib-2.32.4.tar.xz

# tar -xvf glib-2.32.4.tar

# cd glib-2.32.4

# ./configure --prefix=/usr/local/glib-2.32.4 \

--with-libiconv=/usr/local \

LIBFFI_CFLAGS="-I/usr/local/include" \

LIBFFI_LIBS="-L/usr/local/lib -lffi"

# make && make install

 

注意:编译报错处理

(1)configure阶段

# vim ./glib/gconvert.c

注释掉第26、28行的内容

注释掉从61行到67行的内容

 

# vim ./configure

在7880行之上添加如下内容:

found_iconv=yes

 

(2)make阶段

# ln -s /usr/local/lib/libffi-3.0.13/include/ffi.h /usr/local/include

# ln -s /usr/local/lib/libffi-3.0.13/include/ffitarget.h /usr/local/include

 

glib库需要安装在单独的目录“/usr/local/glib-2.32.4”,也是为了避免与系统自带的glib库发生冲突的可能

 

5Atlas安装

(1)、其他基础组件安装

https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz

# tar xvzf libevent-2.0.21-stable.tar.gz

# cd libevent-2.0.21-stable

# ./configure --prefix=/usr/local

# make && make install

 

http://www.openssl.org/source/openssl-1.0.1h.tar.gz

# tar xvzf openssl-1.0.1h.tar.gz

# cd openssl-1.0.1h

# ./config shared --prefix=/usr/local

# make && make install

 

(2)MySQL安装(无需启动)

http://wwwNaNake.org/files/v2.8/cmake-2.8.10.2.tar.gz

# tar -xvzf cmake-2.8.10.2.tar.gz

# cd cmake-2.8.10.2

# ./bootstrap --prefix=/usr/local

# gmake --jobs=`grep processor /proc/cpuinfo | wc -l`

# gmake install

 

http://downloads.mysql.com/archives/get/file/mysql-5.5.24.tar.gz

# tar -xvzf mysql-5.5.24.tar.gz

# cd mysql-5.5.24

# rm-f CMakeCache.txt

# cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql \

-DMYSQL_UNIX_ADDR=/var/run/mysql/mysql.sock \

-DDEFAULT_CHARSET=utf8 \

-DDEFAULT_COLLATION=utf8_general_ci \

-DEXTRA_CHARSETS=all \

-DWITH_MYISAM_STORAGE_ENGINE=1 \

-DWITH_INNOBASE_STORAGE_ENGINE=1 \

-DWITH_READLINE=1 \

-DENABLED_LOCAL_INFILE=1 \

-DWITH_EMBEDDED_SERVER=1 \

-DMYSQL_DATADIR=/data/dbdata/data \

-DMYSQL_TCP_PORT=3306

# make --jobs=`grep processor /proc/cpuinfo | wc -l`

# make install

 

(3)DB中间件安装

https://github.com/Qihoo360/Atlas/archive/2.2.1.tar.gz

# tar xvzf Atlas-2.2.1.tar.gz

# cd Atlas-2.2.1

# ./configure --prefix=/usr/local/mysql-proxy \

--with-lua=/usr/local/lua \

--with-mysql=/usr/local/mysql \

GLIB_CFLAGS="-I/usr/local/glib-2.32.4/include/glib-2.0" \

GLIB_LIBS="-L/usr/local/glib-2.32.4/lib/glib-2.0 -lglib-2.0" \

GMODULE_CFLAGS="-I/usr/local/glib-2.32.4/include" \

GMODULE_LIBS="-L/usr/local/glib-2.32.4/lib -lgmodule-2.0" \

GTHREAD_CFLAGS="-I/usr/local/glib-2.32.4/include" \

GTHREAD_LIBS="-L/usr/local/glib-2.32.4/lib -lgthread-2.0" \

LUA_CFLAGS="-I/usr/local/lua/include" \

LUA_LIBS="-L/usr/local/lua/lib -llua-5.1" \

CFLAGS="-DHAVE_LUA_H -O2" \

LDFLAGS="-L/usr/local/lib -L/usr/local/lib64 -lm -ldl -lcrypto"

# make && make install

 

注意:

编译报错处理

# ln -s /usr/local/glib-2.32.4/lib/glib-2.0/include/glibconfig.h /usr/local/glib-2.32.4/include/glib-2.0

 

# cd /usr/local

# mv mysql-proxy atlas-2.2.1 && ln -s atlas-2.2.1 mysql-proxy

 

6DB中间层配置

(1)、主配置

# vim /usr/local/mysql-proxy/conf/mysql-proxy.cnf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[mysql-proxy]
admin-username = sysadmin
admin-password = admin2356!@()
  
proxy-backend-addresses = 10.222.5.224:3306
proxy-read-only-backend-addresses = 10.240.95.107:3306,10.240.95.108:3306
  
pwds = health_check1:/iZxz+0GRoA=,health_check2:/iZxz+0GRoA=
  
daemon = true
keepalive = true
  
event-threads = 16
  
log-level = message
log-path = /usr/local/mysql-proxy/log
sql-log = ON
  
proxy-address = 0.0.0.0:3306
admin-address = 10.209.6.101:3307
  
charset = utf8

(2)、启动脚本

# vim /etc/init.d/mysql-proxy

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
#!/bin/sh
#
# mysql-proxy This script starts and stops the mysql-proxy daemon
#
# chkconfig: - 78 30
# processname: mysql-proxy
# description: mysql-proxy is a proxy daemon to mysql
# config: /usr/local/mysql-proxy/conf/mysql-proxy.cnf
# pidfile: /usr/local/mysql-proxy/log/mysql-proxy.pid
#
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
  
DAEMON="/usr/local/mysql-proxy/bin/mysql-proxy"
CONFIGFILE="/usr/local/mysql-proxy/conf/mysql-proxy.cnf"
PIDFILE="/usr/local/mysql-proxy/log/mysql-proxy.pid"
LOCKFILE="/var/lock/subsys/mysql-proxy"
PROG=`basename $DAEMON`
  
RETVAL=0
  
start() {
    echo -n $"Starting ${PROG}......"
    [ -x $DAEMON ] || exit 5
    [ -f $CONFIGFILE ] || exit 6
    ${DAEMON} --defaults-file=${CONFIGFILE} || echo -n "${PROG} already running"
  
    RETVAL=$?
    echo
    [[ $RETVAL -eq 0 ]] && touch $LOCKFILE
  
    return $RETVAL
}
  
stop() {
    echo -n $"Stopping ${PROG}......"
    if [[ `ps aux | grep bin/mysql-proxy grep -v grep wc -l` -gt 0 ]]; then
        kill -TERM `ps -A -oppid,pid,cmd | grep bin/mysql-proxy grep -v grep awk '{print $2}'`
    fi
  
    RETVAL=$?
    echo
    [[ $RETVAL -eq 0 ]] && rm -f $LOCKFILE $PIDFILE
  
    return $RETVAL
}
  
restart() {
    stop
    sleep 1
    start
}
  
case "$1" in
start)
    start
    ;;
  
stop)
    stop
    ;;
  
restart)
    restart
    ;;
  
condrestart)
    [[ -e $LOCKFILE ]] && restart
    ;;
  
*)
    echo "Usage: $0 {start|stop|restart|condrestart}"
    RETVAL=1
    ;;
esac
  
exit $RETVAL

# chmod +x /etc/init.d/mysql-proxy

# chmod 0660 /usr/local/mysql-proxy/conf/mysql-proxy.cnf

# service mysql-proxy start

# ps aux | grep mysql-prox[y]

wKiom1Sw7APBGLlPAABNGlf7ct0239.jpg

 

7Atlas高可用【Keepalived】环境安装

http://rpm5.org/files/popt/popt-1.14.tar.gz

# tar xvzf popt-1.14.tar.gz

# cd popt-1.14

# ./configure --prefix=/usr/local

# make && make install

 

http://www.carisma.slowglass.com/~tgr/libnl/files/libnl-3.2.24.tar.gz

# tar xvzf libnl-3.2.24.tar.gz

# cd libnl-3.2.24

# ./configure --prefix=/usr/local

# make && make install

# ln -s /usr/local/include/libnl3/netlink /usr/local/include

# /sbin/ldconfig

 

http://www.keepalived.org/software/keepalived-1.2.10.tar.gz

# tar xvzf keepalived-1.2.10.tar.gz

# cd keepalived-1.2.10

# ./configure --prefix=/usr/local/keepalived

# make && make install

 

# ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin

# ln -s /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig

# ln -s /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d

# chkconfig --add keepalived

 

8Atlas高可用【Keepalived】配置

# mkdir –p /etc/keepalived /data/scripts

 

(1)、主节点配置

# vim /etc/keepalived/keepalived.conf

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
global_defs {
    notification_email {
        lovezym5@126.com
    }
  
    notification_email_from lovezym5@126.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id dbproxy1
}
  
vrrp_script chk_mysql_proxy_health {
    script "/data/scripts/keepalived_check_mysql_proxy.sh"
    interval 1
    weight -2
}
  
vrrp_instance VI_1 {
    state MASTER
    interface eth1
    virtual_router_id 51
    priority 100
    advert_int 1
    smtp_alert
  
    authentication {
        auth_type PASS
        auth_pass 123456
    }
  
    virtual_ipaddress {
        10.209.6.115
    }
  
    track_script {
        chk_mysql_proxy_health
    }
  
    notify_master "/data/scripts/notify.sh master"
    notify_bakcup "/data/scripts/notify.sh backup"
    notify_fault "/data/scripts/notify.sh fault"
}

(2)、备用节点配置

# vim /etc/keepalived/keepalived.conf

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
global_defs {
    notification_email {
        lovezym5@126.com
    }
  
    notification_email_from lovezym5@126.com
    smtp_server 127.0.0.1
    smtp_connect_timeout 30
    router_id dbproxy2
}
  
vrrp_script chk_mysql_proxy_health {
    script "/data/scripts/keepalived_check_mysql_proxy.sh"
    interval 1
    weight -2
}
  
vrrp_instance VI_1 {
    state BACKUP
    interface eth1
    virtual_router_id 51
    priority 90
    advert_int 1
    smtp_alert
  
    authentication {
        auth_type PASS
        auth_pass 123456
    }
  
    virtual_ipaddress {
        10.209.6.115
    }
  
    track_script {
        chk_mysql_proxy_health
    }
  
    notify_master "/data/scripts/notify.sh master"
    notify_bakcup "/data/scripts/notify.sh backup"
    notify_fault "/data/scripts/notify.sh fault"
}

(3)VIP切换通知脚本

# vim /data/scripts/notify.sh

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
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
  
KEEPALIVE_CONF="/etc/keepalived/keepalived.conf"
  
VIP=`grep -A 1 virtual_ipaddress ${KEEPALIVE_CONF} | tail -1 | sed 's/\t//g; s/ //g'`
ETH1_ADDR=`/sbin/ifconfig eth1 | awk '/inet addr:/{print $2}' awk -F: '{print $2}'`
  
MONITOR="/usr/local/oms/agent/alarm/BusMonitorAgent"
TOKEN="ha_monitor"
  
function notify() {
    TITLE="$ETH1_ADDR to be $1: $VIP floating"
    CONTENT="vrrp transition, $ETH1_ADDR changed to be $1"
    ${MONITOR} -c 2 -f ${TOKEN} -t "${TITLE}" -i "${CONTENT}"
}
  
case "$1" in
master)
    notify master
    exit 0
    ;;
  
backup)
    notify backup
    exit 0
    ;;
  
fault)
    notify fault
    exit 0
    ;;
  
*)
    echo 'Usage: `basename $0` {master|backup|fault}'
    exit 1
    ;;
esac

(4)DB中间层进程检查脚本

# vim /data/scripts/keepalived_check_mysql_proxy.sh

1
2
3
4
5
6
7
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
  
if [[ `pgrep mysql-proxy | wc -l` -eq 0 ]]; then
    /sbin/service mysql-proxy start && sleep 5
    [[ -z `pgrep mysql-proxy` ]] && /sbin/service keepalived stop
fi

# chmod +x /data/scripts/*.sh

# service keepalived start

wKioL1Sw72OBWcdcAABQovflyow736.jpg

# ip addr show eth1

wKiom1Sw7r3S6v6_AACfXZvxonQ064.jpg

# ps aux | grep keepalive[d]

wKiom1Sw7tnzsSOAAABqz91YIVo562.jpg

 

==========================================================================================

三、其他设置

==========================================================================================

1Atlas服务监控

# vim /usr/local/mysql-proxy/bin/check_service.sh

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
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
  
[[ $# -ne 3 ]] && echo "$0 端口号 协议类型 服务名" && exit 1
  
SRV_PORT=$1  ## 端口号
SRV_PROT=$2  ## 协议类型
SRV_NAME=$3  ## 服务名
  
MONITOR="/usr/local/oms/agent/alarm/BusMonitorAgent"
TOKEN="ha_monitor"
  
TITLE="${SRV_NAME}服务异常监控"
CONTENT="${SRV_NAME}服务发生异常,已自动拉起!"
  
## 是否已正确扫描
SCAN_FLAG=0
  
function RESTART_SRV_AND_ALERT() 
{
    local CUR_SRV_NAME
     
    [[ $# -ne 1 ]] && exit 1
    CUR_SRV_NAME=$1
     
    TMP_SRV_NAME=`echo ${CUR_SRV_NAME} | tr '[A-Z]' '[a-z]'`
    [[ ! -f /etc/init.d/${TMP_SRV_NAME} ]] && TMP_SRV_NAME="${TMP_SRV_NAME}d"
     
    killall -9 ${TMP_SRV_NAME}
     
    if [[ -z `ps aux | grep ${TMP_SRV_NAME} | grep -v grep` ]]; then
        /sbin/service ${TMP_SRV_NAME} start >/dev/null 2>&1
    fi
     
    ${MONITOR} -c 2 -f ${TOKEN} -t "${TITLE}" -i "${CONTENT}"
    rm -f `pwd`/connect_error.log
}
  
ETH1_ADDR=`/sbin/ifconfig eth1 | awk -F ':' '/inet addr/{print $2}' sed 's/[a-zA-Z ]//g'`
TMP_SRV_PROT=`echo ${SRV_PROT} | tr '[A-Z]' '[a-z]'`
if [[ "${TMP_SRV_PROT}" == "tcp" ]]; then
    PROT_OPT="S"
elif [[ "${TMP_SRV_PROT}" == "udp" ]]; then
    PROT_OPT="U"
else
    echo "未知的协议类型!" && exit 1
fi
  
## 最多扫描3次,成功一次即可,以避免网络抖动而导致误判
for ((i=0; i<3; i++)); do
    RETVAL=`/usr/bin/nmap -n -s${PROT_OPT} -p ${SRV_PORT} ${ETH1_ADDR} | grep open`
    [[ -n "${RETVAL}" ]] && SCAN_FLAG=1;break || sleep 10
done
  
## 1、针对Atlas服务端口不通的情况,也就是服务彻底挂掉
[[ ${SCAN_FLAG} -ne 1 ]] && RESTART_SRV_AND_ALERT ${SRV_NAME}
  
## 2、检查Atlas服务是否正常工作,也就是服务端口正常,但访问异常的情况【高权限DB用户】
mysqladmin -h${ETH1_ADDR} -uhealth_check1 -p123456 --connect-timeout=15 --shutdown-timeout=15 ping
[[ $? -ne 0 ]] && RESTART_SRV_AND_ALERT ${SRV_NAME}
  
## 3、检查Atlas服务是否正常工作,也就是服务端口正常,高权限DB用户访问也正常,但低权限
##    DB用户访问异常的情况【低权限DB用户】
mysqladmin -h${ETH1_ADDR} -uhealth_check2 -p123456 --connect-timeout=15 --shutdown-timeout=15 ping
[[ $? -ne 0 ]] && RESTART_SRV_AND_ALERT ${SRV_NAME}

2Atlas访问日志切割

# vim /data/scripts/cut_and_clear_access_log.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh
# 切割Atlas的访问日志,同时清理15天之前的日志
#
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin
  
## mysql-proxy日志路径
LOGPATH="/usr/local/mysql-proxy/log"
  
[[ `/sbin/ip addr show eth1 | grep inet | wc -l` -eq 2 ]] || exit 
cd ${LOGPATH}
  
## 日志切割
HISTORY_LOG_PATH=`date -d '-1 hour' +"%Y-%m-%d/sql_mysql-proxy_%H.log"`
[[ -d `dirname ${HISTORY_LOG_PATH}` ]] || mkdir -p `dirname ${HISTORY_LOG_PATH}`
cp -a sql_mysql-proxy.log ${HISTORY_LOG_PATH}
  
echo > sql_mysql-proxy.log
  
## 日志清理
HISTORY_LOG_PATH=`date -d '15 days ago' +'%Y-%m-%d'`
[[ -d ${HISTORY_LOG_PATH} ]] && rm -rf ${HISTORY_LOG_PATH}

3crontab内容添加

# touch /var/lock/check_service.lock

# echo 'touch /var/lock/check_service.lock' >> /etc/rc.d/rc.local

# crontab -uroot -e

1
2
* * * * * (flock --timeout=0 /var/lock/check_service.lock /usr/local/mysql-proxy/bin/check_service.sh 3306 tcp mysql-proxy >/dev/null 2>&1)
00 * * * * /data/scripts/cut_and_clear_access_log.sh >/dev/null 2>&1

 

4、平滑设置功能

# mysql -h10.209.6.101 -P3307 -usysadmin -p'admin2356!@()'

wKioL1Sw8S_gXZOuAALgQK7R39c195.jpg

转载于:https://www.cnblogs.com/AmilyWilly/p/5685308.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/284180.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vscode搭建go开发环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装goLang二.配置环境变量三、vscode安装插件四.安装golang依赖五.新建go文件前言 能用golang就用golang..这配置很麻烦 提示&#xff1a;以下是本篇文章正…

【GlobalMapper精品教程】024:批量高效实现多种数据格式互转的方法

globalmapper批量高效实现多种数据格式互转的方法。 文章目录一、批量格式转换二、格式转换形式举例一、批量格式转换 选择原文件类型&#xff1a; 选择文件类型&#xff1a; 在源文件列表中添加需要转换的文件或者文件夹&#xff0c;指定目标文件目录&#xff0c;文件名称和投…

基于 WeihanLi.Npoi 实现excel导入时纯汉字的日期转换

基于 WeihanLi.Npoi 实现excel导入时纯汉字的日期转换Intro前段时间有位小伙伴在 Github 上提了一个 “不能识别纯汉字的日期格式” issue二〇二二年一月一日 格式的日期单元格识别不出来会变成&#xff0c;0001/1/1 0:00:00 如何让它能够识别出来呢&#xff0c;基于 InputForm…

十个模型,总结产品经理沟通方法论

编辑导语&#xff1a;毫不夸张地说沟通占据了产品经理日常工作内容的40%&#xff0c;高效沟通往往能让事情事半功倍。本文作者结合沟通方法与具体沟通情景讲解了如何高效沟通&#xff0c;一起来看看吧&#xff01; 目录 一、为什么要学会沟通 二、沟通模型 1. PREP原则&…

【Globalmapper中文入门到精通系列实验图文教程】(附配套实验数据持续更新)

【Globalmapper中文版入门到精通系列实验图文教程】&#xff08;附配套实验数据持续更新&#xff09; 文章目录一、专栏简介二、文章目录三、数据目录四、传送门一、专栏简介 本专栏为GlobalMapper中文入门实战精品教程&#xff0c;内容主要涉及&#xff1a;Globalmapper23软件…

【GlobalMapper精品教程】025:影像数据集的建立与巧妙使用

GlobalMapper影像数据集类似于金字塔,作用是提高大量影像的加载与显示速度,还可批量进行一系列设置。本文的配套数据为data025.rar。 文章目录 1. 建立影像数据集2. 影像数据集的使用1. 建立影像数据集 (1)点击【文件】→【创建新地图目录】。 (2)选择影像数据集存放路径…

使用xUnit为.net core程序进行单元测试(3)

第1部分: http://www.cnblogs.com/cgzl/p/8283610.html 第2部分: http://www.cnblogs.com/cgzl/p/8287588.html 请使用这个项目作为练习的开始: https://pan.baidu.com/s/1ggcGkGb 测试的分组 打开Game.Tests里面的BossEnemyShould.cs, 为HaveCorrectPower方法添加一个Trait属性…

CDN的强大功能

2019独角兽企业重金招聘Python工程师标准>>> CDN&#xff0c;内容分发网络&#xff0c;除了用作网站加速外&#xff0c;还能够更好的保护网站不被攻击。防护网站不被攻击的功能成就了CDN运行中的主要责任。CDN 防护原理是其主要在于在相关节点中成功的建立动态加速机…

IDEA创建SpringBoot项目无法连接https://start.spring.io(已解决)

错误&#xff1a; 方法&#xff1a; 将&#xff1a;https://start.spring.io 更换为 ​https://start.aliyun.com

2005年AMC8数学竞赛中英文真题典型考题、考点分析和答案解析

今天距离2024年的AMC8美国数学竞赛举办已不足一个月了&#xff0c;赶紧利用周末的时间刷刷真题&#xff0c;查漏补缺吧&#xff01;如果您有任何关于AMC8比赛的任何问题都可以问我&#xff0c;关于题目的解析也可以交流。 今天我们来看看2005年AMC8竞赛的五道典型考题。欢迎您查…

WPF效果第一百九十三篇之登录实现

前面一直在玩耍ListBox(最爱),大周末的就适合在家吹着风扇撸着代码;今天来分享一个很简单实用的登录,来看看最终实现的效果:1、关于软件启动后焦点实现:<Style TargetType"Border"><Style.Triggers><DataTrigger Binding"{Binding IsEmptyAccoun…

IDEA中安装并使用JRebel热部署插件

文章目录 作者简介引言导航热门专栏推荐概述安装JRebel注册JRebel配置JRebel最后小结导航热门专栏推荐作者简介 作者名&#xff1a;编程界明世隐 简介&#xff1a;CSDN博客专家&#xff0c;从事软件开发多年&#xff0c;精通Java、JavaScript&#xff0c;博主也是从零开始一步步…

UWP: 实现 UWP 应用自启动

原文:UWP: 实现 UWP 应用自启动在上一篇文章中&#xff0c;我们实现了使用命令行来启动 UWP 应用&#xff0c;在这一篇文章中&#xff0c;我们会实现 UWP 应用自启用的实现&#xff0c;也即开机后或用户登陆后&#xff0c;应用自己启动。这些特性原来都是 Win32 程序所具备的&a…

选择 GCD 还是 NSTimer ?

我们常常会延迟某件任务的执行&#xff0c;或者让某件任务周期性的执行。然后也会在某些时候需要取消掉之前延迟执行的任务。 延迟操作的方案一般有三种&#xff1a; 1.NSObject的方法&#xff1a; 2.使用NSTimer的方法&#xff1a; 3.使用GCD的方法&#xff1a; 一般情况下&am…

Web框架 性能评测 -- C# 的性能 和 Rust、C++并驾齐驱

自从2021年2月第20轮公布的测试以后&#xff0c;一年半后 的2022年7月19日 发布了 TechEmpower 21轮测试报告&#xff1a;Round 21 results - TechEmpower Framework Benchmarks。Techempower benchmark是包含范围最广泛的web框架性能测试&#xff0c;覆盖了比较典型的使用场景…

【GlobalMapper精品教程】027:路径剖面和和视线工具的使用

文章目录 一、路径剖面简介二、创建剖面图1. 加载DEM2. 创建剖面图3. 计算填挖方3. 保存剖面图一、路径剖面简介 路径剖面视线工具允许您使用加载的高程数据集沿用户指定的路径获取垂直剖面。 要定义生成3D路径剖面所遵循的路径,只需单击鼠标左键选择路径的点,然后石键单击…

QT中VideoProbe的简介和实现

一、遇到问题在Android机上使用QT进行图像处理程序设计的时候&#xff0c;遇到的一个比较明显的问题就是图片采集的问题----摄像头获得是实时的视频&#xff0c;如果我们想从中动态地截获图片&#xff0c;并且转换成Mat的格式&#xff0c;那么仅仅是静态的imagecapturee就无法完…

WinForm(二):WinFrom中Main函数的入参和出参

基本上有独立进程的应用&#xff0c;都是以Main函数作为入口&#xff0c;开始运行的。在C#中&#xff0c;Main函数可以无参无返回值&#xff0c;当然也可以是有string[]参数和int返返回值的。WinFrom也满足这个规则。那么Main作为一个进程的开始函数&#xff0c;那么是谁传这些…

编译源码 JAVA out of memory

转载于:https://www.cnblogs.com/dyufei/p/6612032.html