問題描述:ubuntu服務器為單網卡,設備名稱為eth0,插入一塊網卡后,增加新的網卡設備eth1,后來由于某種原因更換了第二換網卡,重啟以后,網卡設置為eth0和eht2,想將網卡設備eth2改為eth1。
解決方法:終端輸入:vi /etc/udev/rules.d/70-persistent-net.rules
出現以下文件
# This file was automatically generated by the /lib/udev/write_net_rules
# program, run by the persistent-net-generator.rules rules file.
#
# You can modify it, as long as you keep each rule on a single
# line, and change only the value of the NAME= key.
# PCI device 0x8086:0x10de (e1000e)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:25:65:b5:82:ca", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"
# PCI device 0x8086:0x100e (e1000)
#SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:0d:0c:69:af:b8", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"
# PCI device 0x8086:0x100e (e1000)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="00:0e:01:2c:09:9c", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth1"
修改相對的設備名稱,保存退出,重啟網卡服務
目的 在一臺服務器上做主從復制,充分利用CPU資源。下面的文檔首先說明如何在一臺服務器開啟多個MySQL
環境 MySQL 5.5
工具
mysql_install_db
mysqld_multi
配置過程
- 利用mysql_install_db生成數據庫
mysql_install_db --datadir=/var/lib/mysql2 --user=mysql
mysql_install_db --datadir=/var/lib/mysql3 --user=mysql
……
mysql_install_db命令會自動創建datadir目錄。
- 利用mysqld_multi工具生成配置文件
[root@ora01 ~]# mysqld_multi --example
# This is an example of a my.cnf file for mysqld_multi.
# Usually this file is located in home dir ~/.my.cnf or /etc/my.cnf
#
# SOME IMPORTANT NOTES FOLLOW:
#
# 1.COMMON USER
#
# Make sure that the MySQL user, who is stopping the mysqld services, has
# the same password to all MySQL servers being accessed by mysqld_multi.
# This user needs to have the 'Shutdown_priv' -privilege, but for security
# reasons should have no other privileges. It is advised that you create a
# common 'multi_admin' user for all MySQL servers being controlled by
# mysqld_multi. Here is an example how to do it:
#
# GRANT SHUTDOWN ON *.* TO multi_admin@localhost IDENTIFIED BY 'password'
#
# You will need to apply the above to all MySQL servers that are being
# controlled by mysqld_multi. 'multi_admin' will shutdown the servers
# using 'mysqladmin' -binary, when 'mysqld_multi stop' is being called.
#
# 2.PID-FILE
#
# If you are using mysqld_safe to start mysqld, make sure that every
# MySQL server has a separate pid-file. In order to use mysqld_safe
# via mysqld_multi, you need to use two options:
#
# mysqld=/path/to/mysqld_safe
# ledir=/path/to/mysqld-binary/
#
# ledir (library executable directory), is an option that only mysqld_safe
# accepts, so you will get an error if you try to pass it to mysqld directly.
# For this reason you might want to use the above options within [mysqld#]
# group directly.
#
# 3.DATA DIRECTORY
#
# It is NOT advised to run many MySQL servers within the same data directory.
# You can do so, but please make sure to understand and deal with the
# underlying caveats. In short they are:
# - Speed penalty
# - Risk of table/data corruption
# - Data synchronising problems between the running servers
# - Heavily media (disk) bound
# - Relies on the system (external) file locking
# - Is not applicable with all table types. (Such as InnoDB)
# Trying so will end up with undesirable results.
#
# 4.TCP/IP Port
#
# Every server requires one and it must be unique.
#
# 5.[mysqld#] Groups
#
# In the example below the first and the fifth mysqld group was
# intentionally left out. You may have 'gaps' in the config file. This
# gives you more flexibility.
#
# 6.MySQL Server User
#
# You can pass the user=... option inside [mysqld#] groups. This
# can be very handy in some cases, but then you need to run mysqld_multi
# as UNIX root.
#
# 7.A Start-up Manage Script for mysqld_multi
#
# In the recent MySQL distributions you can find a file called
# mysqld_multi.server.sh. It is a wrapper for mysqld_multi. This can
# be used to start and stop multiple servers during boot and shutdown.
#
# You can place the file in /etc/init.d/mysqld_multi.server.sh and
# make the needed symbolic links to it from various run levels
# (as per Linux/Unix standard). You may even replace the
# /etc/init.d/mysql.server script with it.
#
# Before using, you must create a my.cnf file either in /usr/my.cnf
# or /root/.my.cnf and add the [mysqld_multi] and [mysqld#] groups.
#
# The script can be found from support-files/mysqld_multi.server.sh
# in MySQL distribution. (Verify the script before using)
#
上面是mysqld_multi工具的簡單說明,下面是根據實際情況,修改的配置文件。為方便測試,將多實例的配置文件命名為
mysqld_multi.cnf。未指定的其他MySQL參數,將使用默認的。
[mysqld_multi]
mysqld = /usr/bin/mysqld_safe
mysqladmin = /usr/bin/mysqladmin
#user = multi_admin
#password = my_password
[mysqld2]
socket = /var/lib/mysql2/mysql2.sock
port = 3307
#pid-file = /var/lib/mysql2/hostname.pid2
datadir = /var/lib/mysql2
#language = /usr/share/mysql/mysql/english
user = mysql
[mysqld3]
socket = /var/lib/mysql3/mysql3.sock
port = 3308
#pid-file = /var/lib/mysql3/hostname.pid3
datadir = /var/lib/mysql3
#language = /usr/share/mysql/mysql/swedish
user = mysql
注:我做測試的時候,把pid-file和language選項注釋掉了。
- 啟動
# mysqld_multi --defaults-extra-file=/etc/mysqld_multi.cnf report
Reporting MySQL servers
MySQL server from group: mysqld2 is not running
MySQL server from group: mysqld3 is not running
# mysqld_multi --defaults-extra-file=/etc/mysqld_multi.cnf start
等一會兒…………,注意start后面跟具體的數字,比如start 2,則單獨開啟mysqld2這個實例。
# mysqld_multi --defaults-extra-file=/etc/mysqld_multi.cnf report
Reporting MySQL servers
MySQL server from group: mysqld2 is running
MySQL server from group: mysqld3 is running
[root@ora01 mysql2]# netstat -tunlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 3808/dnsmasq
tcp 0 0 :::3307 :::* LISTEN 24335/mysqld
tcp 0 0 :::3308 :::* LISTEN 24241/mysqld
tcp 0 0 :::22 :::* LISTEN 3537/sshd
udp 0 0 192.168.122.1:53 0.0.0.0:* 3808/dnsmasq
udp 0 0 0.0.0.0:67 0.0.0.0:* 3808/dnsmasq
連接
mysql -uroot -p -h127.0.0.1 -P3307
- 測試
如果--defaults-extra-file選項指定的配置文件中,未具體設置路徑socket,則會用mysql默認的路徑。
mysql> show variables like 'socket';
+---------------+---------------------------+
| Variable_name | Value |
+---------------+---------------------------+
| socket | /var/lib/mysql/mysql.sock |
+---------------+---------------------------+
1 row in set (0.00 sec)
但是pid文件,會自動在數據目錄內生成
mysql> show variables like '%pid%';
+---------------+---------------------------------+
| Variable_name | Value |
+---------------+---------------------------------+
| pid_file | /var/lib/mysql2/ora01.dh.cn.pid |
+---------------+---------------------------------+
1 row in set (0.00 sec)
Mysql作為目前世界上使用最廣泛的免費數據庫,相信所有從事系統運維的工程師都一定接觸過。但在實際的生產環境中,由單臺Mysql作為獨立的數據庫是完全不能滿足實際需求的,無論是在安全性,高可用性以及高并發等各個方面。
因此,一般來說都是通過 主從復制(Master-Slave)的方式來同步數據,再通過讀寫分離(MySQL-Proxy)來提升數據庫的并發負載能力 這樣的方案來進行部署與實施的。
如下圖所示:
下面是我在實際工作過程中所整理的筆記,在此分享出來,以供大家參考。
一、MySQL的安裝與配置
具體的安裝過程,建議參考我的這一篇文章:http://heylinux.com/archives/993.html
值得一提的是,我的安裝過程都是源碼包編譯安裝的,并且所有的配置與數據等都統一規劃到了/opt/mysql目錄中,因此在一臺服務器上安裝完成以后,可以將整個mysql目錄打包,然后傳到其它服務器上解包,便可立即使用。
二、MySQL主從復制
場景描述:
主數據庫服務器:192.168.10.130,MySQL已經安裝,并且無應用數據。
從數據庫服務器:192.168.10.131,MySQL已經安裝,并且無應用數據。
2.1 主服務器上進行的操作
啟動mysql服務
/opt/mysql/init.d/mysql start
通過命令行登錄管理MySQL服務器
/opt/mysql/bin/mysql -uroot -p'new-password'
授權給從數據庫服務器192.168.10.131
mysql> GRANT REPLICATION SLAVE ON *.* to 'rep1'@'192.168.10.131' identified by ‘password’;
查詢主數據庫狀態
Mysql> show master status;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000005 | 261 | | |
+------------------+----------+--------------+------------------+
記錄下 FILE 及 Position 的值,在后面進行從服務器操作的時候需要用到。
2.2 配置從服務器
修改從服務器的配置文件/opt/mysql/etc/my.cnf
將 server-id = 1修改為 server-id = 10,并確保這個ID沒有被別的MySQL服務所使用。
啟動mysql服務
/opt/mysql/init.d/mysql start
通過命令行登錄管理MySQL服務器
/opt/mysql/bin/mysql -uroot -p'new-password'
執行同步SQL語句
mysql> change master to
master_host=’192.168.10.130’,
master_user=’rep1’,
master_password=’password’,
master_log_file=’mysql-bin.000005’,
master_log_pos=261;
正確執行后啟動Slave同步進程
mysql> start slave;
主從同步檢查
mysql> show slave status\G
==============================================
**************** 1. row *******************
Slave_IO_State:
Master_Host: 192.168.10.130
Master_User: rep1
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000005
Read_Master_Log_Pos: 415
Relay_Log_File: localhost-relay-bin.000008
Relay_Log_Pos: 561
Relay_Master_Log_File: mysql-bin.000005
Slave_IO_Running: YES
Slave_SQL_Running: YES
Replicate_Do_DB:
……………省略若干……………
Master_Server_Id: 1
1 row in set (0.01 sec)
==============================================
其中Slave_IO_Running 與 Slave_SQL_Running 的值都必須為YES,才表明狀態正常。
如果主服務器已經存在應用數據,則在進行主從復制時,需要做以下處理:
(1)主數據庫進行鎖表操作,不讓數據再進行寫入動作
mysql> FLUSH TABLES WITH READ LOCK;
(2)查看主數據庫狀態
mysql> show master status;
(3)記錄下 FILE 及 Position 的值。
將主服務器的數據文件(整個/opt/mysql/data目錄)復制到從服務器,建議通過tar歸檔壓縮后再傳到從服務器解壓。
(4)取消主數據庫鎖定
mysql> UNLOCK TABLES;
2.3 驗證主從復制效果
主服務器上的操作
在主服務器上創建數據庫first_db
mysql> create database first_db;
Query Ok, 1 row affected (0.01 sec)
在主服務器上創建表first_tb
mysql> create table first_tb(id int(3),name char(10));
Query Ok, 1 row affected (0.00 sec)
在主服務器上的表first_tb中插入記錄
mysql> insert into first_tb values (001,’myself’);
Query Ok, 1 row affected (0.00 sec)
在從服務器上查看
mysql> show databases;
=============================
+--------------------+
| Database |
+--------------------+
| information_schema |
| first_db |
| mysql |
| performance_schema |
| test |
+--------------------+
5 rows in set (0.01 sec)
=============================
數據庫first_db已經自動生成
mysql> use first_db
Database chaged
mysql> show tables;
=============================
+--------------------+
| Tables_in_first_db |
+--------------------+
| first_tb |
+--------------------+
1 row in set (0.02 sec)
=============================
數據庫表first_tb也已經自動創建
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
1 rows in set (0.00 sec)
=============================
記錄也已經存在
由此,整個MySQL主從復制的過程就完成了,接下來,我們進行MySQL讀寫分離的安裝與配置。
三、MySQL讀寫分離
場景描述:
數據庫Master主服務器:192.168.10.130
數據庫Slave從服務器:192.168.10.131
MySQL-Proxy調度服務器:192.168.10.132
以下操作,均是在192.168.10.132即MySQL-Proxy調度服務器 上進行的。
3.1 MySQL的安裝與配置
具體的安裝過程與上文相同。
3.2 檢查系統所需軟件包
通過 rpm -qa | grep name 的方式驗證以下軟件包是否已全部安裝。
gcc* gcc-c++* autoconf* automake* zlib* libxml* ncurses-devel* libmcrypt* libtool* flex* pkgconfig*
libevent* glib*
若缺少相關的軟件包,可通過yum -y install方式在線安裝,或直接從系統安裝光盤中找到并通過rpm -ivh方式安裝。
3.3 編譯安裝lua
MySQL-Proxy的讀寫分離主要是通過rw-splitting.lua腳本實現的,因此需要安裝lua。
lua可通過以下方式獲得
從http://www.lua.org/download.html下載源碼包
從rpm.pbone.net搜索相關的rpm包
download.fedora.redhat.com/pub/fedora/epel/5/i386/lua-5.1.4-4.el5.i386.rpm
download.fedora.redhat.com/pub/fedora/epel/5/x86_64/lua-5.1.4-4.el5.x86_64.rpm
這里我們建議采用源碼包進行安裝
cd /opt/install
wget http://www.lua.org/ftp/lua-5.1.4.tar.gz
tar zvfx lua-5.1.4.tar.gz
cd lua-5.1.4
vi src/Makefile
在 CFLAGS= -O2 -Wall $(MYCFLAGS) 這一行記錄里加上-fPIC,更改為 CFLAGS= -O2 -Wall -fPIC $(MYCFLAGS) 來避免編譯過程中出現錯誤。
make linux
make install
cp etc/lua.pc /usr/lib/pkgconfig/
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/lib/pkgconfig
3.4 安裝配置MySQL-Proxy
MySQL-Proxy可通過以下網址獲得:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/
推薦采用已經編譯好的二進制版本,因為采用源碼包進行編譯時,最新版的MySQL-Proxy對automake,glib以及libevent的版本都有很高的要求,而這些軟件包都是系統的基礎套件,不建議強行進行更新。
并且這些已經編譯好的二進制版本在解壓后都在統一的目錄內,因此建議選擇以下版本:
32位RHEL5平臺:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
64位RHEL5平臺:
http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-64bit.tar.gz
測試平臺為RHEL5 32位,因此選擇32位的軟件包
wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
tar xzvf mysql-proxy-0.8.1-linux-rhel5-x86-32bit.tar.gz
mv mysql-proxy-0.8.1-linux-rhel5-x86-32bit /opt/mysql-proxy
創建mysql-proxy服務管理腳本
mkdir /opt/mysql-proxy/init.d/
vim mysql-proxy
02 #
03 # mysql-proxy This script starts and stops the mysql-proxy daemon
04 #
05 # chkconfig: - 78 30
06 # processname: mysql-proxy
07 # description: mysql-proxy is a proxy daemon to mysql
08
09 # Source function library.
10 . /etc/rc.d/init.d/functions
11
12 #PROXY_PATH=/usr/local/bin
13 PROXY_PATH=/opt/mysql-proxy/bin
14
15 prog="mysql-proxy"
16
17 # Source networking configuration.
18 . /etc/sysconfig/network
19
20 # Check that networking is up.
21 [ ${NETWORKING} = "no" ] && exit 0
22
23 # Set default mysql-proxy configuration.
24 #PROXY_OPTIONS="--daemon"
25 PROXY_OPTIONS="--admin-username=root --admin-password=password --proxy-read-only-backend-addresses=192.168.10.131:3306 --proxy-backend-addresses=192.168.10.130:3306 --admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua --proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua"
26 PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid
27
28 # Source mysql-proxy configuration.
29 if [ -f /etc/sysconfig/mysql-proxy ]; then
30 . /etc/sysconfig/mysql-proxy
31 fi
32
33 PATH=$PATH:/usr/bin:/usr/local/bin:$PROXY_PATH
34
35 # By default it's all good
36 RETVAL=0
37
38 # See how we were called.
39 case "$1" in
40 start)
41 # Start daemon.
42 echo -n $"Starting $prog: "
43 $NICELEVEL $PROXY_PATH/mysql-proxy $PROXY_OPTIONS --daemon --pid-file=$PROXY_PID --user=mysql --log-level=warning --log-file=/opt/mysql-proxy/log/mysql-proxy.log
44 RETVAL=$?
45 echo
46 if [ $RETVAL = 0 ]; then
47 touch /var/lock/subsys/mysql-proxy
48 fi
49 ;;
50 stop)
51 # Stop daemons.
52 echo -n $"Stopping $prog: "
53 killproc $prog
54 RETVAL=$?
55 echo
56 if [ $RETVAL = 0 ]; then
57 rm -f /var/lock/subsys/mysql-proxy
58 rm -f $PROXY_PID
59 fi
60 ;;
61 restart)
62 $0 stop
63 sleep 3
64 $0 start
65 ;;
66 condrestart)
67 [ -e /var/lock/subsys/mysql-proxy ] && $0 restart
68 ;;
69 status)
70 status mysql-proxy
71 RETVAL=$?
72 ;;
73 *)
74 echo "Usage: $0 {start|stop|restart|status|condrestart}"
75 RETVAL=1
76 ;;
77 esac
78
79 exit $RETVAL
==============================================
PROXY_PATH=/opt/mysql-proxy/bin //定義mysql-proxy服務二進制文件路徑
PROXY_OPTIONS="--admin-username=root \ //定義內部管理服務器賬號
--admin-password=password \ //定義內部管理服務器密碼
--proxy-read-only-backend-addresses=192.168.10.131:3306 \ //定義后端只讀從服務器地址
--proxy-backend-addresses=192.168.10.130:3306 \ //定義后端主服務器地址
--admin-lua-script=/opt/mysql-proxy/lib/mysql-proxy/lua/admin.lua \ //定義lua管理腳本路徑
--proxy-lua-script=/opt/mysql-proxy/scripts/rw-splitting.lua" \ //定義lua讀寫分離腳本路徑
PROXY_PID=/opt/mysql-proxy/run/mysql-proxy.pid //定義mysql-proxy PID文件路徑
$NICELEVEL $PROXY_PATH/mysql-proxy $PROXY_OPTIONS \
--daemon \ //定義以守護進程模式啟動
--keepalive \ //使進程在異常關閉后能夠自動恢復
--pid-file=$PROXY_PID \ //定義mysql-proxy PID文件路徑
--user=mysql \ //以mysql用戶身份啟動服務
--log-level=warning \ //定義log日志級別,由高到低分別有(error|warning|info|message|debug)
--log-file=/opt/mysql-proxy/log/mysql-proxy.log //定義log日志文件路徑
==============================================
cp mysql-proxy /opt/mysql-proxy/init.d/
chmod +x /opt/mysql-proxy/init.d/mysql-proxy
mkdir /opt/mysql-proxy/run
mkdir /opt/mysql-proxy/log
mkdir /opt/mysql-proxy/scripts
配置并使用rw-splitting.lua讀寫分離腳本
最新的腳本我們可以從最新的mysql-proxy源碼包中獲取
cd /opt/install
wget http://mysql.cdpa.nsysu.edu.tw/Downloads/MySQL-Proxy/mysql-proxy-0.8.1.tar.gz
tar xzvf mysql-proxy-0.8.1.tar.gz
cd mysql-proxy-0.8.1
cp lib/rw-splitting.lua /opt/mysql-proxy/scripts
修改讀寫分離腳本rw-splitting.lua
修改默認連接,進行快速測試,不修改的話要達到連接數為4時才啟用讀寫分離
vim /opt/mysql-proxy/scripts/rw-splitting.lua
=============================
-- connection pool
if not proxy.global.config.rwsplit then
proxy.global.config.rwsplit = {
min_idle_connections = 1, //默認為4
max_idle_connections = 1, //默認為8
is_debug = false
}
end
=============================
修改完成后,啟動mysql-proxy
/opt/mysql-proxy/init.d/mysql-proxy start
3.5 測試讀寫分離效果
創建用于讀寫分離的數據庫連接用戶
登陸主數據庫服務器192.168.10.130,通過命令行登錄管理MySQL服務器
/opt/mysql/bin/mysql -uroot -p'new-password'
mysql> GRANT ALL ON *.* TO 'proxy1'@'192.168.10.132' IDENTIFIED BY 'password';
由于我們配置了主從復制功能,因此從數據庫服務器192.168.10.131上已經同步了此操作。
為了清晰的看到讀寫分離的效果,需要暫時關閉MySQL主從復制功能
登陸從數據庫服務器192.168.10.131,通過命令行登錄管理MySQL服務器
/opt/mysql/bin/mysql -uroot -p'new-password'
關閉Slave同步進程
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
連接MySQL-Proxy
/opt/mysql/bin/mysql -uproxy1 -p'password' -P4040 -h192.168.10.132
登陸成功后,在first_db數據的first_tb表中插入兩條記錄
mysql> use first_db;
Database changed
mysql> insert into first_tb values (007,’first’);
Query Ok, 1 row affected (0.00 sec)
mysql> insert into first_tb values (110,’second’);
Query Ok, 1 row affected (0.00 sec)
查詢記錄
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
1 rows in set (0.00 sec)
=============================
通過讀操作并沒有看到新記錄
mysql> quit
退出MySQL-Proxy
下面,分別登陸到主從數據庫服務器,對比記錄信息
首先,檢查主數據庫服務器
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
| 007 | first |
+------+------+
| 110 | second |
+------+------+
3 rows in set (0.00 sec)
=============================
兩條新記錄都已經存在
然后,檢查從數據庫服務器
mysql> select * from first_tb;
=============================
+------+------+
| id | name |
+------+------+
| 1 | myself |
+------+------+
1 rows in set (0.00 sec)
=============================
沒有新記錄存在
由此驗證,我們已經實現了MySQL讀寫分離,目前所有的寫操作都全部在Master主服務器上,用來避免數據的不同步;
另外,所有的讀操作都分攤給了其它各個Slave從服務器上,用來分擔數據庫壓力。
經驗分享:
1.當MySQL主從復制在 show slave status\G 時出現Slave_IO_Running或Slave_SQL_Running 的值不為YES時,需要首先通過 stop slave 來停止從服務器,然后再執行一次本文 2.1與2.2 章節中的步驟即可恢復,但如果想盡可能的同步更多的數據,可以在Slave上將master_log_pos節點的值在之前同步失效的值的基礎上增大一 些,然后反復測試,直到同步OK。因為MySQL主從復制的原理其實就是從服務器讀取主服務器的binlog,然后根據binlog的記錄來更新數據庫。
2.MySQL-Proxy的rw-splitting.lua腳本在網上有很多版本,但是最準確無誤的版本仍然是源碼包中所附帶的lib/rw-splitting.lua腳本,如果有lua腳本編程基礎的話,可以在這個腳本的基礎上再進行優化;
3.MySQL-Proxy實際上非常不穩定,在高并發或有錯誤連接的情況下,進程很容易自動關閉,因此打開--keepalive參數讓進程自動 恢復是個比較好的辦法,但還是不能從根本上解決問題,因此通常最穩妥的做法是在每個從服務器上安裝一個MySQL-Proxy供自身使用,雖然比較低效但 卻能保證穩定性;
4.一主多從的架構并不是最好的架構,通常比較優的做法是通過程序代碼和中間件等方面,來規劃,比如設置對表數據的自增id值差異增長等方式來實現兩個或多個主服務器,但一定要注意保證好這些主服務器數據的完整性,否則效果會比多個一主多從的架構還要差;
5.MySQL-Cluster 的穩定性也不是太好;
6.Amoeba for MySQL 是一款優秀的中間件軟件,同樣可以實現讀寫分離,負載均衡等功能,并且穩定性要大大超過MySQL-Proxy,建議大家用來替代MySQL-Proxy,甚至MySQL-Cluster。
原文出處:http://heylinux.com/archives/1004.html
google的開源項目值得我們一用的,這些項目很有意義,甚至可以直接用在我們自己的工作上!學習編程的的一個比較好的方式就是閱讀優秀項目的源代碼,從而能夠了解作者的方法、思路、技巧,另外閱讀源代碼對于一些朋友是枯燥乏味的,這是就可以看看項目的readme,找到項目的閃光點,我們不做開拓者那我們就做實踐者和使用者,呵呵,下面是這些項目的列表,在這里存檔,已備今后查閱之用
文本文件處理:
Google CRUSH (Custom Reporting Utilities for SHell)
CRUSH是為命令行或shell scripts處理特定文字數據而制作的一系列工具,這里有指南。
C++庫和源代碼:
一個開源的多平臺崩潰報告系統。
Gflags是一個命令行標記的處理庫,它可以替代“getopt()”,其內置對C++的支持比如string。指南在此。
Google Glog Glog庫可執行應用級的登陸,提供基于C++式的登陸API,可用于Linux、BSD和Windows。指南見此。
這個工具可讓開發創建更強大的應用程序,特別是那些用C++模版開發的多線程應用程序,包括TCMalloc, heap-checker, heap-profiler 和cpu-profiler。指南見此還有這里。
非常節省內存的hash-map。指南見此。
Omaha,也就是Google Update,它可以保證你的軟件隨時升級到最新版本,目前很多Windows下的Google軟件都是用Omaha升級的,包括Google Chrome和Google Earth,當然你也可以用于自己的應用程序。指南看這里還有這里。
Protocol Buffers是一種可擴展編碼序列數據的方式,Google在幾乎所有內部RPC協議和文件格式都使用了Protocol Buffers。指南見此。它可以用于很多語言而且被一些IDE所支持,比如NetBeans。
互聯網:
Google Code Pretiffy 這是一個Javascript模塊和CSS文件,它可以讓HTML頁面里的部分源碼高亮顯示,支持C/C++, Java, Python, Ruby, PHP, VisualBasic, AWK, Bash, SQL, HTML, XML, CSS, JavaScript, Makefiles和部分Perl,不支持Smalltalk和所有的CAML。例子見此。
SpriteMe – easy “CSS spirtes” SpriteMe使你可以更輕松的創造CSS Sprites(俗稱雪碧……)就是把網站要用到的圖片都堆在一張圖片里,用CSS控制調用哪個區域。它有一個自己的官網在這里。
Reducisaurus是一個壓縮CSS和JS文件的網絡服務,基于YUI壓縮算法,運行于App Engine。
JaikuEngine是一個運行于App Engine的微博系統,由jaiku.com運營。要查看移動客戶端的源碼可以看這里,這里還有介紹。
Selector Shell是一個基于瀏覽器的測試工具,它可以讓你看到CSS在不同瀏覽器里的樣式,用Javascript寫的,你可以在這里測試。
Google Feed Server是一個開源Atom發布協議服務,基于Apache Abdera框架,允許開發者快速為當前數據源(比如數據庫)配置feed。指南見這里和這里。
Melange, the Spice of Creation
這個項目的目標是創建出一個適合開源貢獻流程的框架,比如Google Summer of Code TM (GSoC)項目。使用這個框架你就可以用Google App Engine來運行Google Summer of Code項目,和其它類似項目比如Google Highly Open Participation TM Contest和GHOP。指南見此。
它可以查找最快的DNS服務器給你的電腦用,在Mac OS X、Windows和UNIX系統下都有命令行也有用戶界面可以幫你測試,這是Google工程師用20%自由時間寫出來的。
一個半自動化的大型被動網絡應用安全審查工具,專為精確的探測而優化,文檔在此。
Top Draw是一個圖形生成程序,使用簡單的文字腳本,基于JavaScript編程語言,Top Draw可以創造出非常復雜和有趣的圖形。支持Mac OS 10.5以上系統,使用XCode開發。
開源的EtherPad,這是一個基于網絡的實時合作文檔編輯器,這個項目主要是為了演示代碼而開發,幫助那些想在自己服務器部署Etherpad的人使用,這里有如何安裝的指南。EtherPad使用JavaScript、Java和Comet服務器來建造實時協作服務。
Chromium是開源版的Chrome瀏覽器,Chromium的目標是建立一個新一代的強大網絡應用程序,它與Chrome有很多不同之處。這里有指導如何在Linux上編譯Chromium。
V8 Google’s open source JavaScript engine V8是Google的開源JavaScript引擎,用C++寫成,用于Chrome瀏覽器之上。V8使用ECMAScript的ECMA-262第三版可運行于Windows XP、Vista、Mac OS 10.5和使用IA-32或ARM處理器的Linux。V8可獨立運行也可嵌入到任何C++程序里使用,這里有指南。
Chromium OS是開源版的Chrome OS操作系統,提供快速、簡單而安全的網絡體驗,源碼在此。
Android是第一個免費、開源而且可完全自定義的移動平臺,提供完整的堆棧:一個操作系統、中間件和重要的一用應用,它包含豐富的API可以讓第三方開發者開發出強大的應用程序。
MySQL工具:
Google MySQL Tools
各種管理、維護和改進MySQL數據庫性能的工具,由Google編寫,包括:
- mypgrep.py:一個類似pgrep的工具來管理MySQL連接
- compact_innodb.py:可導出和重載所有表格的密集型innodb數據文件
mMAIM的目標是對MySQL的監控和分析更簡單,且可以和任何環境整合使用。它可顯示主/從同步狀態,一些性能狀態,可以返回大量“show”命令的狀態等等。
其它:
Stressful Application Test (stressapptest)
Stressful Application Test試圖讓來自處理器和I/O到內存的數據盡量隨機化,以創造出模擬現實的環境來測試現在的硬件設備是否穩定,Google就在使用它,現在是Apache 2.0許可,這里有介紹、安裝向導和指南。
它用于診斷并解決客戶端到郵件服務器的連接問題。
Openduckbill是一個Linux下簡單的命令行備份工具,可用于監視文件/目錄在有變化后是否標記為備份,并傳輸這些變化到本地備份目錄、遠程NFS導出分卷或是用rsync命令導出到遠程SSH服務器。見安裝向導。
ZXing(發音類似Zebra crossing)是Java的開源多格式1D/2D條碼圖像處理庫,目的是使用內置在手機上的攝像頭拍照并對條碼進行解碼,而不必與服務器通訊,它被用于Android系統。這里有向導和支持的設備列表。 Tesseract OCR Engine
Tesseract OCR引擎是1995年UNLV Accuracy測試的前三名之一,在1995和2006年之間它的進展不大,但依然是當前精度最高的OCR引擎。這個源碼可讀取二進制、灰階或彩色圖片并輸出文字,內置一個TIFF閱讀器可讀取非壓縮的TIFF文件,增加libtiff后也可讀取壓縮圖片。指南和問答。
Neatx是一個開源NX服務,類似NoMachine公司商業的NX服務。NX協議比VNX更強大,它們的區別主要在:
- NX是X11客戶端所以不會發送位圖
- NX可兼容X、VNC和Windows版的Remote Desktop
- NX可緩存數據
- NX安裝簡單
另外一個可選的項目可以看看Google的FreeNx。
它是這個文件的代碼,這是一個SVM的“支持所有核心”的版本,可多機并行運行,實例見此。
Google開發的新編程語言,谷奧有報道。
The Google Collections Library for Java
這是一系列與Java 5以及更高版本有關的庫,Google花錢給買過來了。
每個主流的開源項目都有它自己的向導形式,比如一系列的演示代碼。如果這些代碼都按照“Style”的形式來演示,會更友好。
從2000年開始從事軟件測試,逐漸形成自己的軟件測試思想,而第一次比較清晰呈現自己的測試的思想是2007年出版的《全程軟件測試》,正如前言所敘:“從項目啟動的第一天起到需求和設計的評審階段,從后期的缺陷修正到產品維護——在整個軟件生命周期中,開發人員和測試人員愉快地合作、共同努力,將軟件產品的開發效率和質量推到一個新的高度。”,這些思想在測試管理工作的體現就是讓測試人員更早地融入項目中,更主動、更密切地與開發人員協作,與項目相關利益者合作,確保項目按時按質地完成,即:
- 測試人員越快地發現缺陷,項目越能盡早結束;
- 測試人員盡可能多地發現Bug,遺留在產品中的Bug就會越少,產品的質量就會越高;
- 測試人員和自己(開發人員)的工作都是為了相同的目標——按時、高質量地發布產品;
而此后和業界的測試人員、開發人員交流更多,思考得更多,在測試上的思想更清晰,于是在2012年9月5日在新浪微博(http://weibo.com/1652927771/yArIqoCKW )上發表了自己的個人軟件測試宣言:
宣言發布后,得到不少網友的肯定。最給力的,要屬@培根芝士牛蛙堡:感覺總結的太到位,can’t agree more了,最近在看《軟測之魂》,很多觀點都是異曲同工啊,雖說就簡單四句話,但是每一句話展開去都能寫一本書。還有@讓測試飛起來:又見右下八卦圖亮點。每當遇到左、右難以分辯時就想到它,并以此為基點,償試思考再進一步,思絲多而力爭不亂。分割線不是直的喲,似乎體現開發中有測試(調試),測試中有開發,而又不完全符合對立統一。
當然,也有不同聲音,例如:@胡爭輝:首先應當強調產品工程,然后在產品工程中強調需求工程,其次在需求工程的基礎上強調品質保證工程。脫離的產品工程的品質保證工程是無本之木,無源之水。這實際和我宣言沒有關系,這里絲毫沒有否定產品工程,也沒有否定需求工程,實際第一句“更鼓勵事先確定驗證的標準并以此來驅動開發”就是強調需求的重要性。需求是軟件開發的源泉,而這里關注點是“軟件測試”,比較局限于測試自身的內涵和測試與開發的關系。如果拓展出去,我需要發表我的“軟件工程宣言”了。
還有其它有意義的補充:
- @程序員鄒欣:值得開發,測試,項目管理人員思考。 認可內部測試的重要性, 但更重視產品對用戶的長期影響;
- @王立杰-WangLijie:認可測試對質量的改善,但更提倡質量是內建的;
- 與@Testin-Daiyibin 討論之后,增加一條,即:認可自動化測試的價值,但更提倡測試分析和設計的創造性和系統性。
那下面回歸主題,就我自己的軟件測試宣言,逐條分別進行說明,并簡要闡述如何將它們應用于實際的軟件開發工作之中。
1. 認可測試的價值,但更鼓勵事先確定驗證的標準并以此來驅動開發
首先認識測試的價值,測試是質量保證的重要手段之一,正如在我的博客中所討論的“軟件測試究竟發揮什么作用?”:
- 對產品質量完成全面的評估,為軟件產品發布(如驗收測試)、軟件系統部署(如性能規劃測試)、軟件產品鑒定(第三方獨立測試)委托方和被委托方糾紛仲裁(第三方獨立測試)和其它決策提供信息;
- 通過持續的測試(包括需求評審、設計評審、代碼評審等)可以對產品質量提供持續的、快速的反饋,從而在整個開發過程中不斷地、及時地改進產品的質量,并減少各種返工,降低軟件開發的成本;
- 通過測試發現所要交付產品的缺陷,特別是盡可能地發現各種嚴重的缺陷,降低或消除產品質量風險,提高客戶的滿意度,擴大市場份額,提高客戶的忠誠度。
- 通過對缺陷進行分析,找出缺陷發生的根本原因(軟件過程中的問題,包括錯誤的行為方式)或總結出軟件產品的缺陷模式,避免將來犯同樣的錯誤或產生類似的產品問題,達到缺陷預防的目的
所以軟件測試的價值不容忽視,但是我們一直提倡“質量更是內建的(Quality is built in)”,軟件產品的質量是在需求分析、功能設計、系統設計、編程等過程中逐漸形成的,事先清楚客戶的需求,明確軟件產品的驗收標準,基于這些需求和驗收標準來開發,開發人員清楚自己要實現的目標、清楚待實現系統的要求和限制,在工作中能夠第一次將事情做對,或者說,第一次將事情做對的可能性會顯著提高,在需求、設計、代碼中引入的缺陷就會大大減少。理解這一點并不難,如果還是不能很好理解,就看看磚墻是如何砌成的?是先拉上水準線再墻砌,還是墻砌好之后再拉線來檢測?
而且,對測試人員說,全生命周期的測試依據也明確了,能夠及時提供明確的質量反饋,測試與開發之間也不容易引起的爭議,測試效率也會明顯改善。本句宣言和驗收測試驅動開發(Acceptance Test Driven Development, ATDD)擁有共同的思想和內涵,無論是在傳統研發流程中還是在敏捷過程中,都可以嘗試這樣去做。雖然在某些項目上需求不夠清楚、或需求變化比較大,但也不能成為“自己懶于徹底分析需求”的借口,能明確60%的需求,也不能做到30%就停下來了。 否則,無論是“迭代”、還是“重構”,都是“返工”美化之后的代名詞。難道企業希望自己團隊常犯錯誤而不斷修正嗎?
2. 認可專業測試人員的不可替代的價值,但更鼓勵開發人員做好測試
上一句已經回答了測試的價值,而這里是討論測試工作由誰來做?測試有價值,但不一定由專職的測試人員來做,正如一些公司(如facebook)沒有專職的測試人員,軟件產品的研發也能正常開展。也許在某些初創的企業、特殊商業模式的軟件服務、某些移動終端的且免費的產品等可以不要專職的測試人員,但對大多數軟件產品、軟件企業還是需要專業的測試人員,因為系統復雜、業務更復雜的原因,更可能是測試本身更需要方法和技術。當我們不能簡單地掌握軟件產品(系統)的測試方法和技術,就需要專業的測試人員。即使在相對低端的制造業,掌握其工作技能不是很難,但熟練工人的工作效率也是初級操作工的幾倍。而軟件測試所涉及的方法、技術與工具,從功能測試到性能測試、安全性測試、兼容測試、可達性測試到可靠性測試等,從測試計劃、測試分析與設計到測試結果分析,從等價類劃分、判定表、因果圖到基于模型的測試、自動化測試等,已形成一個龐大的體系,沒有專注,很難做得精,不能精通測試,又如何有良好的測試效率呢?沒有專業的測試技能,測試的風險也很大。這些內容,在我的另一篇博客“專業測試團隊會消亡還是新生”進行了充分討論。正如網友在本博客上還評論說:“如果沒有專業的測試團隊,那么天上的飛機一定會無緣無故地掉下來,ICU里面的心電監護儀罷工也不會是新聞,核彈未接收到真正的發射命令而自行啟動也不是沒有可能,這個世界將不再是安全的世界。”
為什么更鼓勵開發人員做好測試呢?這是因為:
- 單元測試是基礎,沒有單元的質量,如何有系統的質量?而單元測試主要是在代碼層次上展開,而且和編程交織在一起,編程和單元測試難以分開處理,所以單元測試最好由開發人員來做,確保良好的工作效率與工作質量;
- 如果開發了一個測試工具,先讓開發人員用起來好,還是只讓測試人員用?無論是功能測試工具還是性能測試、安全性測試工具,都可以讓開發人員先用,測試的效率會更高。一邊構建、一邊驗證,更能及時發現問題,能更快調試和修正問題,將問題消除在萌芽之中。這也就是為什么我們一直提倡持續構建、持續測試;
- 如果開發人員做更多測試,就更能認識到自己的問題,了解問題產生的原因,將來在設計、編程中更好地避免同樣問題的發生,預防缺陷效果更好。
這里鼓勵開發人員做的測試,主要集中在單元測試(功能、性能方面的測試)、集成測試等方面。而系統的測試、用戶需求的進一步驗證和確認、大規模的性能測試、兼容性測試、安全性測試等則有專業的測試人員完成。
3. 認可測試計劃的價值,但更強調計劃是一個基于風險不斷調整的過程
這點比較容易理解,做一件事,如果沒有計劃就比較盲目,失敗的可能性就很大。測試計劃目的就是明確測試的目標、測試的需求(包括測試范圍、測試任務優先級等)、測試風險、測試資源和進度安排等,但同時需求會發生變更、開發的設計與代碼質量超出我們的預料、測試工作量估算不足以及其它新的測試風險等各種因素的影響,我們可能需要不斷調整測試計劃,以適應新的測試需求等。計劃重要,但不是一成不變的,也就是我們強調:
- 測試計劃不能停留在文檔上面,它是對測試過程的規劃與指導,使測試工作開展得更順利、更有效;
- 測試計劃不是一個文檔,而是一個計劃的過程,適時調整以及時滿足項目新的需求;
- 對測試計劃的調整也是學習的過程,有利于將來(為下一個項目)制定出更可靠的測試計劃。
4. 認可探索式測試的價值,但更希望測試是具有系統方法的、相對規范的過程
我們都知道,測試不能窮盡,測試不能做到百分之百,總是有不能測到的地方,總是有缺陷遺留下來,這就給我們留下了足夠的探索空間。探索式測試(Exploratory Testing,ET)的出現正是因為在軟件系統中存在許多未知的東西難以得到快速、簡單的驗證,需要我們轉變思路,不要以固定的模式來完成測試,而是要換一種新的模式來進行測試,以提高測試效率。因為需求不清楚、時間緊等各種原因,探索式測試才更有效,在一定程度上是因為軟件開發本身的問題,所以,我也戲稱“敏捷開發”為“探索式開發”。從這個意義上講,探索式測試方法是不得已而為之的一種方式。在傳統行業,沒有看到一種“探索式檢驗”(除了食品安全檢驗,在我國還不夠成熟,可能會采用探索式檢驗,哈哈),而是有明確的技術規格,有相應的檢測儀器或方法進行檢驗,可以明確地給出檢查結果。
探索式測試作為明確的術語或概念,最早是由測試專家CemKaner博士在1983年提出的,距今天差不多有30年,但絕大多數測試人只是最近幾年才聽到或熟知這個概念。說明其價值是有限的,如果價值很高,也不至于我們現在才比較關注的。但最近幾年探索式測試很熱,為什么?
一方面要感謝James A. Whittaker撰寫的《ExploratorySoftware Testing》一書,比較全面地介紹了探索式軟件測試(國內是2010年引進本書的,但也有不足,我在為史亮和高翔寫的《探索式測試實踐之路》的序中談到這一點),對推廣探索式測試有很大的促進作用。另方面,在互聯網時代,需求衍變越來越快;軟件已經成為一種服務(SaaS),迭代周期越來越頻繁。敏捷方法開始流行,被軟件企業廣泛采用,敏捷測試隨之而生,正是探索式測試用武之時。而且探索式測試的確給人一些新鮮的感覺,將測試工作變成更有趣的探索式活動,在享受工作的同時完成測試,容易受到測試工程師的歡迎。
探索式測試也在不斷發展,人們試圖幫助它建立一套方法體系,例如James Bach提出的基于會話的測試管理(Session Based Test Management,簡稱 SBTM)。該管理方法將測試任務分解成一系列會話(Sessions,發生在特定時間盒內的會話活動,對軟件系統的測試就是看成不斷地問系統的過程,從系統那里獲得答案,探索式測試的會話特征更為明顯),測試人員在會話過程中完成一個特定測試任務的設計、執行和記錄。
但從探索式測試的“探索”概念本身來看,還是強調“設計與執行”同時發生的特點來看,探索式測試更多強調人的創造性,強調隨軟件功能的使用對其理解不斷深入來發現問題,更強調這種上下文驅動的思維模式,而對驗收的標準、驗證的具體指標缺乏關注,更談不上測試需求的分析、測試的系統設計,在系統性和規范性方面有很大的欠缺,所以難以得到國際標準的支持,在多數軟件產品的測試工作中探索式測試只能起著輔助、補充的作用。
任何嚴重的缺陷的遺漏可能給公司帶來不可估量的損失,軟件測試更注重對軟件質量的全面評估,最大程度地減少軟件產品的質量風險,從這個意義看,測試目標、測試需求、測試風險等都是非常重要的,需要認真分析,然后在此基礎上進行系統的測試設計。測試的結果需要嚴格的覆蓋率衡量,而要確保高覆蓋率,需要事先進行精心的設計,從業務流程、數據流程、用戶場景等各個方面進行細致分析,采用合適的測試方法設計出相應的測試用例來覆蓋流程路徑、數據輸入空間以及各種產品使用的場景。事先能從需求覆蓋出發來設計測試用例,事后還可以從代碼覆蓋來檢驗測試的效果。當然,更理想的方式是用基于模型的測試或形式化方法來驗證系統的需求,給出更客觀的、更準確的質量評估,我們對產品的發布就更有信心,客戶就能得到高質量的產品或服務。
5. 認可發現缺陷的價值,但更重視對軟件產品質量的全面評估與持續反饋
發現一個缺陷并得到修正,產品的質量就減少一份風險;在當前產品中發現的缺陷越多,就能更多地消除產品的質量風險,這是軟件測試價值之一個方面的體現。但我們不能有這樣的思想:測試人員發現的缺陷越多,測試人員的價值越大。例如,我們不能一直等開發人員把設計、代碼都工作全部完成之后,我們再來發現問題,以體現測試的價值。我們更不能明明看著開發人員犯錯誤、或者明明知道開發人員可能會在某些地方犯錯誤,我們也不給予提醒、不給予幫助,而是等到他們做完工作,我們再把問題發現出來,以體現我們的價值。
正確的做法則是及時提供有關質量的反饋,可能是一種質量風險的提示,也可能是一種質量擔心的傾訴,更可能是一種有關質量改進的、積極的建議。例如:
- 在需求分析時,發現需求不夠清晰,發現可能給開發、測試帶來困惑的地方,都要及時指出來,并幫助糾正。
- 如果發現文檔中新增加的功能沒有多大意義,或者是自己難以看清楚其功能對客戶的價值,就要主動和產品經理溝通,建議拿掉這個功能,或讓產品經理解釋清楚、說服自己。
- 如果覺得開發任務安排不合理,或覺得開發之前的討論、培訓不夠,對業務理解還很膚淺,就要及時和開發溝通,幫忙消除這種潛在的質量風險;
- 如果發現開發不重視單元測試、或者單元測試做得很少,就要協助開發做好單元測試,提供單元測試指導,提供單元測試框架,提供一切可以幫助開發改善單元測試的服務。
- 如果發現個別的開發工程師不遵守編程規范,就要啟動質量反饋機制…
- … …
這意味著:
- 測試工作不是軟件開發生命周期的某個環境、某個階段性的工作,而是貫穿整個軟件軟件開發生命周期,測試人員無時無刻不在關注質量;
- 測試人員不僅僅要關注已經存在的產品缺陷的問題,還要關注可能導致缺陷發生的問題,盡量幫助產品需求人員、設計人員、編程人員預防質量問題的發生。
- 測試不僅僅是測試人員的工作,而且和軟件開發的其他團隊(人員)有關系;測試工作不是測試團隊內部的事,而是整個開發團隊的事。
泰坦尼克號,在世界航海史上曾被驕傲地稱為“永不沉沒的巨輪”。 愛德華·史密斯,擁有豐富航海經驗的船長與泰坦尼克號,在1912年4月14日處女航中撞擊冰山而葬身大西洋,還有1503名船員和乘客。
2012年的蘇寧正面臨著同樣的挑戰。做了二十多年零售的張近東,其面臨的現實挑戰已經不是讓蘇寧如何避免撞上冰山,而是已經撞上了冰山,如何讓這艘巨輪前行,而不是坐等沉沒。
“泰坦尼克號”是如何沉沒的?
泰坦尼克號設計中,如果船上的16個防水艙只有4個進水的話,船還可以浮在水上,但不幸的是有5個底艙的外壁被冰山撕裂了,棄船是必然的選擇。
蘇寧作為中國最優秀的連鎖零售商,如果在線零售只是占所有社會商品零售的20%也許沒有影響,但不幸的是在過去的一年里,蘇寧所處的家電3C品類,線上占比已經迅速從7%攀升至17%以上,而且還在加速度發展,棄線下發展線上也是必然的選擇。蘇寧不是如何預警,如何躲避冰山的問題,而是已經撞上了冰山。
2012年底馬云和王健林對賭未來10年,在線零售能否占到社會零售總額的一半。也許包含餐飲服務在內,未必能夠實現,但僅僅看家電和3C品類,在可預見的三五年內線上必然會超過線下,蘇寧根本就沒有10年的轉型時間窗口。否則,隨著線下市場被蠶食,而線上無法打敗競爭對手京東商城,蘇寧會如同泰坦尼克號永遠的沉沒。
當然,這絕對不僅僅是蘇寧的命運,而是所有傳統零售商所需要面對的挑戰。
蘇寧急轉彎
2012年6月19日,蘇寧增發55億后,在其南京總部召開發布會,高調發布了“2011-2020新十年發展戰略”,董事長張近東攜高管團隊集體亮相,從連鎖店面、業績、市場營銷、電子商務等方面分別作了目標預期,并“撂下狠話”:蘇寧在2020年將成為店面總數3500家、銷售規模6500億元(線下3500億,線上3000億)的超級服務提供商。
時隔短短半年,蘇寧為何再次傷筋動骨調整長期戰略,必是事出有因。因為半年前制定的戰略是根本沒有辦法完成的。不考慮線上蘇寧易購收入,蘇寧線下實體店收入2012年前三季度負增長1%,門店也從每年凈新增300多家轉為負增長,線下已經在萎縮已無可能增長。因此,線上收入變成了蘇寧未來收入唯一增長點。為了適應新情況的變化,線上業務需要注入更多的資源,戰略再次調整自然成為了必然。
否則,結局會如同國美一樣。
國美電器11月19日公布了前三季度財務報告,國美前三季度凈虧損6.87億人民幣,而去年同期凈利潤為人民幣17.91億元人民幣。前三季度營收為360.57億人民幣,比去年同期人民幣439.83億人民幣同比下滑約18%,前三季度國美電器的毛利率為15.88%,而去年同期的為18.85%,毛利率下滑了2.97%。已經通過消息渠道了解:黃光裕無心再戰,百思買欲重返中國,黃則可能將國美出售給百思買。
簡單總結:回顧2010年張近東言電商破壞價值毫無價值,到2011年言電商只是傳統零售的補充,再到2012年結束后大動干戈調整戰略,將電商視為蘇寧的未來。中國零售業正在發生著翻天覆地的變革,而蘇寧不得不調整戰略,調整資源應對新的挑戰。
蘇寧放下的救生艇:提升線上業務地位
鑒于中國在線零售的快速發展,蘇寧于2009年下半年上線蘇寧易購,算是正式進軍在線零售。回顧歷史,2010年20億,2011年59億,2012年180億,2012年第三季度蘇寧易購營收占蘇寧整體營收的16.94%,放之四海都是讓人瞠目的業績。然而問題是,在不顧用戶體驗,采取非可持續低價促銷(零元購)的增長,在2013年能夠持續嗎?難。
期望蘇寧電商能夠有更大的突破,必須借力蘇寧的各種資源,而原來的組織和業務架構體系是無法滿足這些要求的。因此在此次戰略調整中,與之前相比,最大變化是新建了三個經營事業部,連鎖平臺經營總部、電子商務經營總部和商品經營總部,將電子商務的線上業務重要性提升到與線下電商平等的位置。
至于說三個經營事業部下面結合實體產品、內容產品、服務產品三大類的28個事業部,形成“平臺共享+垂直協同”的運營組合,如何理解解讀就不重要了。
另外指望線上線下融合是沒希望的,且不說很多用戶根本就不去實體店體驗再下單,就算用戶去了實體店,難道就意味著到蘇寧電商下單嗎?蘇寧的體驗店,也可以是京東,可以是易迅網的體驗店。至于線上線下價格同價,更是沒有可能的。要么線下和線上同價,線下毛利潤率19%降低到線上的7%以下嗎?線上賺錢的生意就變成虧本生意,顯然不可能。要么線上價格和線下同價,線上19%的毛利率怎么和堅持10%以下毛利率的京東、易迅網競爭。總而言之,關店會繼續,剩余的門店資源,也看不出特別的價值來。
簡單總結:電子商務是蘇寧的未來,線下變成了線上的支持力量,線下變成了線上的補充。線上打仗需要支援,線下要支持要配合,那么線上的地位就要提升,各方的利益需要協同協調。背水一戰,成敗在此一役,張近東下了一個大賭注。
蘇寧需升級改造
不管蘇寧張近東怎么做,蘇寧改成“云商”,還是“商城”,這些事用戶看不到的,也不需要去關注。用戶在蘇寧買東西,只關注商品,價格和服務。蘇寧的調整,能夠讓蘇寧的商品豐富度提高嗎?能夠讓蘇寧的商品價格更加便宜嗎?或者還是能夠顯著提升蘇寧的服務品質,讓蘇寧電商的配送速度提升到當日達,次日達嗎?
先讓我們來比較一下蘇寧京東之間在商品豐富度、成本效率和用戶體驗的差距。
蘇寧的SKU不超過150萬(小半是圖書),而京東超過200萬,如果你認真比較每個品類,直觀比較更加明顯,蘇寧僅完成了橫向的品類擴張,深度還很欠佳。
蘇寧的整體庫存周轉天數在70天左右,而京東的整體庫存周轉天數為32天,具體到3C品類只有15天。蘇寧的成本費用率上升到15-16%,而京東在8-9%左右(最新情況預估)。
蘇寧電商的用戶體驗,除了大家電能夠做到次日達,其它包括3C在內基本都要3-5天送達,甚至6-7天。送的慢,而且預測的送達時間也非常不準。而了解到京東最新的一個數據是去年第二季度訂單平均下單到出庫時間不到1小時,52%的訂單,在出庫后的4.2小時送達客戶。
如何讓商品更加豐富?需要龐大的合理布局的倉儲體系,需要一個智能化的IT系統。如何讓商品價格更低?需要高效的倉儲物流體系,需要一個系統驅動的商品采銷管理運營系統,做到低成本運營。如何讓服務用戶體驗更好?還是需要一個成熟穩定的倉儲物流體系,需要一個穩定的IT系統。當然,倉儲物流以及IT系統,都需要一個能征善戰的優秀團隊。以上這些,蘇寧有了嗎?
蘇寧電商倉儲,大家電能夠共用集團的倉儲資源,但是包括3C、日用百貨在內的小件倉儲,以及最后一公里,需要另外籌建。按照蘇寧的規劃,12個分布全國的小件倉要到2015年底才完成建設。電商一日千里,等得起三年時間嗎?
蘇寧電商IT系統,蘇寧是一家對IT系統不可謂不重視的零售企業。但相比較于優秀電商而言,還遠遠不夠,否則就不會把核心系統交給第三方服務商了。因為無論是Amazon,還是國內的京東,易迅網都是自建的IT系統。至于交給第三方服務商如何,看用戶投訴即可知。蘇寧易購之前的投訴中,大部分來自IT系統,比如日常都出現這樣的情況:網頁打開速度慢甚至無法打開、商品無法正常下單,支付不成功,返券系統不默認……而這些問題在促銷日更加多。IT系統,已經成為了蘇寧電商發展的核心瓶頸,而且嚴重制約了后續的發展。
簡單總結:蘇寧電商很重要,但是打造蘇寧電商核心競爭力的兩項重要能力倉儲物流和IT系統,做得并不好,而且兩三年內無望解決。所以蘇寧電商必然還是會維持在一個高成本運營,以及較差的用戶體驗的運營狀態。知己知彼方能百戰百勝,蘇寧對其競爭對手了解還不夠深。
蘇寧應該急剎車
昨日和同事晚餐,我說蘇寧面臨著巨大的挑戰,是有可能出人意料出局的。同事贊同蘇寧所面臨的困境,也覺得蘇寧新的戰略也無太多的亮點,但不會出局。因為蘇寧政府關系之強,而不會讓它倒閉,蘇寧背后幾家PE不愿意讓它倒。退一萬步,蘇寧在線下擁有大量地產資產,變賣了,也夠蘇寧活幾十年。
當然生意不是這么做的,從我個人的角度來看,蘇寧不要急于完成它的6500億,不要急于去打敗京東。零售是馬拉松長跑,不在一城一池得失,搭建一個規模化成長的基礎才是關鍵所在。零售做好了,什么供應鏈金融、大數據,也就自然而然了。零售做不好,其它“云商”概念,如水中月鏡中花,是沒有意義的。
簡單總結:蘇寧提“云商”概念,可以給投資人聽,給政府聽,得到更多的支持。但做好零售還是根本,還得繼續關注成本效率,關注用戶體驗,因此現階段改造倉儲物流體系,完善IT系統,才是更加關鍵的,這些都需要時間,需要蘇寧將電商剎車,慢下來。
對蘇寧的希望,別把馬拉松長跑當百米沖刺
我希望蘇寧轉型成功,為什么?因為無數的傳統企業都在盯著看蘇寧,之前無數的零售商品牌商企業都試過了,都失敗了。如果像蘇寧這樣如此堅決轉型,如此愿意投入海量資源,擁有如此優秀的執行力強的團隊的零售商都轉型失敗了,傳統零售商轉型的心,真的要死了。
借用我回同事的一句話結尾:2013年是電商關鍵的一年,可以說蘇寧成敗在此一役,但最重要的是如何打造一個低成本高效率,并保證用戶體驗的可規模化成長基礎。零售,是馬拉松長跑,不是100米沖刺。