Mysql数据库复制及备份


一、mysql数据库复制概述

复制解决的基本问题是让一台服务器的数据和另外的服务器保持同步。一台主服务器可以连接多台从服务器,并且从服务器也可以反过来作为主服务器。主服务器和从服务器可以位于不同的网络拓扑中,还能对整台服务器、特定的数据库,甚至特定的表进行复制。

MySQL复制大部分都是向后兼容的。这意味着版本较新的服务器可以是版本较老的服务器的从服务器。但老版本的服务器通常不能是新版本号的服务器的从服务器。复制通常不会大幅增加主服务器的开销。它需要主服务器启用二进制日志,这或许会有较大的开销,但是出于备份的目的,无论如何这种开销都是需要的。

复制通常的用途有:数据分布、负载平衡、备份、高可用性和故障转移、测试mysql升级。


二、复制的工作原理

总体上来说,复制有以下三个步骤:

(a)主服务器把数据更改记录到二进制日志中。(这叫做二进制日志事件(binary
log events
)。)

(b)从服务器把主服务器的二进制日志事件拷贝到自己的中继日志(relay
log
)中。

(c)从服务器重放中继日志中的事件,把更改用到自己的数据上。

这三个步骤如下图所示:

第一步:在主服务器上记录二进制日志。在每个更新数据的事务完成之前,主服务器都会把数据更改记录到二进制日志中。即使事务在执行期间是交错的,mysql也会串行地把事务写入到二进制日志中。在把事件写入到二进制日志之后,主服务器告诉存储引擎提交事务。

第二步:从服务器把主服务器的二进制日志拷贝到自己硬盘上,进入所谓的“中继日志(relay log)中。

它首先启动一个工作线程,叫I/O线程。这个I/O线程开启一个普通的客户端连接,然后启动一个特殊的二进制日志转储进程。这个转储进程从主服务器的二进制日志中读取事件。它不会对事件进行轮询。如果它跟上了主服务器,就会进入休眠状态,并等待有新事件发生时主服务器发出的信号。I/O线程把事件写入从服务器的中继日志中。

第三步:SQL从线程处理了该过程的最后一部分。该线程读取了中继日志,并且重放其中的事件,然后更新从服务器的数据。由于这个线程能跟上I/O线程,所以,中继日志一般都是在操作系统的缓存中,因此中继日志的开销很低。同时SQL线程执行的事件也可以被写入从服务器自己的二进制日志中。


三、创建复制以及配置主、从服务器

创建复制主要分为下面几个步骤:

1、  在每一台服务器上建立复制账号。

2、  配置主、从服务器。

3、  指导从服务器进行连接与复制。

下面以实际操作的例子来进一步说明复制的创建。

1、  平台说明:

系统环境:ubuntu10.10

软件版本:mysql-5.5.25

2、  Mysql数据库说明:

在两台不同的计算机里面安装好mysql服务器。

主服务器IP192.168.1.100

从服务器IP192.168.1.104

下面将按照创建复制的步骤进行说明

第一步:在每一台服务器上建立复制账号

Mysql有一些特殊的权限允许复制进程运行。从I/O线程运行在从服务器上,它创建了到主服务器的连接。基于此,在主服务器上就必须创建一个用户账户并且给它合适的权限,这样I/O线程就可以以这个用户的身份连接到主服务器,并且读取它的二进制日志。

上述命令在主服务器上创建一个用户名为repl的账号。这里把用户限制到了本地网络。

第二步:配置主、从服务器

修改主服务器的配置文件my.cnf:加入如下设置

sync_binlog = 1

log-bin = mysql-bin

server-id = 10

innodb_support_xa =1

在主服务器上最重要的二进制日志设置是sync_binlog,这使得mysql在每次提交事务的时候把二进制日志的内容同步到磁盘上,即使服务器崩溃也会把事件写入日志中。

如果不想在服务器崩溃后表被破坏,所以我们使用mysql默认的存储引擎InnoDB

而且必须显式地定义唯一的服务器ID。这里为了避免产生混淆,用10代替1。因为1通常是服务器的默认值。所以使用1容易引起混淆,并导致和没有服务器ID的服务器冲突。

如果log_bin选项在主服务器的配置文件中没有定义,那就重启mysql

验证二进制日志文件已经被创建出来,可以运行如下指令:

从服务器也需要和主服务器类似的配置,并且也需要在从服务器上重启mysql

log-bin=mysql-bin

server-id  = 2

relay_log  = mysql-relay-bin

log_slave_updates = 1

read_only  = 1

skip_slave_start

以上配置单从技术上来说,有些选项是不需要的。实际上,从服务器只有server_id参数是必须的,这里我们也开启了log_bin,并且显式地给了二进制文件一个名字。同时,把主、从服务器的文件名设置成一样的,这样做的目的是便于把从服务器变为主服务器。

此外,还添加了两个其他的可选配置参数:relay_log(定义中继日志的位置和文件名)和log_slave_update(使从服务器把复制的事件记录到自己的二进制日志中)。

Skip_slave_start选项会阻止从服务器在崩溃后自动启动,可以让管理员有机会去修复服务器。

第三步:指导从服务器进行连接与复制

这一个步骤是告诉从服务器如何连接到主服务器并中继其中二进制日志。这一个步骤中,不要直接在配置文件my.cnf里配置,而是应该使用CHANGE MASTER TO命令,在从服务器上输入如下所示命令:

参数说明:

MASTER_HOST:指主服务器IP

MASTER_USER:指复制账号用户名。

MASTER_PASSWORD:指复制用户密码。

MASTER_LOG_FILE:指复制的二进制日志名。

MASTER_LOG_POS:指二进制日志的偏移量。

输入上述指令没有出错的话,将会有成功的提示。

检测输出:

输入上面这条命令,将会出现如下所示内容:

由上图可以看到,此时,从服务器I/O线程和SQL线程正在运行,并且Seconds_Behind_Master不再是NULL(如果想看到是NULL的话,就先STOP
SLAVE
;然后再SHOW SLAVE STATUS\G)。I/O线程正在等待主服务器的事件,这意味着它已经提取了主服务器的所有二进制日志。日志位置已经增加了,表示一些事件已经提取并执行过了。这时,如果在主服务器上做一些数据更改,那么将会看见从服务器上的文件和位置参数都增加了。些时就可以在从服务器上看到数据库改变了。

查看主、从服务器工作线程:

    当然啦,这里显示的例子,是来自运行了一些日子的服务器,所以I/O线程Time列值比较大。从服务器的SQL线程已经空闲了11秒,这表示已经有11秒没有发生事件重放了。Info显示正在执行的查询,目前正在执行的查询为NULL

前面所述都是假设主、从服务器刚刚安装好,使用的数据都是默认的初始化数据,所以两台服务器默认的有相同数据,并且也知道了主服务器的二进制日志。但如果是主服务器已经运行了一段时间了,然后用一台新安装的从服务器进行同步,那么此时,从服务器还没有主服务器的数据。

所以,在复制数据之前,必须用主服务器初始化一台从服务器。为了让从服务器和主服务器同步数据,需要下面三个条件:

1、  某个时间点上主服务器数据的快照。

2、  主服务器当前的日志,以及从快照时间点以来精确的日志字节偏移量。这两个值叫做日志文件坐标,它们共同确定了二进制日志的位置。可以使用SHOW
MASTER STATUS
查找主服务器的日志文件坐标。

3、  从快照时间到现在的主服务器二进制日志文件。

这里,由于我们只用了mysql默认的存储引擎InnoDB,所以,可以使用下面的命令来转储主服务器的所有内容,把它装入从服务器中,并且把从服务器的坐标改成主服务器二进制日志的相应位置:

$mysqldump –h 192.168.1.100 –u repl –p123456 –single-transaction –all-databases –master-data=0 | mysql –p

这样,就可以把主服务器上的数据同步到从服务器上了。

至此,当主服务器上有数据更改,从服务器上的数据也会发生更改。我们管这种数据复制模式叫做主—从模式。

但现实中,通常需要的是两台服务器,当其中一台服务器的数据发生变化,将会把数据同步到另一台服务器中。这种模式叫主—主模式。

配置这种模式,只要将前面所述的主、从服务器配置反过来设置一次就可以了。主服务器和从服务器的设置是对称的。

当设置好后,就可以实现主—主同步复制了。


四、其他复制模式简介

1、一主多从模式

刚才配置从服务器的时候加入了log_slave_updates选项,这样就可以把一台从服务器变成主服务器了,它会指导mysql把自己执行的事件写到二进制日志中,然后自己的从服务器就可以取得这些事件并执行它。如下图所示:

在这种情形下,主服务器的改变导致事件被写入到二进是中。第1个从服务器提取并执行这个事件。

一般来说,这个时候事件的生命周期就结束了,但是因为log_slave_updates 打开了,所以,从服务器就会把它写入到自己的二进制日志中。那么第2个从服务器就可以再次取得这个事件并执行它了。

2、复制过滤器

在主、从服务器的数据复制同步过程中,我们可以有选择性的复制同步一部份数据,这时就要用到复制过滤器。复制过滤器有两种:

(a)主服务器上把事件从二进制日志中过滤掉的过滤器。

(b)从服务器上把事件从中继日志中过滤掉的过滤器。

如下图所示:

控制二进制日志过滤的选项是binlog_do_dbbinlog_ignore_db。但通常不要开启它们。

在从服务器上,replicate_*选项在从服务器SQL线程从中继日志中读取事件的时候进行过滤。可以复制,或者忽略一个或多个数据库。

3、复制拓扑

Mysql数据库的复制拓扑中,必须遵守下面的基本原则:

(a)一个mysql从服务器只能有一个主服务器。

(b)每个从服务器有唯一的服务器ID

(c)一个主服务器可以有很多从服务器。

(d)如果打开了log_slave_update,一个从服务器就能把主服务器的改动传播下去,并且能成为其他从服务器的主服务器。

下面列出一部份复制拓扑的结构示意图:

一台主服务器和多个从服务器

  

拥有从服务器的环形结构

 

    除上述所讲到的复制拓扑外,不家其他一些拓扑,这里不一一叙述。具体在现实工作环境中,要使用哪一个复制模式,将要按照需求进行选择配置。


五、备份与还原

备份数据是数据库管理中最常用的操作。为保证数据库中数据的安全,数据库管理员需要定期的进行数据库备份。当数据库遭到破坏时,通过备份文件来还原数据库。

1、使用mysqldump命令备份

Mysqldump命令可以将数据库中的数据备份成一个文本文件。表的结构和表中的数据将存储在生成的文本文件中。

Mysqldump命令的工作原理:它先查出需要备份的表的结构,再在文本文件中生成一个CREATE语句。然后,将表中的所有记录转换成一个INSERT语句。这些CREATE语句和INSERT语句都是还原时使用的。还原数据时就可以使用其中的CREATE语句来创建表,使用其中的INSERT语句来还原数据。

使用mysqldump命令备份一个数据库的基本语法如下:

Mysqldump –u username –p dbname table1 table2……>BackupName.sql

参数说明:

Dbname:参数表示数据库的名称;

Table1table2:表示表的名称,没有该参数时将备份整个数据库;

BackupName.sql:表示备份文件的名称,文件名前面可以加上一个绝对路径。一般都会将数据库备份成一个后缀名为sql的文件。

但是mysqldump命令备份的文件并非一定要求后缀名为.sql,备份成其他格式的文件也是可以的,但是通常情况下是备份成后缀名为.sql的文件,因为,后缀名为.sql的文件给人的第一感觉就是与数据库有关的文件。

使用mysqldump备份多个数据库:

Mysqldump –u username –p –databases dbname1 dbname2…… > BackupName.sql

可以看到,备份多个数据库和备份一个数据库不同,备份多个数据库要加上“–databases”这个选项,然后后面跟多个数据库的名称。

使用mysqldump备份所有的数据库:

Mysqldump –u username –p –all-databases > BackupName.sql

2、远程备份

远程备份可以分为两种情况:

第一:两台服务器没有进行数据同步设置、从服务器数据跟不上主服务器数据更新或者设置数据同步的时候不是完全数据同步而只份数据同步。

第二:两台服务器进行了数据同步设置、服务器数据几本上不落后主服务器数据并且设置数据同步的时候是完全数据同步。

下面先讨论第一种情况。假设,需要备份的服务器主机IP为:192.168.1.100,首先在该主机上为mysql系统添加root远程登录权限:

mysql> grant all privileges on *.* to  root@’%’ identified by ‘123456;

此时在远端的服务器上就可以登录主机服务器了:

Mysql –h 192.168.1.100 –u root –p

然后输入密码后就可以登录进主服务器的root用户了。

远程备份全部数据库:

 Mysqldump –h 192.168.1.100 –u root –p123456 –all-databases >/home/Backup.sql

这样就可以把远程主机上的数据库数据备份到本地设备上了。

第二种情况比较简单,因为两台服务器数据是完全同步的,也就是说两台服务器上的数据库数据是一致的,所以,对于这种情况,我们只需要用mysqldump命令按本地备份模式进行备份就可以了。

3、数据还原

当管理员的非法操作和计算机的故障等都会破坏数据库文件。当数据库遭到这些意外时,可以通过备份文件将数据库还原到备份时的状态。这样可以将损失降低到最小。

前面说了,我们是用mysqldump命令将数据库中的数据备份成一个文本文件。并且通常来说这个文件会以.sql后缀名结尾。需要还原的时候,可以使用mysql命令来还原备份的数据。

备份文件中通常包含CREATE语句和INSERT语句。Mysql命令可以执行备份文件中的CREATE语句和INSERT语句。通过CREATE语句来创建数据库和表。通过INSERT语句来插入备份的数据。从而达到还原的目的。

Mysql命令的基本语法如下:

Mysql –u root –p [dbname] < backup.sql

参数说明:

Dbname参数表示数据库名称。该参数可选,可以指定数据库名,也可以不指定。指定数据库名时,表示还原该数据库下的表。不指定数据库名时,表示还原特定的一个数据库。

 

mysql show database size

SELECT table_schema                                        "DB Name", 
   Round(Sum(data_length + index_length) / 1024 / 1024, 1) "DB Size in MB" 
FROM   information_schema.tables 
GROUP  BY table_schema; 

arguments

function show(foo, bar) {
  window.alert(foo+' '+bar);
}
function run(f) {
  // use splice to get all the arguments after 'f'
  var args = Array.prototype.splice.call(arguments, 1);
  f.apply(null, args);
}

run(show, 'foo', 'bar');

Two Ways to Check for Palindromes in JavaScript

function palindrome(str) {
  // Step 1. Lowercase the string and use the RegExp to remove unwanted characters from it
  var re = /[\W_]/g; // or var re = /[^A-Za-z0-9]/g;
  
  var lowRegStr = str.toLowerCase().replace(re, '');
  // str.toLowerCase() = "A man, a plan, a canal. Panama".toLowerCase() = "a man, a plan, a canal. panama"
  // str.replace(/[\W_]/g, '') = "a man, a plan, a canal. panama".replace(/[\W_]/g, '') = "amanaplanacanalpanama"
  // var lowRegStr = "amanaplanacanalpanama";
     
  // Step 2. Use the same chaining methods with built-in functions from the previous article 'Three Ways to Reverse a String in JavaScript'
  var reverseStr = lowRegStr.split('').reverse().join(''); 
  // lowRegStr.split('') = "amanaplanacanalpanama".split('') = ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"]
  // ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"].reverse() = ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"]
  // ["a", "m", "a", "n", "a", "p", "l", "a", "n", "a", "c", "a", "n", "a", "l", "p", "a", "n", "a", "m", "a"].join('') = "amanaplanacanalpanama"
  // So, "amanaplanacanalpanama".split('').reverse().join('') = "amanaplanacanalpanama";
  // And, var reverseStr = "amanaplanacanalpanama";
   
  // Step 3. Check if reverseStr is strictly equals to lowRegStr and return a Boolean
  return reverseStr === lowRegStr; // "amanaplanacanalpanama" === "amanaplanacanalpanama"? => true
}
 
palindrome("A man, a plan, a canal. Panama");

继续阅读“Two Ways to Check for Palindromes in JavaScript”

diffTwoArrays

function arr_diff (a1, a2) {
    var a = [], diff = [];
    for (var i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }
    for (var i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }
    for (var k in a) {
        diff.push(k);
    }
    return diff;
};
function diffArray(arr1, arr2) {
  var newArr = [];
  // Same, same; but different. 
  var diff1 = arr1.filter(function(x) { return arr2.indexOf(x) < 0; });
  var diff2 = arr2.filter(function(x) { return arr1.indexOf(x) < 0;});
  newArr = diff1.concat(diff2);
  return newArr;
}

diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);

MySQL多种存储引擎比较及应用场景

MySQL有多种存储引擎:
MyISAM、InnoDB、MERGE、MEMORY(HEAP)、BDB(BerkeleyDB)、EXAMPLE、FEDERATED、ARCHIVE、CSV、BLACKHOLE。
MySQL支持数个存储引擎作为对不同表的类型的处理器。MySQL存储引擎包括处理事务安全表的引擎和处理非事务安全表的引擎:

◆ MyISAM管理非事务表。它提供高速存储和检索,以及全文搜索能力。MyISAM在所有MySQL配置里被支持,它是默认的存储引擎,除非你配置MySQL默认使用另外一个引擎。

◆ MEMORY存储引擎提供“内存中”表。MERGE存储引擎允许集合将被处理同样的MyISAM表作为一个单独的表。就像MyISAM一样,MEMORY和MERGE存储引擎处理非事务表,这两个引擎也都被默认包含在MySQL中。
注释:MEMORY存储引擎正式地被确定为HEAP引擎。

◆ InnoDB和BDB存储引擎提供事务安全表。BDB被包含在为支持它的操作系统发布的MySQL-Max二进制分发版里。InnoDB也默认被包括在所 有MySQL 5.1二进制分发版里,你可以按照喜好通过配置MySQL来允许或禁止任一引擎。

◆ EXAMPLE存储引擎是一个“存根”引擎,它不做什么。你可以用这个引擎创建表,但没有数据被存储于其中或从其中检索。这个引擎的目的是服务,在 MySQL源代码中的一个例子,它演示说明如何开始编写新存储引擎。同样,它的主要兴趣是对开发者。

◆ NDB Cluster是被MySQL Cluster用来实现分割到多台计算机上的表的存储引擎。它在MySQL-Max 5.1二进制分发版里提供。这个存储引擎当前只被Linux, Solaris, 和Mac OS X 支持。在未来的MySQL分发版中,我们想要添加其它平台对这个引擎的支持,包括Windows。

◆ ARCHIVE存储引擎被用来无索引地,非常小地覆盖存储的大量数据。

◆ CSV存储引擎把数据以逗号分隔的格式存储在文本文件中。

◆ BLACKHOLE存储引擎接受但不存储数据,并且检索总是返回一个空集。

◆ FEDERATED存储引擎把数据存在远程数据库中。在MySQL 5.1中,它只和MySQL一起工作,使用MySQL C Client API。在未来的分发版中,我们想要让它使用其它驱动器或客户端连接方法连接到另外的数据源。
当你创建一个新表的时候,你可以通过添加一个ENGINE 或TYPE 选项到CREATE TABLE语句来告诉MySQL你要创建什么类型的表:
CREATE TABLE t (i INT) ENGINE = INNODB;
CREATE TABLE t (i INT) TYPE = MEMORY;
虽然TYPE仍然在MySQL 5.1中被支持,现在ENGINE是首选的术语。

如何选择最适合你的存储引擎呢?

下述存储引擎是最常用的:
◆ MyISAM:默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。注意,通过更改STORAGE_ENGINE配置变量,能够方便地更改MySQL服务器的默认存储引擎。

◆ InnoDB:用于事务处理应用程序,具有众多特性,包括ACID事务支持。

◆ BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性。

◆ Memory:将所有数据保存在RAM中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问。

◆ Merge:允许MySQL DBA或开发人员将一系列等同的MyISAM表以逻辑方式组合在一起,并作为1个对象引用它们。对于诸如数据仓储等VLDB环境十分适合。

◆ Archive:为大量很少引用的历史、归档、或安全审计信息的存储和检索提供了完美的解决方案。

◆ Federated:能够将多个分离的MySQL服务器链接起来,从多个物理服务器创建一个逻辑数据库。十分适合于分布式环境或数据集市环境。

◆ Cluster/NDB:MySQL的簇式数据库引擎,尤其适合于具有高性能查找要求的应用程序,这类查找需求还要求具有最高的正常工作时间和可用性。

◆ Other:其他存储引擎包括CSV(引用由逗号隔开的用作数据库表的文件),Blackhole(用于临时禁止对数据库的应用程序输入),以及Example引擎(可为快速创建定制的插件式存储引擎提供帮助)。
请记住,对于整个服务器或方案,你并不一定要使用相同的存储引擎,你可以为方案中的每个表使用不同的存储引擎,这点很重要。

MySQL Cross Server Select Query

mysqldump could be a solution as mentioned already or you could try using the SELECT … INTO OUTFILE and then LOAD DATA INFILE … commands.

MySQL does have the federated storage engine which might be useful to you. Here’s some more documentation on it http://dev.mysql.com/doc/refman/5.0/en/federated-storage-engine.html I have to confess that I’ve not had huge success with it but it might work for you.

The third solution would be to do the work in your application. Read in the results of the SELECT query line by line and INSERT to the other server line by line. You might run into some issues with data types and null handling that way though.

卖油翁

陈康肃公尧咨(zī) 善射,当世无双 ,公亦以此自矜(jīn)。尝射于家圃(pǔ),有卖油翁释担(dàn)而立,睨(nì)之,久而不去。见其发矢(shǐ)十中八九,但微颔(hàn)之。
康肃问曰:”汝(rǔ)亦知射乎?吾射不亦精乎?”翁曰:”无他, 但手熟(shú)尔。”康肃忿(fèn)然曰:”尔安敢轻吾射!”翁曰:”以我酌(zhuó)油知之。”乃取一葫芦置于地,以钱覆其口,徐以杓(sháo)酌油沥(lì)之,自钱孔入,而钱不湿。因曰:”我亦无他,唯手熟(shú)尔。”康肃笑而遣(qiǎn)之。
此与庄生所谓解牛斫轮者何异?

leetcode-sum3

Given an array S of n integers, are there elements a, b, c in S such that
a + b + c = 0?
Find all unique triplets in the array which gives the sum of zero.

Note:

Elements in a triplet (a,b,c) must be in non-descending order.
(ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.

For example, given array S = {-1 0 1 2 -1 -4},

A solution set is:
(-1, 0, 1)
(-1, -1, 2)

package leetcode

import (
	"fmt"
	"sort"
	"sync/atomic"
)

var arrLen int
var ops uint64 = 0
var sortArr []int

func getArr() []int {
	inputArr := []int{-7, -8, -1, -2, -4, 1, 4, 9, 3, 6}
	return inputArr
}

func ThreeSum() {
	// call get array func
	inputArr := getArr()
	//make sure are sorted
	fmt.Println(inputArr)
	if !sort.IntsAreSorted(inputArr) {
		// sort inputArr
		sort.Ints(inputArr)
		fmt.Println(inputArr)
		sortArr = inputArr
	}
	//get this array length
	arrLen = len(sortArr)
	for i := 0; i < arrLen-2; i++ {
		fmt.Println("loop time : ", i)
		if i > 0 && sortArr[i-1] == sortArr[i] {
			//if near equal ,skip this time loop
			continue
		}
		currNum := sortArr[i]
		low := i + 1
		high := arrLen - 1
		for low < high {
			lowNum := sortArr[low]
			highNum := sortArr[high]
			sumNum := currNum + lowNum + highNum
			if sumNum == 0 {
				//2d array use
				atomic.AddUint64(&ops, 1)
				opsFinal := atomic.LoadUint64(&ops)
				//print result
				fmt.Println("--------------Begin--------------")
				fmt.Println("counter : ", opsFinal)
				fmt.Println("first Number : ", currNum)
				fmt.Println("second Number : ", lowNum)
				fmt.Println("third Number : ", highNum)
				fmt.Printf("[%d,%d,%d]", currNum, lowNum, highNum)
				fmt.Println("")
				fmt.Println("---------------End---------------")
				low++
			} else if sumNum > 0 {
				for high > 0 && sortArr[high] == sortArr[high-1] {
					high--
				}
				high--
			} else {
				for low < arrLen && sortArr[low] == sortArr[low+1] {
					low++
				}
				low++
			}
		}
	}
}

散步 [课文原文] — 莫怀戚

  我们在田野散步:我,我的母亲,我的妻子和儿子。

  母亲本不愿出来的。她老了,身体不好,走远一点就觉得很累。我说,正因为如此,才应该多走走。母亲信服地点点头,便去拿外套。她现在很听我和话,就象小时候我很听她的话一样。

  天气很好。今年的春天来的太迟,太迟了,有一些老人挺不住。但春天总算来了。我的母亲又熬过了一个严冬。

  这南方初春的田野,大块小块的新绿随意地铺着,有的浓,有的淡;树上的绿芽也密了;田野里的冬水也咕咕地起着水泡。这一切使人想起一样东西——生命。

  我和母亲走在前面,我的妻子和儿子走在后面。小家伙突然叫起来:“前面也是妈妈和儿子,后面也是妈妈和儿子。”我们都笑了。

  后来发生了分歧:母亲要走大路,大路平顺;我的儿子要走小路,小路有意思。不过,一切都取决于我。我的母亲老了,她早已习惯听从她强壮的儿子;我的儿子还小,他还习惯听从他高大的父亲;妻子呢,在外边,她总是听我的。一霎时我感到了责任的重大。我想一个两全的办法,找不出;我想拆散一家人,分成两路,各得其所,终不愿意。我决定委屈儿子,因为我伴同他的时日还长。我说:“走大路。”

  但是母亲摸摸孙儿的小脑瓜,变了主意:“还是走小路吧。”她的眼随小路望去:那里有金色的菜花,两行整齐的桑树,尽头一口水波粼粼的鱼塘。“我走不过去的地方你就背着我。”母亲对我说。

  这样,我们在阳光下,向着那菜花、桑树和鱼塘走去。到了一处,我蹲下来,背起了母亲,妻子也蹲下来,背起了儿子。我的母亲虽然高大,然而很瘦,自然不算重;儿子虽然很胖,毕竟幼小,自然也轻:但我和妻子都是慢慢地,稳稳地,走得很仔细,好像我背上的同她背上的加起来,就是整个世界。