From 443286b89c06d65d5e26ee4c5e0162031fe45b1b Mon Sep 17 00:00:00 2001 From: chenwenli Date: Sun, 6 Jan 2013 00:05:07 +0800 Subject: [PATCH] fixed some errors in 12.2,12.3,12.4md files --- 12.2.md | 14 +++++++------- 12.3.md | 14 +++++++------- 12.4.md | 20 ++++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/12.2.md b/12.2.md index 7a146efa..4de4e2c3 100644 --- a/12.2.md +++ b/12.2.md @@ -4,7 +4,7 @@ - 数据库错误:指与访问数据库服务器或数据相关的错误。例如,以下可能出现的一些数据库错误。 - 连接错误:这一类错误可能是数据库服务器网络断开、用户名密码不正确、或者数据库不存在。 - - 查询错误:使用的SQL非法导致错误,这样SQL错误如果程序经过严格的测试应该可以避免。 + - 查询错误:使用的SQL非法导致错误,这样子SQL错误如果程序经过严格的测试应该可以避免。 - 数据错误:数据库中的约束冲突,例如一个唯一字段中插入一条重复主键的值就会报错,但是如果你的应用程序在上线之前经过了严格的测试也是可以避免这类问题。 - 应用运行时错误:这类错误范围很广,涵盖了代码中出现的几乎所有错误。可能的应用错误的情况如下: @@ -13,14 +13,14 @@ - HTTP错误:这些错误是根据用户的请求出现的错误,最常见的就是404请求,虽然可能会出现很多不同的错误,但其中比较常见的错误还有401未授权错误(需要认证才能访问的资源)、403禁止错误(不允许用户访问的资源)和503错误(程序内部出错)。 - 操作系统出错:这类错误都是由于应用程序上的操作系统出现错误引起的,主要有操作系统的资源被分配完了,导致死机,还有操作系统的磁盘满了,导致无法写入,这样就会引起很多错误。 -- 网络出错:指两方便的错误,一方面是用户请求应用程序的时候出现网络断开,这样就导致连接中断,这种错误不会造成应用程序的崩溃,但是会影响用户访问的效果,另一方面是应用程序读取其他网络上的数据,这种网络断开会导致读取失败,这种需要对应用程序做有效的测试,能够避免这类问题出现的情况下程序崩溃。 +- 网络出错:指两方面的错误,一方面是用户请求应用程序的时候出现网络断开,这样就导致连接中断,这种错误不会造成应用程序的崩溃,但是会影响用户访问的效果;另一方面是应用程序读取其他网络上的数据,其他网络断开会导致读取失败,这种需要对应用程序做有效的测试,能够避免这类问题出现的情况下程序崩溃。 ## 错误处理的目标 在实现错误处理之前,我们必须明确错误处理想要达到的目标是什么,错误处理系统应该完成以下工作: - 通知访问用户出现错误了:不论出现的是一个系统错误还是用户错误,用户都应当知道Web应用出了问题,用户的这次请求无法正确的完成了。例如用户的错误请求我们显示一个统一的错误页面(404.html),出现系统错误我们通过自定义的错误页面显示系统暂时不可用之类的错误页面(error.html) - 记录错误:系统出错错误时,一般就是我们调用函数的时候返回err不为nil的情况下,使用前面小节介绍的日志系统记录到日志文件,如果是一些致命错误通过邮件通知系统管理员,例如一般404之类的错误不需要发送邮件,只需要记录到日志系统。 -- 回滚当前的请求:如果一个用户请求过程中出现了一个服务器错误,那么已完成的操作需要回滚。下面来看一个例子:一个系统讲用户递交的表单保存到数据库,并将这个数据递交到一个第三方服务器,但是第三方服务器挂了,这就导致一个错误,那么先前存储到数据库的表单数据应该删除,而且应该通知用户系统出现错误了。 +- 回滚当前的请求操作:如果一个用户请求过程中出现了一个服务器错误,那么已完成的操作需要回滚。下面来看一个例子:一个系统讲用户递交的表单保存到数据库,并将这个数据递交到一个第三方服务器,但是第三方服务器挂了,这就导致一个错误,那么先前存储到数据库的表单数据应该删除(应告知无效),而且应该通知用户系统出现错误了。 - 保证现有程序可运行可服务:我们知道没有人能保证程序一定能够一直正常的运行着,万一哪一天程序崩溃了,那么我们就需要记录错误,然后立刻让程序重新运行起来,让程序继续提供服务,然后再通知系统管理员,通过日志等找出问题。 ## 如何处理错误 @@ -99,9 +99,9 @@ } ## 如何处理异常 -我们知道在很多其他语言中有try...catch操作,可以捕获异常情况,但是其实很多的错误我们都是可以预期的,而不是异常处理,应该当做错误来处理,这也是为什么Go语言采用了函数返回错误的设计,这些函数不会panic,例如如果一个文件找不到,os.Open返回一个错误,它不会panic;如果你向一个中断的网络连接写数据,net.Conn系列类型的Write函数返回一个错误,它们不会panic。这些状态在这样的程序里都是可以预期的。你知道这些操作可能会失败,因为设计者已经用返回错误清楚地表明了这一点。这就是上面所讲的可以预期的错误。 +我们知道在很多其他语言中有try...catch关键词,用来捕获异常情况,但是其实很多错误都是可以预期发生的,而不需要异常处理,应该当做错误来处理,这也是为什么Go语言采用了函数返回错误的设计,这些函数不会panic,例如如果一个文件找不到,os.Open返回一个错误,它不会panic;如果你向一个中断的网络连接写数据,net.Conn系列类型的Write函数返回一个错误,它们不会panic。这些状态在这样的程序里都是可以预期的。你知道这些操作可能会失败,因为设计者已经用返回错误清楚地表明了这一点。这就是上面所讲的可以预期发生的错误。 -但是还有一种情况,有一些操作几乎不可能失败,而且在一些特定的情况下也没有办法返回错误,也无法继续执行,这样情况就应该panic。举个例子:如果一个程序计算x[j],但是j越界了,这部分代码就会导致panic,像这样的一个不可预期严重错误就会引起panic,在默认情况下它会杀掉进程,它允许一个正在运行这部分代码的goroutine从发生错误的panic中恢复运行,发生panic之后,这部分代码后面的函数和代码都不会继续执行,这是Go特意这样设计的,因为要区别于错误和异常,panic其实就是异常处理。如下代码,我们期望通过uid来获取User中的username信息,但是如果uid越界了就会抛出异常,这个时候如果我们没有recover机制,进程就会被杀死,从而导致程序不可服务。因此为了我们程序的健壮性,在一些地方我们需要建立recover机制。 +但是还有一种情况,有一些操作几乎不可能失败,而且在一些特定的情况下也没有办法返回错误,也无法继续执行,这样情况就应该panic。举个例子:如果一个程序计算x[j],但是j越界了,这部分代码就会导致panic,像这样的一个不可预期严重错误就会引起panic,在默认情况下它会杀掉进程,它允许一个正在运行这部分代码的goroutine从发生错误的panic中恢复运行,发生panic之后,这部分代码后面的函数和代码都不会继续执行,这是Go特意这样设计的,因为要区别于错误和异常,panic其实就是异常处理。如下代码,我们期望通过uid来获取User中的username信息,但是如果uid越界了就会抛出异常,这个时候如果我们没有recover机制,进程就会被杀死,从而导致程序不可服务。因此为了程序的健壮性,在一些地方需要建立recover机制。 func GetUser(uid int) (username string) { defer func() { @@ -114,10 +114,10 @@ return } -上面我们介绍了错误和异常的区别,那么我们在开发程序的时候如何来设计呢?规则很简单:如果你的函数无论如何有可能失败,它就应该返回一个错误。当我调用其他package的函数时,如果这个函数实现的很好,我不需要担心它会panic,除非有真正的异常情况发生,即使那样也不应该是我去处理它。而panic和recover是针对自己开发package里面实现的逻辑,针对一些特殊情况来设计。 +上面介绍了错误和异常的区别,那么我们在开发程序的时候如何来设计呢?规则很简单:如果你定义的函数无论如何有无可能失败,它就应该返回一个错误。当我调用其他package的函数时,如果这个函数实现的很好,我不需要担心它会panic,除非有真正的异常情况发生,即使那样也不应该是我去处理它。而panic和recover是针对自己开发package里面实现的逻辑,针对一些特殊情况来设计。 ## 小结 -本小节总结了当我们的Web应用部署之后如何处理各种错误:网络错误、数据库错误、操作系统错误等,当错误发生时,我们的程序如何来正确的处理,显示友好的出错界面、回滚操作、记录日志、通知管理员等操作,最后介绍了如何来正确的处理错误和异常,一般的程序中错误和异常都是混淆的,但是在Go程序中错误和异常是有区分的,所以最后介绍了程序设计的时候如何来遵循这样的原则。 +本小节总结了当我们的Web应用部署之后如何处理各种错误:网络错误、数据库错误、操作系统错误等,当错误发生时,我们的程序如何来正确处理:显示友好的出错界面、回滚操作、记录日志、通知管理员等操作,最后介绍了如何来正确处理错误和异常。一般的程序中错误和异常很容易混淆的,但是在Go中错误和异常是有明显的区分,所以告诉我们在程序设计中处理错误和异常应该遵循怎么样的原则。 ## links * [目录]() * 上一章: [应用日志](<12.1.md>) diff --git a/12.3.md b/12.3.md index c5b3c23b..99cebd24 100644 --- a/12.3.md +++ b/12.3.md @@ -1,9 +1,9 @@ # 12.3 应用部署 -程序开发完毕之后,我们现在要部署Web应用程序了,但是我们如何来部署这些应用程序呢?因为Go程序编译之后是一个可执行文件,编写过C程序的读者一定知道使用daemon就可以完美的实现程序后台运行,但是目前Go还无法完美的实现daemon,因此,针对Go的应用程序部署,我们可以利用第三方工具来管理,第三方的工具有很多,例如Supervisord、upstart、daemontools等,这小节我介绍目前自己系统中采用的工具Supervisord。 -## deamon -目前Go程序如果要实现daemon还不行,详细的见这个Go语言的bug:http://code.google.com/p/go/issues/detail?id=227,大概的意思说很难从现有的使用的线程中fork一个出来,因为没有一种简单的方法来确保所有已经使用的线程的状态一致性问题。 +程序开发完毕之后,我们现在要部署Web应用程序了,但是我们如何来部署这些应用程序呢?因为Go程序编译之后是一个可执行文件,编写过C程序的读者一定知道采用daemon就可以完美的实现程序后台持续运行,但是目前Go还无法完美的实现daemon,因此,针对Go的应用程序部署,我们可以利用第三方工具来管理,第三方的工具有很多,例如Supervisord、upstart、daemontools等,这小节我介绍目前自己系统中采用的工具Supervisord。 +## daemon +目前Go程序如果要实现daemon还不行,详细的见这个Go语言的bug:,大概的意思说很难从现有的使用的线程中fork一个出来,因为没有一种简单的方法来确保所有已经使用的线程的状态一致性问题。 -但是我们可以看到很多网上的一些实现deamon的方法,例如下面两种方式: +但是我们可以看到很多网上的一些实现daemon的方法,例如下面两种方式: - MarGo的一个实现思路,使用Commond来执行自身的应用,如果真想实现,那么推荐这种方案 @@ -107,12 +107,12 @@ 上面提出了两种实现Go的daemon方案,但是我还是不推荐大家这样去实现,因为官方还没有正式的宣布支持daemon,当然第一种方案目前来看是比较可行的,而且目前开源库skynet也在采用这个方案做daemon。 ## Supervisord -上面已经介绍了Go目前是有两种方案来实现他的daemon,但是官方本身还不支持这一块,所以还是建议大家采用第三方成熟工具来管理我们的应用程序,这里我给大家介绍一款目前使用比较广泛的进程管理软件:Supervisord。Supervisord是用Python实现的一款非常实用的进程管理工具。supervisord会帮你把管理的应用程序转成daemon程序,而且可以方便的通过命令开启、关闭、重启等操作,而且它管理的进程一旦奔溃会自动再次重新开启,这样就可以保证程序中断的情况下有自我修复功能。 +上面已经介绍了Go目前是有两种方案来实现他的daemon,但是官方本身还不支持这一块,所以还是建议大家采用第三方成熟工具来管理我们的应用程序,这里我给大家介绍一款目前使用比较广泛的进程管理软件:Supervisord。Supervisord是用Python实现的一款非常实用的进程管理工具。supervisord会帮你把管理的应用程序转成daemon程序,而且可以方便的通过命令开启、关闭、重启等操作,而且它管理的进程一旦崩溃会自动重启,这样就可以保证程序执行中断后的情况下有自我修复的功能。 >我前面在应用中踩过一个坑,就是因为所有的应用程序都是由Supervisord父进程生出来的,那么当你修改了操作系统的文件描述符之后,别忘记重启Supervisord,光重启下面的应用程序没用。当初我就是系统安装好之后就先装了Supervisord,然后开始部署程序,修改文件描述符,重启程序,以为文件描述符已经是100000了,其实Supervisord这个时候还是默认的1024个,导致他管理的进程所有的描述符也是1024.开放之后压力一上来系统就开发报文件描述符用光了,查了很久才找到这个坑。 ### Supervisord安装 -Supervisord可以通过`sudo easy_install supervisor`安装,当然也可以通过Supervisord官网下载后`setup.py install`安装。 +Supervisord可以通过`sudo easy_install supervisor`安装,当然也可以通过Supervisord官网下载后解压并转到源码所在的文件夹下执行`setup.py install`来安装。 - 使用easy_install必须安装setuptools @@ -172,7 +172,7 @@ Supervisord安装完成后有两个可用的命令行supervisor和supervisorctl - supervisorctl reload,载入最新的配置文件,并按新的配置启动、管理所有进程。 ## 小结 -这小节我们介绍了如何实现Go的daemon,但是我们知道由于目前Go的daemon实现不是很完美,我们需要依靠第三方工具来实现应用程序的daemon管理,这里介绍了一个python写的进程管理工具Supervisord,通过Supervisord可以很方便的把我们的Go应用程序管理起来。 +这小节我们介绍了Go如何实现daemon化,但是由于目前Go的daemon实现的不足,需要依靠第三方工具来实现应用程序的daemon管理的方式,所以在这里介绍了一个用python写的进程管理工具Supervisord,通过Supervisord可以很方便的把我们的Go应用程序管理起来。 ## links diff --git a/12.4.md b/12.4.md index 0cf69a5a..9c6b34c0 100644 --- a/12.4.md +++ b/12.4.md @@ -1,13 +1,13 @@ # 12.4 备份和恢复 -这小节我们要讨论应用程序管理的另一个方面:生成服务器上数据的备份和恢复。我们经常会遇到生成服务器的网络断了、硬盘坏了、操作系统奔溃、或者数据库不可用了等各种情况,所以我需要对我们的生成服务器上的应用、数据做异地灾备,冷备热备。在下面的介绍中,将讲解如何备份应用、如何备份Mysql数据库以及将其恢复,如何备份redis数据库以及恢复。 +这小节我们要讨论应用程序管理的另一个方面:生产服务器上数据的备份和恢复。我们经常会遇到生产服务器的网络断了、硬盘坏了、操作系统奔溃、或者数据库不可用了等各种异常情况,所以维护人员需要对生产服务器上的应用、数据做好异地灾备,冷备热备的准备。在接下来的介绍中,讲解了如何备份应用、如何备份/恢复Mysql数据库和redis数据库。 ## 应用备份 -在大多数集群坏境下,Web应用程序基本不需要备份,因为这个其实就是一个代码副本,我们在本地开发环境中,或者版本控制系统中已经保持了这些代码。但是很多时候,我们开发的站点需要用户动态来上传文件,那么我们需要对这些上传的文件进行备份,目前其实一种合适的做法是把和网站相关的需要存储的文件存储到云储存,这样即使系统奔溃我们的文件还在云储存,至少数据不会丢失。 +在大多数集群环境下,Web应用程序基本不需要备份,因为这个其实就是一个代码副本,我们在本地开发环境中,或者版本控制系统中已经保持这些代码。但是很多时候,一些开发的站点需要用户来上传文件,那么我们需要对这些用户上传的文件进行备份。目前其实有一种合适的做法就是把和网站相关的需要存储的文件存储到云储存,这样即使系统崩溃,只要我们的文件还在云存储上,至少数据不会丢失。 -如果我们没有采用云储存的情况下,如何做到网站的备份呢?这里我们介绍一个文件同步工具rsync:rsync能够实现网站的备份,文件的同步,不同系统的文件的同步,如果是windows的话,需要windows版本cwrsync。 +如果我们没有采用云储存的情况下,如何做到网站的备份呢?这里我们介绍一个文件同步工具rsync:rsync能够实现网站的备份,不同系统的文件的同步,如果是windows的话,需要windows版本cwrsync。 ### rsync安装 -rysnc的官方网站:http://rsync.samba.org/ 可以从上面获取最新版本的源码。当然,因为rsync是一款如此有用的软件,所以很多Linux的发行版本都将它收录在内了。 +rysnc的官方网站:http://rsync.samba.org/ 可以从上面获取最新版本的源码。当然,因为rsync是一款非常有用的软件,所以很多Linux的发行版本都将它收录在内了。 软件包安装 @@ -42,14 +42,14 @@ rsync主要有以下三个配置文件rsyncd.conf(主配置文件)、rsyncd.secr - 客户端同步: - 客户端可以通过如下命令同步服务器但的文件: + 客户端可以通过如下命令同步服务器上的文件: rsync -avzP --delete --password-file=rsyncd.secrets 用户名@192.168.145.5::www /var/rsync/backup 这条命令,简要的说明一下几个要点: 1. -avzP是啥,读者可以使用--help查看 - 2. --delete 是为了比如A上删除了一个文件,同步的时候,B会自动删除那个文件 + 2. --delete 是为了比如A上删除了一个文件,同步的时候,B会自动删除相对应的文件 3. --password-file 客户端中/etc/rsyncd.secrets设置的密码,要和服务端的 /etc/rsyncd.secrets 中的密码一样,这样cron运行的时候,就不需要密码了 4. 这条命令中的"用户名"为服务端的 /etc/rsyncd.secrets中的用户名 5. 这条命令中的 192.168.0.100 为服务端的IP地址 @@ -59,9 +59,9 @@ rsync主要有以下三个配置文件rsyncd.conf(主配置文件)、rsyncd.secr ## MySQL备份 -应用数据库目前还是MySQL为主流,目前MySQL的备份有两种方式:热备份和冷备份,热备份目前主要是采用master/slave方式,关于如何配置这方面的资料,大家可以找到很多。master/slave方式的同步目前主要用于读写分离,其实也可以用于热备份数据。冷备份的话就是数据有一定的延迟,但是可以保证该时间段之前的数据完整,例如有些时候可能我们的误操作引起了数据的丢失,那么master/slave模式是无法找回丢失数据的,但是通过冷备份可以部分恢复数据。 +应用数据库目前还是MySQL为主流,目前MySQL的备份有两种方式:热备份和冷备份,热备份目前主要是采用master/slave方式,关于如何配置这方面的资料,大家可以找到很多。master/slave方式的同步目前主要用于数据库读写分离,其实也可以用于热备份数据。冷备份的话就是数据有一定的延迟,但是可以保证该时间段之前的数据完整,例如有些时候可能我们的误操作引起了数据的丢失,那么master/slave模式是无法找回丢失数据的,但是通过冷备份可以部分恢复数据。 -冷备份一般使用shell脚本定时的备份数据库,然后通过上面介绍rsync同步到异地机房的一台服务器。 +冷备份一般使用shell脚本来实现定时备份数据库,然后通过上面介绍rsync同步非本地机房的一台服务器。 下面这个是定时备份mysql的备份脚本,我们使用了mysqldump程序,这个命令可以把数据库导出到一个文件中。 @@ -158,7 +158,7 @@ rsync主要有以下三个配置文件rsyncd.conf(主配置文件)、rsyncd.secr 可以看到,导出和导入数据库数据都是相当简单,不过如果还需要管理权限,或者其他的一些字符集的设置的话,可能会稍微复杂一些,但是这些都是可以通过一些命令来完成的。 ## redis备份 -redis是目前我们使用最多的NOSQL,它的备份也分为两种:热备份和冷备份,redis也支持master/slave模式,所以我们的热备份可以通过这种方式实现,相应的配置大家可以参考官方的文档配置,相当的简单。我们这里介绍冷备份的方式:redis其实会定时的把内存里面的缓存数据保存到数据库文件里面,我们备份只要备份相应的文件就可以,然后利用前面介绍的rsync备份到异地机房就可以实现。 +redis是目前我们使用最多的NoSQL,它的备份也分为两种:热备份和冷备份,redis也支持master/slave模式,所以我们的热备份可以通过这种方式实现,相应的配置大家可以参考官方的文档配置,相当的简单。我们这里介绍冷备份的方式:redis其实会定时的把内存里面的缓存数据保存到数据库文件里面,我们备份只要备份相应的文件就可以,就是利用前面介绍的rsync备份到非本地机房就可以实现。 ## redis恢复 redis的恢复分为热备份恢复和冷备份恢复,热备份恢复的目的和方法同MySQL的恢复一样,只要修改应用的相应的数据库连接即可。 @@ -166,7 +166,7 @@ redis的恢复分为热备份恢复和冷备份恢复,热备份恢复的目的 但是有时候我们需要根据冷备份来恢复数据,redis的冷备份恢复其实就是只要把保存的数据库文件copy到redis的编译目录,然后启动redis就可以了,redis在启动的时候会自动加载数据库文件到内存中,启动的速度根据数据库的文件大小来决定。 ## 小结 -本小节介绍了当我们应用部分完毕之后,如何做好灾备,包括文件的备份、数据库的备份,这里我们介绍了rsync如何同步文件,MySQL数据库和redis数据库如何备份和恢复,希望通过本小节的介绍,能够让作为开发的你对于线上产品的灾备方案提供一个参考。 +本小节介绍了我们的应用部分的备份和恢复,即如何做好灾备,包括文件的备份、数据库的备份。同时也介绍了使用rsync同步不同系统的文件,MySQL数据库和redis数据库的备份和恢复,希望通过本小节的介绍,能够给作为开发的你对于线上产品的灾备方案提供一个参考方案。 ## links * [目录]()