Archive for July, 2011

MySQL的Connection自动断开问题

MySQL缺省配置下,会自动断开那些idle超过8小时的Connection,如果应用程序保持这个连接,8个小时(wait_timeout=28800秒)后,用JDBC,再次访问数据库,会有异常抛出,据说用autoReconnect=true可以避免这个问题,不管你信不信,反正我信了,而且好多年前,我就这么做的。

直到最近,在一个鲜有人访问的应用中发现,问题依旧,8小时候后的第一次访问,总是失败,刷新一下页面,就正常了。Google了一下,才知道MySQL不推荐使用autoReconnect=true来解决此问题,http://bugs.mysql.com/bug.php?id=5020,如下:

[12 Aug 2004 18:46] Mark Matthews
Note: Autoreconnect functionality will be depcreated and eventually removed in future
releases. 

The reason this isn't working for your particular case is that the methodolgy for
autoreconnect was changed to be safer after 3.0.11, and is related to autoCommit state,
which will also cause the current 'in-flight' transaction to fail (if you attempt your
transaction again _after_ the failure, the driver will reconnect). Please see the docs
for the explanation on how to correctly use this feature in the 'Troubleshooting'
section.

In any case, there is no 100% safe way that a JDBC driver can re-connect automatically if
a TCP/IP connection dies without risking corruption of the database 'state' (even _with_
transactional semantics), which is why this feature will eventually be removed.

The JDBC spec does not specify that a connection is alive no matter what happens to the
underlying network for this very reason. 

Clients of JDBC drivers are responsible for dealing with network failures, as only the
application itself (really the developer of the application) 'knows' what the 'correct'
response to a transaction failing due to the network going down is. 'Wait_timeout'
expiring on the server is basically a 'forced' network failure by the server. You can
correct this in a non-robust way by setting 'wait_timeout' higher, however, you as a
developer should be handling SQL exceptions in your code and taking appropriate recovery
actions, not just passing them up the call stack.

解决也很简单,记录最近一次的Connection访问时间,如果超过了8小时,就重新建立这个连接,经验证是可行的。另外也可以在建立Connection的同时,创建一个线程定时的去执行一个SELECT 1语句,前面的方法比较简单。

这里要指出的是,用Connection的isValid()方法去检测Connection是否有效是不行的,程序会死在那里(未调查原因),试图用isClosed()去判断Connection是否断开也是行不通的,因为只有明确的调用了Connection的close()方法后,你才能用isClosed()去判断,也就是说Connection在idle超过8小时候后,这个时候你如果去打印它的isClosed()的值,它还是显示false,但实际上却不能使用。

iPhone流量偷跑探秘

换了部iPhone,用的是联通的3G卡,96的套餐,一个月才340M数据,如果要每月1G以上的流量,就得办386的套餐,有些不划算,并且我的移动卡还继续用,算起来就更不划算了。于是先用起来再说。

前3个月,联通每月额外赠送500M的流量,三个月后就恢复到正常的340M每月,所以我得在前几个月把自己的使用方式和习惯建立起来,以便达到套餐使用的最大利用率。第一件事情就是分析自己的每日数据使用量。

于是乎,安装了几个流量监控软件,比如QQ手机管家,Data Usage等。几天监控下来,发现日平均流量很大,至少有几十兆,这样一个月下来,肯定远远超过340M的上限。这些流量监控软件都无法具体看到是哪个程序耗费了流量,所以很难对症下药。我猜测大概是邮件占了绝大多数流量,我设置了2个邮箱,一个Google Apps Gmail,一个是公司的Exchange,还有一个MobleMe的Find My iPhone,都是Push的方式。Push虽然很方便,但是对于这个套餐,太让人纠结了,只能关闭了。

关闭Push后,只开一个Data Usage软件,每隔10多秒观察一下,发现还有流量产生,小的几十、几百B,大的20、30KB。这个就让人纳闷了,难怪网上很多关于iPhone流量偷跑的帖子。Google了一下,发现一个Paros的软件可以嗅探到HTTP访问(我没有去找更好的软件,比如Sniffer Pro,基于HTTP的分析就可以大概了解情况了)。用Paros设置好代理,将iPhone的Cellular Data和3G都关闭,只是使用Wifi,将代理指向Paros。结果很有意思:

需要上网的软件,使用网络无可厚非。那些看似无需网络的软件,很多也会偷偷的访问网络。举几个例子:

注:这些程序并非只访问一个地址,很多程序会访问很多地址,很多次,我只是列出了一个而已。

很多游戏需要连接到Apple的Game Center,即使是非网络游戏,启动的时候也要联网。让人受不了的是,那个我用来检测流量的软件Data Usage也在不停的消耗流量,它每隔一段时间会从去访问一下它的服务器上的Version.txt,估计是为了提示更新。

我还发现有的软件,每次打开都去访问一下新浪博客的注册页面,URL后面跟着它的邀请码,不知道这样会不会给它带来收益,没有仔细的分析,不做论断。综上所述,结论如下:

  1. iPhone自带的单机软件,也可能访问网络
  2. 第三方的单机软件,更是扑朔迷离,有的为了广告,有的为了了解自己软件的使用情况,有的为了别的目的
  3. 单机版的游戏可能会在和Game Center通信的时候消耗流量
  4. 有的软件,没有做好优化,访问时,发送大量的数据,比如,下图中的‘我查查’,每次请求一个非常长的请求,浪费了用户的流量。
  5. 最后,如果你的套餐流量有限,不用时就关闭Cellular Data,否则联通就笑开了花。

 

下图为‘我查查’的请求URL之一:

上面的分析,不一定全面和准确,请自行验证,并且这里只有HTTP的嗅探,如果程序用别的方式访问网络(比如QQ),还是会消耗你的流量。但是管中窥豹,其他协议也不用具体分析了,分析了也不好解决。总之一句话:在天朝用3G,就得认这个蛋疼的命,如果资费便宜了,谁会在乎这点流量。

Switch to our mobile site