作者归档:Young

MySQL Errno 28解决方案

昨天下午组里的同学跟我说数据库不能更改字段了,原本这台CentOS的机器工作很久都还还算正常,于是过去看了一下,发现MySQL在执行SQL之后报错,类似:

即提示错误码为28,告知用户无法创建表格。

错误码28第一反应就是磁盘空间不足,之后查看了df -hl查看了磁盘空间,发现MySQL所在的分区挂载的磁盘空间余量还有70%之多,之后查看是否是因为/tmp目录已满(即my.cnf中配置的tempdir)导致的,结果发现/tmp挂载的分区也有不少剩余空间,最后一想是不是有可能是inode已满导致的无法创建新文件的问题,使用df -i查看inode使用情况,发现inode使用已经达到了100%。

既然如此,那么整个事情也就明了了,磁盘空间已满不仅仅是物理空间上的已经使用完毕,也包括inode的使用情况,inode个数使用完毕之后,就不会有空间留给新文件用于记录文件信息了,自然也就不能创建文件了。关于inode,可以阅读阮一峰老师的《理解inode》这篇博文,清晰易懂。

解决问题的话,自然是要找到用尽inode的元凶,一般来说,小文件过多都是引起这个问题的主要原因。检查了这台数据库机器的进程,发现居然有有一套PHP在运行,查看了下php.ini之后,发现session的配置上,目录层级很深,运行了这么长的时间,session文件已经多到让人无语的程度,那么剩下的事情就好解决了,因为这台机器当前的服务不需要session的支持,直接干掉全部session文件即可。

小结一下,当MySQL出现28的错误码的时候,可以考虑:

  1. 检查磁盘空间
  2. 磁盘空间足够,检查临时目录空间大小
  3. 检查inode是否还有剩余

不得不说,这个事情并不是第一次看到,那么下次再出现磁盘无剩余空间,可以再看看是不是inode已满。

CentOS装机

最近想要做一些实验,无奈自己手头上没有富余的机器,看到好几个同事都自带电脑,没有用公司发的台式机,于是打算用这些台式机来做做实验。

公司本身是有完整的LAMP/LNMP环境安装包的,但是基于一些原因是不能使用的,整套环境只能自行安装,综合了一下决定安装如下软件:

  • CentOS 6.5 64位(可以考虑使用 北理工 的源,速度很快)
  • Nginx 1.2.7
  • PHP 5.4

装机其实是一个很无聊的过程,然而每次都能出现新的状况,真是让人抓狂,写过好几次这样的笔记,但是这次却又遇到了各种情况。

CentOS

启动项问题

安装CentOS已经变得极为简便,由于安装的是公司的台式机,直接用UltraISO或者直接用dd将镜像写入U盘,再通过GUI完成安装即可(参考此处),不过这次用U盘安装倒是出了个不大不小的问题,即安装之后只要拔掉U盘就无法启动。

这个问题首先感觉应该是引导项写入的问题,前期安装的时候一阵无脑的下一步点选,没有注意到写入的设备居然是U盘,而且这台机器U盘被识别成了/dev/sda,并不是意想中的/dev/sdb,那么单纯把启动项写入/dev/sdb,也就是实际的机器磁盘之后仍然是不能启动的,因为启动之后机器硬盘就被识别为/dev/sda了……

关键地方在于设定写入的磁盘的时候,点击更改设备按钮(如果你用的是中文安装环境的话),同时还要设定BIOS驱动器顺序这一项目(这里是一个折叠的选项),将驱动器设定为机器磁盘,比如安装的时候U盘是/dev/sda,那么这个项目就要设定为/dev/sdb,这样之后的安装才能正确的完成,机器才会能够启动。

远程桌面

作为Server来说是不需要GUI界面的,但是首先来说,为了方便实验,同时后期可能会安装Oracle数据库,那么一个图形界面还是很需要的,安装的时候可以选择Basic Server,同时自行设定软件界面,在桌面选项卡中选择上需要的桌面软件,我自己是勾选了KDE以外的所有项目。

GUI界面虽好,但是好几台机器放在脚下,每台机器再接一个显示器,还得有键鼠等设备,我的桌面肯定是放不下了。这时候就需要用上远程桌面了。

因为是做实验,选择了一个自己觉得简单易用的远程桌面软件TigerVNC

安装上来说非常容易,使用yum就可以:

这个软件的配置文件也是很简单,编辑/etc/sysconfig/vncservers,设定一下即可

简单来说就是设定第1个可登陆用户为root,同时设定分辨率为1024X768。

之后su到root下,通过vncpasswd设定登录所需的密码,之后通过客户端连接的时候需要通过这个密码登录,之后通过vncserver启动服务,这个软件也把自己注册成了服务,可以考虑使用service启动。

连接的时候需要使用端口,这里比较有意思的是这个软件监听的端口与你设定的用户编号有关,也就是用户1是5901,用户2是5902.

连接的客户端可以考虑直接使用Chrome的VNC Viewer扩展

VNC Viewer

再也不用在桌面上摆上一堆显示器键鼠什么的了。

VNC Viewer connected

PHP

PHP真是没太多麻烦的地方,然后在装libmemcached的时候发现1.0.18版本的libmemcached依然没法在我的CentOS 6.5的机器上成功的安装,没想到上次在Ubuntu上配环境遇到的问题在又遇到了一次,老办法,换1.0.16版本解决问题。

其他

测试的机器使用路由器串联起来的,只需要在路由器上使用一个简单的端口转发配置(家用路由器应该都有),将制定的端口请求绑定到各台路由器已连接的机器上即可。

端口转发

SSH的话需要多监听一个端口,CentOS的话修改/etc/ssh/sshd_config,解除对Port 22这一行的注释,同时加上想要监听的端口即可,即增加一行Port your-port,之后重启sshd服务。

同时配置上一条端口转发规则即可,之后用

即可。即所有的请求都发向路由器IP就好。

九月

九月

好像最近事情有点多,9月真是今年最忙的一个月了。

工作

同部门换组之后开始接触业务工作。

自己之前给大牛打杂,做点边边角角的工作,完全不用和PM还有运营的同学打交道,每天主要任务就是开心的写代码和折腾东西。

换组之后安心写代码的日子一去不返,每天的工作除了写代码之外还要做很多的沟通工作,沟通工作真是巨大的挑战,每天花在这上面的时间比写代码的时间多了很多,一段时间内觉得还是很困惑,每天的写代码工作几乎都要从下班之前开始,感觉上自己技术提升不够快,加上睡眠质量不好,对自己比较不满意,脾气变得有些急躁,不过既然工作内容都是这样,那我就安心去做吧,学会沟通也算是涨姿势了。

干了几个月,感觉作为开发,想要做得好真是不容易。

简单小结一下在业务组工作的感觉:

  • 团队利益为先,不要轻易的接需求,跟PM不妥协,讲道理
  • 业务是结果导向,业务成功才算是没有做无用功,老板可能为过程喝彩,但是结果不成功一样没用
  • 技术真到家在业务上可以体现,没时间写好代码感觉是个不好的借口
  • 任务拆解先行,没有任务拆解不能开始开发工作,否则留坑无数,越是紧急的项目越是要拆解得彻底
  • 风险及时上报,有问题快解决总比瞒着好,最多被批评一下,总比项目失败要好
  • 需要多想想业务的完整逻辑,对业务逻辑了解可以避免陪PM无谓的试错
  • 做事要有根据,口头需求不作数,临时变更需求不作数

项目

9月负责的3个项目是自己负责去评估工作和人力的,一个项目是和两位正式同学,一个项目是三位正式同学+两位实习生同学,还有一个也是两位正式同学。

同时开展两个项目真心难度很大,每个项目都需要协调人力,同时自己也要投入开发,拆解工作难度比较大。

难度大的原因是自己对工时的评估还是有些欠缺经验,对自己的工作时间评估能做到很准确,但是带上其他同学的话就感觉比较困难。

期间leader领我们玩了一个简单的游戏,让大家用扑克牌的点数评估一个工作时间,玩完之后明白其实完全可以让项目参与的同学一起来评估他们的工作时间,每位同学需要根据PRD评估出每一个功能点的具体工时。评估工时看起来消耗时间,但是自己认为这个时间是值得的,评估的过程中大家都能知道所有的功能点,如果突然有同学陷入困境或者请假的时候马上能投入人力开工协助,减少因为大家互相不知道功能点造成人力闲置的情况,保证项目能够按期完工。

大家评估出来的工期其实还是会有偏差,有时候过度乐观,有时候留了过度的buffer,这时候作为项目负责人就需要解决这些问题。对于大家估计出的工时长的工作需要特别注意,这时候可能会需要去和PM确定这个模糊的需求,让PM更明确一些。之后按照大家排期最合理的认领工作。实习生同学的使用可能需要注意,虽然现在的实习生同学能力都很厉害(至少比我自己……),但是实习应该是个欢乐的过程,不应该让实习生同学背负太重的项目压力,大家觉得有趣就好了,所以在使用人力上估计要* 0.x这个系数吧。

同时开发的时候考虑找到最短路径,同时循序渐进的找到各个时间点,每个时间点需要做出可体验或者可工作的对象,作为里程碑,周知需求方以及组内,让工作明确,也就是量化了吧。可以画个甘特图,感觉画完了甘特图里程碑的定义就简单了很多。

工时评估万万不能用上加班的时间,加班虽然是常态,但是确实是工作评估不应该评估的时间,每个项目都加班,直接硬抗,最后估计整个组的人都要离职了吧,还是大家开心的工作下去吧。考虑每天大家还要刷微博买东西看帖子吃午饭睡午觉,工时还是6小时一天来算吧。

技术

惭愧惭愧,我的MySQL还是没怎么学啊,每天回来倒头就睡,学习不够努力,需要批评。

还有一堆堆着的PPT/PDF,哎……

生活

太糟糕,说好的早睡早起完全没做到,睡眠不足引起肥胖与急躁,古人诚不余欺也……

貌似上个月去挂了几瓶,感觉还是有点虚,不太想要运动,前些日子减下来的肥肉似乎又长回来了,后面天气又更冷了,希望体重能够维持现状不要恶化了。

月初给母上大人置办了个交通工具(刚好拿到驾照……),上下班终于不用怕风吹雨打,早上也不用去赶那个坑爹的公交车了,自己为人子女,总算做了件让自己小高兴的事情。不过一看到空了的银行卡……哎,我退下努力学习工作了……

CI连接Oracle 11G数据库

CI连接Oracle 11G数据库

CI框架算是个人最喜欢的PHP框架之一,易用性上没的说,还有完备的中文文档,不过大多数时候是搭配MySQL一起使用。

不过最近接触的一个项目使用的是Oracle 11G数据库,开发前给大家搭环境的时候发现连接有一些问题,主要来说是安装配置上的一些问题。

环境

  • CodeIgniter 2.2.0
  • Oracle 11G R2
  • CentOS 6.4
  • PHP 5.2

扩展安装

首先CI本身是能支持Oracle数据库的,在DB Driver的代码中可以明确地看到,下面需要的就是安装oci8扩展了。

oci8扩展在安装上和其他的PHP扩展没有太多的区别,稍微有点区别的是需要下载安装一个Instant Client,Windows下的下载安装倒也还算顺利,然后Linux下的下载真是让人哭笑不得了,因为页面上的js错误,点击我同意按钮之后是不会出现熟悉的下载功能的,即各个链接仍然连接到本页,不过没有关系,看了下页面源码,还是找出了rpm包的实际下载链接(当然这个也是要注册Oracle的账户才能下载的)。

http://download.oracle.com/otn/linux/instantclient/112010/oracle-instantclient11.2-basic-11.2.0.1.0-1.x86_64.rpm

同时还需要安装devel包否则在编译扩展时会出现找不到头文件的情况。

http://download.oracle.com/otn/linux/instantclient/112010/oracle-instantclient11.2-devel-11.2.0.1.0-1.x86_64.rpm

之后就是常规的phpize && configure && make && make install了。

多说一句,如果通过rpm包安装了sqlplus之后不能使用,出现诸如:

sqlplus64: error while loading shared libraries: libsqlplus.so: cannot open shared object file: No such file or directory

的问题时,可以考虑通过:

export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib:$LD_LIBRARY_PATH

的方式来解决。

CI配置

下面来看在autoload配置文件中已经配置了autoload database配置的情况下CI的配置。

网上对于CI的配置主要区别在hostname这一个项目,有写成tnsnames.ora样式的,这个自己没实验成功,最后读了一下CI连接部分的代码,确定了连接中hostname配置应该是:

//数据库IP:数据库端口/数据库名称

最终连接成功的配置如下:

$db['default']['hostname'] = "//192.168.1.200:1521/db200";
$db['default']['username'] = 'learn';
$db['default']['password'] = '123456';
$db['default']['database'] = '';
$db['default']['dbdriver'] = 'oci8';

db200是dbca安装数据库时指定的名称。

环境搭好之后开发自然是要开始了。

以上。

又写了一个Hello world

又写了一个Hello world

近期有两天没有需求的日子,下周leader说让我去和前端学习一下,不过要先写个通关作业简单了解一下js。于是花两天时间又写了个Hello world。

简单记录一下,代码包含大量的调试语句,暂时不贴代码,后期还得试着填坑,写出一个完善的hello world。

要求

这个通关作业要求主要有下面一些东西:

  • 用Node.js自己实现一个简单的Http服务,实现BigPipe输出页面
  • 通过$Import加载js依赖模块
  • 通过register方式注册js模块
  • 实现自定义事件的支持,以及广播与事件代理

时间所限,自己只在chrome上完成了测试。

实现

整体设计

虽然是个Hello world,但是还是简单的思考了一下结构,大致的流程如下图:

流程图

Http服务

Node.js的Http模块的使用例子几乎是学习Node.js各类教程的标配了(比如七天学会Node.js……),实现的过程中基本上也是沿用了基本的写法。

其实感觉直接使用Express完成。

加载依赖模块

js代码如果能够把每一个部分代码拆分出来单独开发,只加载所需模块,那么对于开发维护,以及网络开销以及用户的体验上个人觉得都是有很大的帮助。自己理解是这一方式可以在浏览器端完成(比如requirejs最近同学推荐的seajs),也可以在服务器端通过主动的合并成单一文件返回给用户。

作业里面的方式是通过在服务器端合并的方式进行的。

由于对Node.js的异步编程思想并没有完全掌握,原先希望的通过异步的加载依赖文件的方式实现了一个下午也没有实现,眼看deadline就要到了,只能换成递归的方式进行处理,依赖文件首先读取并输出。

中间使用了UglifyJS2先对代码进行压缩操作,减小返回数据的大小,顺路去掉注释,简化匹配$Import语句使用的正则表达式。

在所有依赖完成读取之后,添加业务逻辑代码。

BigPipe

BigPipe工作中经常接触,这里的实现并没有特别之处,仍然是首先输出骨架,之后输出各个Pagelet。

具体来说这里使用了Node.js提供的信号功能,骨架输出完成之后会发出骨架已输出(设为skeleton_ready),同时计数器设定为Pagelet的数目。之后监听这一信号的各个Pagelet开始执行计算,完成之后直接输出用于渲染的<script>标签。骨架部分同时会监听Pagelet输出完成信号(设为pl_ready),之后计数器-1,当计数器为0时输出封闭标签</body></html>

Node.js通过repsonse对象的write方法返回值就能确定缓冲区是否已经刷新(参见文档),类似的,通过PHP实现的话还需要手动的进行ob_flush && flush。

从页面代码上看,大致是这样的一个效果:

代码效果

register

这里方法名任意,register的意义在于将当前的Pagelet(以下简称pl)的业务代码加入到当前运行环境中,register作为一个方法,第一参数为模块名称,也就是代码的路径,第二参数即为对应的回调方法。

register方法根据参数1,将回调方法绑定到指定的节点上,例如当前js对象的名称为Xe,pl的名称为pl.index.top,回调方法为func1(){...},那么在register操作完成之后就可以通过Xe.pl.index.top()调用func1(){...}

所有的依赖模块都通过这一方式进行组织。

自定义事件

对于自定义事件,目前了解到的应用场景,主要是单个pl中的模块之间的通信,实现上简单的通过保存自定义事件以及对应的回调方法的对应关系,通过对象的call方法调用自定义事件对应的回调方法。

为了能让回调能够异步的执行,还需要使用setTimeout方法。

广播

广播用于pl之间的通信,实现方式与自定义事件类似,但是不同点在于,广播中是通过频道对象调用回调方法,在每个频道中维护广播事件与回调之间的关系。

同理,也需要结合使用setTimeout方法。

使用上,每个模块都需要import这一个频道,同时向这个频道订阅指定的事件,绑定对应的回调方法。

事件代理

目前事件代理做法是将事件绑定到pl的顶部节点中,同时阻止事件进一步冒泡,由pl的顶级节点处理。

每个事件代理上都有一个对象维护回调方法与节点的对应关系。自己的实现中所有的节点绑定方法都会绑定一个共有的事件处理方法,在这一个方法中获取节点类型以及事件信息,之后调用具体的事件处理回调方法。

Todo

  • js依赖文件的异步加载

其他

有关静态服务器的实现,读了@朴灵大神文章《Node.js静态文件服务器实战》感觉有些启发。