分类目录归档:程序相关

C,Python,环境配置等

在线修改MySQL大表的表结构

问题描述

由于某个临时需求,需要给在线MySQL的某个超过千万的表增加一个字段。此表在设计之时完全按照需求实现,并没有多余的保留字段。

我们知道在MySQL中如果要执行ALTER TABLE操作,MySQL会通过制作原来表的一个临时副本来工作。对于表结构的修改在副本上施行,然后将新表替换原始表,此时会产生锁表,用户可以从原始表读取数据,而用户的更新和写入操作都会被lock,待新表准备好后写入新表。
这对于在线的数据量较大的表来说是绝对无法容忍的,并且由于这种在线操作时间会很长,此时如果show processlist,会发现有若干的MySQL进程处于lock状态,当这种进程太多超过单台服务器允许的MySQL进程数,其它进程可能会被拒绝连接。

有哪些方案可以处理这个问题呢?

方案1、直接ALTER TABLE
这个方案只能说这仅仅是一种方案,在某些非实时在线或数据量较小时有较好的表现。

方案2、模拟数据库修改表结构的操作,在非数据库层实现整个过程。

  1. 实现业务中对于数据的读写分离
  2. 创建一个已经按需求修改好结构的新表
  3. 修改业务逻辑,将读操作指向旧表,将写操作指向新表。如果读旧表没有,再读新表,并将旧的数据写入到新表,当然这一步写入操作我们可以不用,我们可以在后台做一个定时任务将旧数据同步到新表。

这种方案有一个较大的缺点,需要业务逻辑层配合实现数据的迁移,对于业务逻辑有修改,并且如果有多台机器的话,需要一台一台的修改,较费时间,但是对于MySQL的两种主要存储引擎都适用。


方案3、facebook online schema change
facebook的OSC在整体流程上与方案2没有较大的区别,只是它在这里引入了触发器,从而不需要修改业务逻辑,在数据库层就实现了新数据的两个表的同步问题。其大概步骤如下:

  1. 按需求创建新表
  2. 针对原始表创建触发器
  3. 对于原始表的更新操作都会被触发器更新到新表中
  4. 把原始表中的数据复制到新表中
  5. 将新表替换旧表

fb的osc方案从数据库层解决了方案2的问题,但是它仅支持InnoDB存储引擎。


方案4、换一个思路,保留字段。
假设一切可以从头再来,我们也许可以加多一些冗余字段,各个类型都加一些,备用。只是,回不去了!

方案5、再换一个思路,增加扩展表。
我们不在原有的表的基础上修改了,以增加扩展表的方式,将新字段的数据写入到扩展表中,修改业务逻辑,这些字段从新表中读取。
志强同学说这是典型的维表结构设计。
暂时解决了问题,如果这些字段后续使用频率高的话,可能会有对后期维护或业务有一定的影响。

后记
基于现有的需求,只是需要记录新的字段,所以采用了扩展表的方案。

从PHP的自动测试想到的

从PHP的自动测试想到的

昨日,因TIPI项目而阅读了PHP的自动测试实现相关代码。于此,有些许感想,记录如下。

1、用自己测试自己,制定测试过程规范。
PHP的测试环境是用PHP实现的,这不得不说是一个创新之举。相对于编译型语言,作为动态语言的PHP在应对变化上有着不少的优势,而测试本来就是一个变化是非较多的地儿。其实用到了PHP的地方只是这个框架的控制器,即源码根目录下run-tests.php文件。作为控制器,它实现了整个测试过程的控制。以一个测试过程为例,总体上分为三个部分:准备、运行和显示结果。准备活动包括测试所必须的环境变量的读取与设置,对测试参数的解析,测试脚本名的解析,各种输出文件的准备 解析测试脚本中的各个段落等;运行活动包括构造测试语句,执行测试语句,得到实际运行结果;显示结果活动包括测试后的结果比对及输出,相关记录记录以及总的测试报告显示。

这个控制器就是PHP自动测试的规范,所有的逻辑都在这一个脚本文件中,在一个时间点上,这是一个不变的过程。对于测试中变化的内容如测试环境,测试输入数据、需要验证的内容以及针对不同输入和不同测试点应该得到的预期结果,这些都存储在PHPT文件中,以不同的标记作为段分开。这些文件按模块划分,一个用例就是一个文件,与将用例写成代码相比,优势不仅仅在于工作量,更多的是在于它的扩展性、可读性和可维护性。

2、简单监控框架

先确认我们这个监控框架的需求什么。现在我们要的是一个可以监控数据是否正常,数据的状态是否符合业务逻辑,并将监控的结果发给相关负责人。从这个简单的需求出发,我们可以发现这里变化的是监控的内容,而不变的是整个监控的流程:查询特定的数据源,根据具体业务确认数据的正确性和合理性,并将结果发送给相关责任人。

对于不变的因素,我们可以以公共模块的方式在代码中实现,如果汇报结果的形式有不同的分类和权限控制的话,我们可以将这些配置放到数据库,当然,我们还是需要在代码中实现这些汇报的方式。

对于变化的因素,我们可以学习PHP的测试过程,以某些特定的规则定义一个一个的监控,我们可以称之为监控用例。在用例中定义名称、输入、过程和预期结果。比如,我们可以定义–SQL–字段做数据源。当然,这些内容我们可以分散存储,也可以集中存储在数据库。

这样一种以测试的方式实现监控过程,也许可以试试。

Form表单的enctype属性和method属性

在WEB开发过程中,Form表单元素是一个使用频率非常高的控件,对于这样一个控件,也许我们并没有认真关注过。今天我们来解读它的enctype属性和method属性。

enctype 属性

enctype属性规定在发送到服务器之前应该如何对表单数据进行编码。它的编码方式有三种:

  • application/x-www-form-urlencoded编码是以name=value键值对为基础,以&连接;
    此为默认值。如果method属性为GET,则编码后的字符串会接到url的后面(其实用其它编码方式,GET的效果也是一样的)。
    如果method属性为POST,则编码后的字符串会被封装到HTTP协议的请求实体中,然后发送到服务器。
  • text/plain编码是以name=value键值对为基础,以\r\n连接;如果服务端的程序是PHP的话,使用此编码,如果method为GET,一切和其它编码一样,如果method为POST,则无论是$_GET、$_POST还是$_REQUEST都无法获取数据,为什么呢?因为PHP对于POST方法处理方法中根本就没有针对这种编码的处理函数。当然,我们可以通过php://input或$HTTP_RAW_POST_DATA获取POST过来的原始值。
  • multipart/form-data编码,这是最为特殊的编码;以其Content-Type后面的boundary为分隔符,将各个控件的值包含的请求实体中。

对于POST请求,一般来说用默认的application/x-www-form-urlencoded就可以了。但是如果有文件控件(type=file)的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain,且没有显示),name(控件的name)等信息,并加上分割符(boundary)。

method 属性

Form的method属性支持POST和GET方法。默认为GET提交。
GET方法用于信息获取,而且应该是安全的和幂等的。所谓安全指该操作用于获取信息而非修改信息。换句话说,GET请求一般不应产生副作用。相当于SQL中的SELECT操作。所谓幂等指对同一URL的多个请求应该返回同样的结果。比如sina网中点击某一个新闻页面,不同的时候返回应该是同一篇文章,如果后台有修改这条新闻,用户所看到的内容不同,但是我们还是会认为这是幂等的。

POST方法表示可能修改变服务器上的资源的请求。这里的修改包括在服务器上增加资源,修改已有资源或者其它修改类型的操作。

虽然method只支持这两个方法,但是HTTP协议还定义了一些其它的方法:
比如PUT方法,它表示完全替换或更新一个已经存在的资源或创建一个新的资源。PUT与POST的差别是这是一个完整的修改,不存在只修改部分。比如DELETE,它表示删除一个资源。

只是,在实际应用中,为了图方便,我们经常使用GET方法实现修改操作,因为这样我们不需要创建表单,如此而已。