Mysql SpockProxy 架构和配置

最近想架构一个水平shards架构设计,暂时还是选定Mysql SpockProxy。这个在性能上还是可以的。现在就简单介绍一下我是如何架构和配置。
首先去官网去下载Mysql SpockProxy,接下就是安装和配置了。

./autogen.sh
./configure && make
[code]
进入安装目录。老套路到bin中,这里我写一个shell脚本。这个脚本如下:
[code]
/usr/local/spockproxy/sbin/spockproxy --proxy-address=192.168.1.46:3325 --admin-address=192.168.1.46:3324 --partition-info-host=192.168.1.46 --partition-info-database=pn_cluster --db-user=btoc365 --db-user-password=123456

这样子这个服务就可以起来了。
重点在配置了,这会好好细细分析一下
看到上面配置有人会说为什么是这样子。
我就把这个服务结构图放进去一看大家就明白了。
spockproxy
这个服务代理逻辑都放到这张数据结构图中。
想必大家看了应该有所了解吧
这里我还是去这三张表给说明一下:
1.shard_database_directory
包含的主机名列表,数据库名称,端口,定义数据库服务器,代理服务器将连接到斯波克.这些都是在生活的碎片(注意:如果你只是测试他们没有对seporate机只是给他们不同的DB名称)。

database_id
    auto-incrementing, unique ID
host_name
    hostname
port_num
    port number
database_name
    database name

2.shard_table_directory
定义哪些表和列名分区,应该被重定向到一个特定的数据库连接(状态='联合'),哪些不是(状态='通用')。

table_id
    auto-incrementing, unique ID
table_name
    table name
status
    federated (sharded) or universal (on one machine and replicated the all shards)
column_name
    column to federate on, or NULL if this table is consolidated
next_id
    the next id for this table (since auto_increment is different in the proxy)
increment_column
    the automaticly incremented column.

3.shard_range_directory
一个查找表用于定义列的ID(在shard_table_directory定义)和哪个数据库(在shard_database_directory定义)范围内发送的命令.请注意,范围是所有表中的相同,让你可以在表的连接在同一个分区

range_id
    auto-incrementing, unique ID
low_id
    low boundary of the range for this shard
high_id
    high boundary of the range for this shard
database_id
    database ID from database_list table

至于这三张表每个字段是英文大家很简单暂时不做翻译呵呵

基本这里我的这个介绍已经差不多了。
不过还是把相关几个重点最后说明一下。
说到这里有人会问这个shards全局ID是如何呢。

4.get_next_id
这是一个存储功能,将增加shard_table_directory.increment_column.它用于插入语句作为AUTO_INCREMENT更换由代理.但你也可以调用它自己获得一个或多个ID为您的表的.

SELECT get_next_id('users', 10);

上述将返回表中的下一个ID的人可用,它增加了10.它总是返回一个整数,如果你问10开始在给定之一,使用下一个9.
其实这一步就是在你的数据库增加一个自定义函数;
这个SQL是这样子以及这三张表数据结构如下:


CREATE TABLE `shard_database_directory` (
  `database_id` int unsigned NOT NULL auto_increment,
  `host_name` varchar(255) NOT NULL,
  `port_number` int NOT NULL default '3306',
  `database_name` varchar(255) NOT NULL,
  PRIMARY KEY  (`database_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

CREATE TABLE `shard_table_directory` (
  `table_id` int unsigned NOT NULL auto_increment,
  `table_name` varchar(255) NOT NULL,
  `status` enum('federated','universal') NOT NULL default 'universal',
  `column_name` varchar(255) default NULL,
  `next_id` bigint(20) default '0',
  `increment_column` varchar(256) default NULL,
  PRIMARY KEY  (`table_id`),
  KEY `name_status_column` (`table_name`,`status`,`column_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;

CREATE TABLE `shard_range_directory` (
  `range_id` int unsigned NOT NULL auto_increment,
  `low_id` bigint(20) NOT NULL,
  `high_id` bigint(20) NOT NULL,
  `database_id` bigint(20) NOT NULL,
  PRIMARY KEY  (`range_id`),
  KEY `id_range` (`low_id`,`high_id`,`database_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;

delimiter $$
DROP FUNCTION IF EXISTS get_next_id $$
CREATE FUNCTION `get_next_id`($table varchar(255), $number_needed integer) RETURNS bigint(20)
    MODIFIES SQL DATA
BEGIN
  DECLARE $next_id bigint;
  IF EXISTS(SELECT * FROM shard_table_directory WHERE table_name = $table) THEN
    SELECT next_id INTO $next_id FROM shard_table_directory WHERE table_name = $table;
    UPDATE shard_table_directory SET next_id = next_id + $number_needed WHERE table_name = $table;
    RETURN $next_id;
  ELSE
    RETURN NULL;
  END IF;
END

$$
delimiter ;

启动参数介绍

--proxy-address
    代理服务器地址
--admin-address
    代理服务器管理查询地址
--partition-info-host
    代理服务器主机读取分区信息
--partition-info-database
   代理服务器主机读取分区数据库名
--db-user
    代理服务器主机读取分区数据库用户名
--db-user-password
    代理服务器主机读取分区数据库用户密码

./spockproxy --proxy-address=127.0.0.1:3325 --admin-address=127.0.0.1:3324 --partition-info-host=database_name --partition-info-database=database_universal_production --db-user=database_user --db-user-password=abcdefg > ./spockproxy.log 2>./spockproxy.err

注意一下。在上面创建那个自定义函数可以不能建。其实这个很简单。

show variables like '%function%';
+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | OFF   |
+---------------------------------+-------+

set global log_bin_trust_function_creators=1;
flush privileges;

+---------------------------------+-------+
| Variable_name                   | Value |
+---------------------------------+-------+
| log_bin_trust_function_creators | ON   |
+---------------------------------+-------+

如果你想mysql启动后就可以把这个打开的话,可以在my.cnf 修改 log_bin_trust_function_creators=1

配置到这个已经是可以大功告成了。

接下来你下载这个包中目录下面sample中有三个SQL文件有一些测试数据这样让你可以更新去了解这个水平切分代理一个工作情况和一些底层配置。
相关对于这个开源水平切分代理服务器先讲到这里。接下来还会对于这个开源软件更加细的分析和讲解相关性能方面。

置顶文章! 继续阅读?

Mac 系统中强制退出应用程序的快捷键

mac osx
Mac 系统虽然很稳定,但有时候也还是会有个别应用程序失去响应的情况出现,很多 Mac 初学者遇到这种情况往往不知所措,只好重新启动整个系统,其实完全没必要这样,你只需要强制退出这个应用程序即可。方法非常简单,直接按快捷键 command+option+shift+esc(要多按几秒钟,直到退出)。
cmd+option+esc

另外,你也可以按快捷键 command+option+esc 或者点击系统菜单栏上的苹果——强制退出应用程序,调出强制退出应用程序的菜单,在菜单里自己选择想要强制退出的应用程序。

置顶文章! 继续阅读?

Mac OS X 10.6.8更新升级为Lion操作系统准备

升级这个版本让我有点小麻烦一把,由于自己也是追求朝流,与是在6.24刚出来我就采用软件更新方式去更新,一切正常,不过在安装中在写入文件时一直卡在那边的,我试了两三次还是一样的。不知有没有这样朋友碰到这个问题。第二天采用官方那个更新包dmg,更新成功了。
正在为lion更新做准备了。哈哈。
Mac OS X 10.6.8 更新内容如下:
改进了 Mac App Store,以便 Mac 升级到 Mac OS X Lion
解决了可能导致“预览”意外退出的问题
增强了对 IPv6 的支持
增强了 VPN 的可靠性
可识别并移除 Mac Defender 的已知变体
Mac OS X 10.6.8 更新
我的机器

置顶文章! 继续阅读?

mongodb用mapreduce时临时collection删除


最近用mongodb来统计网站日志结果还是发现这个效果蛮好的。特别是当中mapreduce相当不错。有点像hadoop中mapreduce.
但是在使用中发现这个处理数据在临时collection中。每次统计好都会生成一些临时collection,这回让我头痛一把。结果还是让在官方一些论坛中找到一个shell脚本:

./mongo 192.168.0.21/logservice -ubtoc365 -pxxxxxx
function f() {
    var names = db.getCollectionNames();
    for(var i = 0; i < names.length; i++){
     if(names[i].indexOf("tmp.mr.") == 0){
      db[names[i]].drop();
     }
    }
   };[function 定义]
f()[function 调用]

轻轻松松操作处理这些没有用的临时collection。
当然说明一点你的定义 function名字采用任何什么都可以的。这个shell跟我们写客户端js完成一样。这也是mongodb一大特征。
今天先说到这里,谢谢来看我写的blog.

置顶文章! 继续阅读?

iPhone Developer Program 申请流程及亲身体验

developer iso program
1.注册一个apple id,如果已经有了。可以直接采用这个apple id,来申请Developer Program咨格,申请Developer Program可以参考,在这里我不详细去介绍Developer Program时所要填写资料。
我也按照以上步骤去做。可惜就是发国际传真让人麻烦了一把。先是采用网上所说采用一些简便方法去做,像给写信到 chinadev@asia.apple.com,然后把自己填好parchase form 电子文件发给他们和用免费传真方式发给他们结果一等就是四五天。后来一直没有什么回复。这个时间给我发了封邮件
这个邮件是:

Dear songfu zhang,
In reviewing your enrollment, we noticed that you have not yet purchased your iOS Developer Program. You can complete your purchase now through the Apple Online Store.
If you have any questions, please contact us.
Best regards,

Apple Developer Support

由于英文不是太好翻译了一下。结果让说可以传真没有收到还有是你还没有developer progame开发计划,所以这时侯有点郁闷。后来还是想想花点钱,用一个即时传真方式直接发那边可以直接收网站Faxflesh
2.按照上面这个网站我就试试这个即时传真,因为要付费,大概是需要1.49$,其发送步骤比较简单
输入对方苹果传真+1(408)862-7602
然后到paypal支付这个费用后就可以把你的传真发到对方去。
我就按照发传真步骤把传真也成功发送到对方顺便说一下这个时间在中国晚上10点多。然后就是去睡了。
3.接下来早上一起来就是直接收到一个短信,是一个99$扣款。看到这个消息。才有点欣慰了一下。而且也为苹果这种高效率工作向他们表示敬意。
同时也收到他们给我邮件是这样的。

Dear songfu zhang,
Thank you for joining the iOS Developer Program. You now have access to a comprehensive set of development tools and resources to assist you in developing innovative apps.
Please feel free to contact us if you have any general questions or require assistance.
Best regards,

Apple Developer Support

看到这个说明我已经成功加入IDP计划。
接下来收到一个苹果订单扣款几封邮件和几封itunes connects邮件后我认为已经成功了。
心里一直有点还是有点不是很妥。然后这个时候我就拨打亚洲苹果中心服务热线。他们说你已经成功加入这个计划。我就问他们按照一个流程我应该有收到一个激活码邮件。他们回复说有些我们直接给开发客户开通的。听他们这样一说我就放心了。
最后还是表示敬意他们工作效率确实是很快。从我发传真就是4个小时左右。就帮我开通这个服务。呵呵。

申请IDP时的注意事项:
1.地址要写申请信用卡时的账单地址
2.一般来说saler名都是信用卡持卡人的名字
3.收钱卡由于在公司向个人汇款,所以银行那边可能会监管,选银行前提前打听清楚,不要再出现钱到了拿不到的问题了
4.要想快速开通服务还是用付费传真
5.除了签名,如无意外情况全用英文或拼音

置顶文章! 继续阅读?

(Mac OSX Snow Leopard)上快速搭建MogileFS 2.x测试环境

最初试验MogileFS好像是05年初了,从那开始一直看它的代码,前年作painiu.com(sns交友社区,现有运营不当已关闭)的时候就加入了对MogileFS的支持,作为一个备选的Storage Provider实现. 但是投入生产环境中.好在使用Storage接口, 从FileSystem切换MogileFS也非常简单…

决定在自己的MacBookPro上搭建一下,在此记录一下,省得以后又忘了.

1. 安装MogileFS及其相关的CPAN模块

zhangsf$ sudo cpan -i BSD::Resource
zhangsf$ sudo cpan -i MogileFS::Client
zhangsf$ sudo cpan -i MogileFS::Server
zhangsf$ sudo cpan -i MogileFS::Utils
zhangsf$ sudo cpan -i MogileFS::Client::FilePaths

好了,必要的软件都安装完毕

BTW, 我是懒人,所以用cpan迅速解决一切,
虽然也可以直接从danga.com下载或者svn co, 不过, 有必要那么烦么…

2. 安装数据库
可以通过安装Store::Sqlit来作一个纯测试的环境,但是最好还是选择mysql

zhangsf$ mogdbsetup

按照提示修改数据库,或者干脆 mogdbsetup –yes
会生成一个mogilefs数据库.

3.配置tracker(mogilefsd)

建立测试环境:

mkdir -p /usr/local/mogilefs/conf

创建 /usr/local/mogilefs/conf/mogilefsd.conf, 内容如下:
#pidfile = /var/run/mogile/mogilefsd.pid
daemonize = 1
# Database settings
db_dsn = DBI:mysql:mogilefs:host=127.0.0.1
db_user = mogile
# You must insert your password here!
# db_pass = __PASSWORD__

# Network settings
conf_port = 7001
#listen = 127.0.0.1:7001,

# Storage
#
# UPDATE::原先老版本使用NFS,当前版本已经不再使用,可以忽略
# <strong>mog_root = /usr/local/mogilefs/mnt</strong>

# Plugins
#plugins = …

# Tuning knobs
query_jobs = 2
delete_jobs = 1
replicate_jobs = 1
monitor_jobs = 1
reaper_jobs = 1
#min_free_space = 100
#max_disk_age = 5
#node_timeout = 2
#old_repl_compat = 1
#default_mindevcount = 2

*_jobs用于定义各自工作线程数量, 上面是适合我的MBP的值,仅供测试而已.

把tracker启动起来

mogilefs -c /usr/local/mogilefs/etc/mogielfsd.conf

检查一下:
zhangsf$ mogadm check

Checking trackers…
127.0.0.1:7001 … OK

Checking hosts…
No devices found on tracker(s).

4. 配置存储节点(mogstored).
实际上mogilefs的存储节点本质是WebDAV(只不过最初是作为Perbal的wrapper),
因此Nginx,Lighttpd都可以作为存储节点.
还是记录一下mogstored的配置,其他如何配置网上很多:

mogstored的逻辑是host,device. 一个mostored服务对应一个host(逻辑上的),
所以你可以在同一台物理主机上通过监听不同的端口
同一台物理主机上通过IP别名来实现不同的host.

下面是创建一个服务:

创建 /usr/local/mogilefs/etc/mogstored.conf
#pidfile = /var/run/mogile/mogstored.pid
daemonize = 1

# Network settings
httplisten = 192.168.1.98:7500
mgmtlisten = 192.168.1.98:7501

# Storage
docroot = /usr/local/mogilefs/mogdata

# Server type
# Perlbal is the default
#server = perlbal
# But lighttpd is supported too
#server = lighttpd
#serverbin = /usr/sbin/lighttpd

# Tuning knobs
#max_conns = 10000
#opt_iostat 1

启动节点服务
$ mkdir -p /usr/local/mogilefs/mogdata
$ mogstored -c etc/mogstored.conf

将存储节点追加到tracker, 命名为storage1

zhangsf$ mogadm host add mognode1 –ip=192.168.1.98 –port=7500 –status=alive

zhangsf$ mogadm host list
storage1 [1]: alive
IP: 192.168.1.98:7500

上述输出表示节点已经被加入到tracker中.

现在,为存储节点增加存储设备device, 首先手动创建一个目录(生产环境下应该mount到一个独立的分区)

zhangsf$mkdir /usr/local/mogilefs/mogdata/dev1

添加到storage node:
zhangsf$ mogadm device add mognode1 1 –status=alive

检查一下结果:

Macintosh-2:mogilefs night$ mogadm check
Checking trackers…
192.168.1.98:7001 … OK
<code>Checking hosts…
[ 1] storage1 … OK

Checking devices…
host device size(G) used(G) free(G) use% ob state I/O%
—- ———— ———- ———- ———- —— ———- —–
[ 1] dev1 55.770 50.008 5.762 89.67% writeable 0.0
—- ———— ———- ———- ———- ——
total: 55.770 50.008 5.762 89.67%

这样,存储节点mognode1就完成了, 为了测试复制,可以再启动一个节点,
通过修改etc/mogstored.conf 为: /etc/mogstored2.conf

httplisten = 192.168.1.100:7500
mgmtlisten = 192.168.1.100:7501

# Storage
docroot = /usr/local/mogilefs/mogdata2

$ mogstored -c etc/mogstored2.conf

$ mogadm host add mognode2 --ip=192.168.8.100 –port=7500 –status=alive

….
(为storage2添加device, id 从2 开始)

现在2个存储节点已经搭建好了, 它们之间可以实现自动复制.

测试一下实际的工作:

Macintosh-2:mogilefs night$ mogadm domain add test
Macintosh-2:mogilefs night$ mogadm domain list
domain class mindevcount
——————– ——————– ————-
test default 2

添加一个文件
mogtool --trackers=192.168.1.98:7001 --domain=test inject test.txt

查看:
mogtool --trackers=192.168.1.98:7001 --domain=test extract
====================
完成.

////////////////////////////
UPDATE:
1.CPAN,DBI, DBD-Mysql 这些CPAN模块都要事先安装,不再赘述.
2.Device ID 是唯一的,一旦创建将无法删除,只能mark为dead. 所以,如果你某个磁盘坏了,你mark为dead, 后来又修好了,
那么你必须重新格式化并命名为新的device id, 不支持将device从dead变为alive.

置顶文章! 继续阅读?

Nginx设置默认虚拟主机(空主机头,默认主机头)

nginx的默认虚拟主机在用户通过IP访问,或者通过未设置的域名访问(比如有人把他自己的域名指向了你的ip)的时候生效

最关键的一点事,在server的设置里面添加这一行:

listen       80 default;

后面的default参数表示这个是默认虚拟主机。

这个设置非常有用。
比如别人通过ip或者未知域名访问你的网站的时候,你希望禁止显示任何有效内容,可以给他返回500.
目前国内很多机房都要求网站主关闭空主机头,防止未备案的域名指向过来造成麻烦。就可以这样设置:

server {
listen       80 default;
return 500;
}

也可以把这些流量收集起来,导入到自己的网站,只要做以下跳转设置就可以:

server {
listen       80 default;
rewrite ^(.*) http://www.painiu.com permanent;
}

置顶文章! 继续阅读?

低延迟信息推送:Nginx & Comet(nginx+push module)

nginx-push
服务器推送(Server Push)是高效的、延迟低的数据交换方式。如果数据发送端与接收端都在互联网中公开可见,可以使用PubSubHubbub或simpler Webhook等方法完成任务。但是如果数据接收方在防火墙内、在内网或它只是一个浏览器(只可以向外发送数据请求,无法处理传入的数据),则实现服务器推送就更难了。如果你有冒险精神,你可以建立一个反向HTTP服务器。如果你寻求可靠的解决方案,也许你要等待HTML5的WebSocket’s API特性了。但如果你需要即刻可以实现的解决方案,你可以妥协一下,使用异步推送模式来代替,你可以使用Comet,也被称为反向Ajax、HTTP服务器推送或HTTP流。

早在2006年Alex Russel提出了一个不坏的技术思路,那就是长连接(Comet)概念:从客户端发起并保持一个连接直到数据出现并传送(long polling),或者永远保持一个连接,通过它推送数据到客户端(streaming)。这两种方法的好处是数据传送非常及时。因此长连接技术广泛用于聊天应用(Facebook, Google, Meebo等)以及实现即时触发的机制。

将Nginx变成一个长连接服务器

实现长连接服务比较大的问题是特殊的隐形需求以及事件驱动web服务器能否高效处理众多的长连接。Friendfeed的Tornado服务器是一个标准应用级服务器的好例子。另外,感谢Leo Ponomarev的努力,你现在可以用nginx_http_push_module插件使你的Nginx服务器变身成为一台完全功能的长连接服务器。

使用自定义的一套框架结构,Leo的插件只提供两个对外的接口:一个是订阅者,一个是发布者。客户端连接Nginx服务器,创建针对一个频道的long- polling长连接并等待数据。同时,发布者只是简单的将数据使用POST方法提交给Nginx,插件收到数据后将它一个个发给等待的客户端。这表明发布者不需要直接传递数据,它只是一个简单的事件产生器!

还有更强大的功能是,客户端和发布端可以建立任意的channel,插件提供消息队列功能,也就是说Nginx服务器会在客户端断线的情况下临时保存消息。队列消息可以按照时间、等待列表长度或内存限制大小来失效释放。

Nginx配置例子(聊天室demo)

首先,你需要从源代码编译一个Nginx。解压源代码包,从GitHub获取插件的源码并放入Nginx的源码目录,然后使用下面的参数编译(./configure –add-module=/path/to/plugin && make && make install)。下一步,参考readme文件和协议文件,了解所有的参数选项。一个多客户端接收信息的配置例子如下:

> nginx-push.conf

# internal publish endpoint (keep it private / protected)
# 内部发布点(保证私有或不对外公开)
 location /publish {
     set $push_channel_id $arg_id;      #/?id=239aff3 or somesuch
     push_publisher;
     push_store_messages on;            # enable message queueing  # 打开消息队列
     push_message_timeout 2h;           # expire buffered messages after 2 hours # 2小时后消息失效
     push_max_message_buffer_length 10; # store 10 messages # 保存10条消息
     push_min_message_recipients 0;     # minimum recipients before purge # 清除前面接收人数目
  }  

# public long-polling endpoint
# 公开的长连接接收点
 location /activity {
     push_subscriber;
     # how multiple listener requests to the same channel id are handled
     # 每个channel  id能有多少客户端同时连接
     # - last: only the most recent listener request is kept, 409 for others.
     # – last: 只有最频繁请求的客户端能保持,其它连接返回409
     # - first: only the oldest listener request is kept, 409 for others.
     # – first: 只有最早连接的那个客户端可以保持,其它连接返回409
     # - broadcast: any number of listener requests may be long-polling.
     # – broadcast: 所有的客户端连接都会是长连接
    push_subscriber_concurrency broadcast;
    set $push_channel_id $arg_id;
    default_type  text/plain;
   }  

# internal publish endpoint (keep it private / protected)
# 内部发布点(保证私有或不对外公开)
  location /publish {
    set $push_channel_id $arg_id;      #/?id=239aff3 or somesuch
    push_publisher;
    push_store_messages on;            # enable message queueing  # 打开消息队列
    push_message_timeout 2h;           # expire buffered messages after 2 hours # 2小时后消息失效
    push_max_message_buffer_length 10; # store 10 messages # 保存10条消息
    push_min_message_recipients 0;     # minimum recipients before purge # 清除前面接收人数目
  }

# public long-polling endpoint
# 公开的长连接接收点
location /activity {
  push_subscriber;
  # how multiple listener requests to the same channel id are handled
  # 每个channel  id能有多少客户端同时连接
  # - last: only the most recent listener request is kept, 409 for others.
  # – last: 只有最频繁请求的客户端能保持,其它连接返回409
  # - first: only the oldest listener request is kept, 409 for others.
  # – first: 只有最早连接的那个客户端可以保持,其它连接返回409
  # - broadcast: any number of listener requests may be long-polling.
  # – broadcast: 所有的客户端连接都会是长连接
  push_subscriber_concurrency broadcast;
  set $push_channel_id $arg_id;
  default_type  text/plain;
}

编译配置好Nginx,并且启动它,我们可以建立一个简单的广播场景,一个数据发送广播方,几个订阅信息接收方来测试我们的长连接服务器。
每5秒钟数据发布端向Nginx发出新的事件,nginx将数据通过长连接转发给两个订阅的客户端。当消息发送到客户端,服务器会断开他们的连接,客户端会立即重连并等待下一次数据的到来。这样,就实现了Nginx将一个数据发布端到客户端的实时消息推送机制!

Long Polling, Streaming, and Comet in Production

Leo的模块还在开发期,还需要时间来稳定下来,但它是一个需要关注的项目。最近的更新计划都着重于bug修复,未来的计划里有描述要加入流的模式:代替现在每次数据获取后都要重连的情况(long polling),Nginx会保持连接,将数据一段段的实时传送给客户端。拥有这个功能后你能很方便的部署你自己的信息触发式API(例如:Twitter流)。

下载nginx-push module

置顶文章! 继续阅读?

解决MYSQL主从不同步的低级错误

昨天我们公司Mysql出现了两个意外:
1、一台MYSQL停止不了服务,那时可能还有程序在写入,我就先SLAVE STOP后,杀死MYSQL进程
结果,这台MYSQL无法恢复,导致innodb大量回滚,不断自动重新启动MYSQL
2、当把上面问题解决后,结果两台MYSQL无法主从同步了,显示如下状态:
Slave_IO_Running: NO
Slave_SQL_Running: Yes
查看日志如下:
090915 11:20:33 [ERROR] Error reading packet from server: Could not find first log file name in binary log index file ( server_errno=1236)
090915 11:20:33 [ERROR] Got fatal error 1236: ‘Could not find first log file name in binary log index file’ from master when reading data from binary log

其实这个问题是一个老生常谈的问题,解决办法也简单
一是权限问题,二是重新定位一下MASTER位置
可是一直解决不了…
最后,发现是由于logfile多写了一空格,如下:

change master to master_host='192.168.X.XXX', master_user='rep', master_password='password',master_log_file='binlog.000001 ',master_log_pos=8843;

实际应该是

change master to master_host='192.168.X.XXX', master_user='rep', master_password='password',master_log_file='binlog.000001',master_log_pos=8843;

3、第二步问题解决了,结果出现了
Slave_IO_Running: YES
Slave_SQL_Running: NO
并报出,有重复记录,无法插入的提示信息
解决这个问题,也有两个办法,一是在my.cnf里加
slave-skip-errors=1062
二是,直接执行
SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
跳过一步,不作同步,根据情况可以设置多步。

置顶文章! 继续阅读?

Varnish2.X.X 配置文件 分析

varnish
Varnish是一款高性能的开源HTTP加速器,所以自己网站也采用这个加速器。结果表明还是蛮不错的。现将配置说明如下:


backend painiu {
       .host = "113.107.103.XXX";
       .port = "81";
       .connect_timeout = 100s;
       .first_byte_timeout = 500s;
       .between_bytes_timeout = 200s;
}

acl purge {
       "113.107.103.XXX";
       "127.0.0.1";
}

sub vcl_recv {
       if (req.request == "PURGE") {
               if (!client.ip ~ purge) {
                       error 405 "Not allowed.";
               }
               lookup;
       }
       #unset req.http.X-Varnish;
       #unset req.http.Via;
       #unset req.http.Accept-Encoding;
       #unset req.http.Vary;

       if (req.http.host ~ "^(.*).painiu.com") {
               set req.backend = painiu;
               if (req.request != "GET" && req.request != "HEAD") {
                       pipe;
               }
               else {
                       lookup;
               }
       } 

       elseif (req.http.host ~ "^(.*).hi51.cn") {
               set req.backend = painiu;
               if (req.request != "GET" && req.request != "HEAD") {
                       pipe;
               }
               else {
                       lookup;
               }
       }
       elseif (req.http.host ~ "^hi51.cn") {
               set req.backend = painiu;
               if (req.request != "GET" && req.request != "HEAD") {
                       pipe;
               }
               else {
                       lookup;
               }
       }

       elseif (req.http.host ~ "^(.*).alirenren.com") {
               set req.backend = painiu;
               if (req.request != "GET" && req.request != "HEAD") {
                       pipe;
               }
               else {
                       lookup;
               }
       }
       elseif (req.http.host ~ "^alirenren.com") {
               set req.backend = painiu;
               if (req.request != "GET" && req.request != "HEAD") {
                       pipe;
               }
               else {
                       lookup;
               }
       }

       elseif (req.http.host ~ "^painiu.com") {
               set req.backend = painiu;
               if (req.request != "GET" && req.request != "HEAD") {
                       pipe;
               }
               else {
                       lookup;
               }
       }

       else {
               error 404 "Painiu Cache Server";
               lookup;
       }
}

sub vcl_hit {
       if (req.request == "PURGE") {
               set obj.ttl = 0s;
               error 200 "Purged.";
       }
}

sub vcl_miss {
       if (req.request == "PURGE") {
               error 404 "Not in cache.";
       }
}

sub vcl_fetch {
      if (req.request == "GET" && req.url ~ "\.(txt|js|html|htm|css|jpg|gif|png|swf)($|\?)") {
               set obj.ttl = 3600s;
       }
       else {
               set obj.ttl = 0s;
       }
}

sub vcl_deliver {
        remove resp.http.X-Varnish;
        remove resp.http.Via;
        if (obj.hits > 0) {
                set resp.http.X-Cache = "HIT";
        } else {
                set resp.http.X-Cache = "MISS";
        }
}

置顶文章! 继续阅读?

memcachedb1.2.0安装过程

根据memcachedb介绍、编译以及安装,试装memcachedb(centos5.4)。
BerkeleyDB页面上提供的是oracle的官方地址,但下载要注册。。。找朋友要了个4.6版本的装,装memcachedb-1.2.1-beta会提示:
configure: error: cannot find libdb.so in /usr/local/BerkeleyDB.4.7/lib(所以暂时放弃,选用1.2.0,一切安装很顺利)
看到memcached下载页面上写着:MemcacheDB 1.2.0 is released, for BerkeleyDB 5.1.19

1.装libevent

yum install libevent libevent-devel

2.装berkeley-db

wget http://123.196.117.14/db-5.1.19.tar.gz
tar zxf db-5.1.19.tar.gz
cd db-5.1.19/build_unix/
../dist/configure --prefix=/usr/local/BerkeleyDB
make
make install

#编译完成,将Berkeley Db运行库的路径添加到系统配置里面
有两种做法:

1.echo "/usr/local/BerkeleyDB/lib/" >> /etc/ld.so.conf
ldconfig
2.touch /etc/ld.so.conf.d/bdb.conf
/usr/local/BerkeleyDB/lib/
ldconfig

这一步原因主就是让你bdb动态共享库加入到系统当中,以上两种可以选一种呵呵。

3.装memcachedb,最新版是2008年12月份的,至今没有更新据说是已经比较稳定了。

wget http://memcachedb.googlecode.com/files/memcachedb-1.2.0.tar.gz
tar zxf memcachedb-1.2.0.tar.gz
cd memcachedb-1.2.0
./configure
make
make install
[code]

启动memcachedb
[code]
创建目录/www/mcdb_data
memcachedb -p 22222 -d -r -u root -H /opt/mcdb_data -N

用PHP连接memcachedb和连接memcache的代码几乎是一模一样的。

<?php
    $mcdb_host = '192.168.0.11';
    $mcdb_port = '22222';

    $mcdb = new Memcache;
    $mcdb->connect($mcdb_host, $mcdb_port);

    $mcdb->set('test','test');
    echo $mcdb->get('test');
?>

服务器重启后,$mcdb->get('test'),仍然可以获得值,证明不会丢失,测试完成:)

注意memcache中有依赖libevent.
安装方式有两种:

1.yum install libevent libevent-devel(centos安装升级命令)
2.手工下载编译然后在编译memcachedb时加入参数 --with-libevent=/usr/local/libevent***

memcachedb1.2.0安装过程介绍到此为止,有兴趣朋可以试我的说明安装一下,谢谢你来到我的博客。

置顶文章! 继续阅读?

用3G 版 iPad 变成全功能 iPhone 的应用

Phoneit-ipad
此前成功在 iPhone 3GS 上实现(单向) FaceTime 的开发团队 iPhoneIslam 今天带来了新作 Phoneit-iPad,据说这个是可以将 3G 版 iPad 完全变成一个全功能 iPhone 的应用,已经登陆 Cydia(源:http://apps.iphoneislam.com/),需要花20美金激活该应用。你要做的就是将一张普通的 SIM 卡(语音/数据二合一卡)插入 iPad 3G ,然后安装这个应用程序,并到 iPhoneIslam 官网将这个应用程序激活就可以了。

从 iPhoneIslam 官方发布的视频演示来看,功能上确实实现的非常完美,但目前我们还没有亲自测试,看今天有没有用3G版 iPad 的同事买来测试一下,嘎嘎。下面是视频演示以及常见问题回答:

关于 Phoneit-iPad 的常见问题:

需要准备什么?

一台运行着 iOS 4.3.3 固件的 iPad 1,一张普通SIM卡,20美金。

为什么要普通的 SIM 卡而不是 iPad 上用的数据卡?

因为 iPad 上用的那种是数据卡,不具备语音通话功能,反正就是要一张能打电话的卡。

为啥我安装了这个软件没啥反应?

必须要去 iPhoneIslam 官网激活之后才能使用。

为啥我编辑短信的时候神马都输入不进去?

只有第一次会出现这种情况,按enter之后就不会再出现了。

支持 iOS 5 不?

iOS 5 正式版出来之后会尝试开发,如果可以的话用户到时候可以免费升级,但没法保证一定行。

不能发彩信?

嗯,现在还不支持彩信。

能玩 FaceTime 不?

不能保证,这得取决于你的设备、运营商和你所在的国家。

能用蓝牙耳机打电话不?

不能,因为 iPad 1 不支持蓝牙干这事儿。

Linux tcp 状态查看

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

iPhone4 自动设置时间不准的确原因

自己买iPhone4已经快两个月了,港版已越狱,系统4.2.1,昨天注意到时间自动设置不准,慢了12小时左右,只能手动设置。还有点慢几分钟。问题还是没有解决。

我的电脑系统是Mac,时间是与internet同步的,时区设置是北京,与itunes同步还是不行。今天偶然发现问题解决了,小小的开心了一下。现在把方法分享给还没有解决的同学,还是分享一下吧!

1、iphone4时间设置——自动设置关闭
2、设置时区——北京或是上海,日期以当天日期为准
3、打开自动设置,这时时间是不准确的,不管它
4、打开定位服务、进入手机自带地图,让它自动定位,定位好后就可以退出了。现在看看时间是不是已经同步为当时的时间了,自动设置时间不准的问题解决啦!这是我自己的实验,已经成功了,我的手机自动时间已经准确显示了。开心一下呀。。。

用户工具 Useradd和Adduser 添加使用方法

添加用户工具有useradd和adduser ,这两个工具所达到的目的都是一样的,在Fedora 发行版中,useradd 和adduser 用法是一样的;但在slackware发行版本中,adduser和useradd 还是有所不同,表现为adduser 是以人机交互的提问的方式来添加用户;

除了useradd和adduser工具以外,我们还能通过修改用户配置文件/etc/passwd和/etc/groups的办法来实现;

当然我们也不要忽略一些发行版独有用户管理工具,比如Fedora 中有 system-config-users 工具;这个工具比较简单,点几下鼠标就能完成;

1、useradd 工具

useradd 不加参数选项时,后面直接跟所添加的用户名时,系统时读取添加用户配置文件/etc/login.defs和/etc/default/useradd文件,然后读取/etc/login.defs和/etc/default/useradd中所定义的规则添加用户;并向/etc/passwd和 /etc/groups文件添加用户和用户组记录;当然/etc/passwd和/etc/groups的加密资讯文件也同步生成记录;同时发生的还有系统会自动在/etc/add/default中所约定的目录中建用户的家目录,并复制/etc/skel中的文件(包括隐藏文件)到新用户的家目录中;

useradd 的语法:

usage: useradd [-u uid [-o]] [-g group] [-G group,...]

[-d home] [-s shell] [-c comment] [-m [-k template]]

[-f inactive] [-e expire ] [-p passwd] name

useradd -D [-g group] [-b base] [-s shell]

[-f inactive] [-e expire ]

当我们执行useradd 用户名 来添加用户时,我们会发现一个比较有意思的现象,新添中的用户的家目录总是被自动添加到 /home目录下,我们先举个例子;

实例一:不加任何参数,直接添加用户;

[root@localhost beinan]# useradd beinanlinux

[root@localhost beinan]# ls -ld /home/beinanlinux/

drwxr-xr-x 3 beinanlinux beinanlinux 4096 11月 2 15:20 /home/beinanlinux/

在这个例子中,我们添加了beinanlinux用户,我们在查看/home/目录时,会发现系统自建了一个beinanlinux的目录;

我们再来查看 /etc/passwd 文件有关beinanlinux的记录,也会有新发现;我们通过more 来读取 /etc/passwd 文件,并且通过grep 来抽取 beinanlinux字段,得出如下一行;

[root@localhost beinan]# more /etc/passwd | grep beinanlinux

beinanlinux:x:509:509::/home/beinanlinux:/bin/bash

从得出的beinanlinux的记录来看,以adduser 工具添加beinanlinux用户时,设置用户的UID和GID分别为509 ,并且把beinanlinux的家目录设置在 /home/beinanlinux ,所有的SHELL是 bash ; 我们再来看看 /etc/shadow、/etc/groups和/etc/gshadow 文件,是不是也有与beinanlinux有关的行;我们还要查看/etc/default/useradd 和/etc/login.defs文件的规则,看一下beinanlinux用户的增加是不是和这两个配置文件有关;我们还要查看 /home/beinanlinux目录下的文件,是不是和/etc/skel目录中的一样;

由此我们引出我们下面所要谈的内容:

useradd -D [-g group] [-b base] [-s shell] [-f inactive] [-e expire ]

1)/etc/default/useradd 配置文件的定义;

useradd -D [-g group] [-b base] [-s shell] [-f inactive] [-e expire ]

useradd 加-D参数后,就是用来改变配置文件 /etc/default/useradd的;

useradd -D [-g group] [-b base] [-s shell] [-f inactive] [-e expire ]

当-D选项出现时,useradd秀出现在的预设值,或是藉由命令列的方式更新预设值。可用选项为∶

-b default_home 注:定义用户所属目录的前一个目录。用户名称会附加在default_home后面用来建立新用户的目录。当然使用-d后则此选项无效。

-e default_expire_date 注:用户帐号停止日期。

-f default_inactive 注:帐号过期几日后停权。

-g default_group 注:新帐号起始用户组名或ID。用户组名须为现有存在的名称。用户组ID也须为现有存在的用户组。

-s default_shell 注:用户登入后使用的shell名称。往后新加入的帐号都将使用此shell.

如不指定任何参数,useradd显示目前预设的值。

实例二:

useradd -D 如不指定任何参数,useradd显示目前预设的值;

[root@localhost beinan]# useradd -D

GROUP=100

HOME=/home

INACTIVE=-1

EXPIRE=

SHELL=/bin/bash

SKEL=/etc/skel

CREATE_MAIL_SPOOL=no

我们看一下/etc/default/useradd 文件就明白了,应该和上面的输出是一样的;所以如果我们想改变useradd配置文件/etc/default/adduser 的内容,也可以用编辑器直接操作,如果你会用vi编辑器或者其它编辑器的话,这个应该不成问题吧;

实例三:

我想把添加用户时的默认SHELL /bin/bash 改为 /bin/tcsh ,则应该用下面的命令;

[root@localhost beinan]# useradd -D -s /bin/tcsh 注:把添加用户时的SHELL 改为tcsh ;

[root@localhost beinan]# more /etc/default/useradd 注:查看是否成功;

# useradd defaults file

GROUP=100

HOME=/home

INACTIVE=-1

EXPIRE=

SHELL=/bin/tcsh 注:成功;

SKEL=/etc/skel

CREATE_MAIL_SPOOL=no

这个-D参数的解说就这样了,也是比较简单,如果不会用命令,直接改参数配置文件总会吧;Linux解决问题是极为灵活的,就看我们怎么解决了,对不对?

2)useradd 添加用户;

useradd [-u uid [-o]] [-g group] [-G group,...]

[-d home] [-s shell] [-c comment] [-m [-k template]]

[-f inactive] [-e expire ] [-p passwd] name

新帐号建立,当不加-D参数,useradd指令使用命令列来指定新帐号的设定值 and使用系统上的预设值.新用户帐号将产生一些系统档案,用户目录建立,拷备起始档案等,这些均可以利用命令列选项指定。此版本为RedHat Linux提供,可帮每个新加入的用户建立个别的group,毋须添加-n选项。

useradd 可使用的选项为

-c comment 注:新帐号 password 档的说明栏 。

-d home_dir 注:新帐号每次登入时所使用的home_dir。预设值为default_home内login名称,并当成登入时目录名称。

-e expire_date 注:帐号终止日期。日期的指定格式为MM/DD/YY。

-f inactive_days 注:帐号过期几日后永久停权。当值为0时帐号则立刻被停权。而当值为-1时则关闭此功能,预设值为-1

-g initial_group 注:group名称或以数字来做为用户登入起始用户组(group)。用户组名须为现有存在的名称。用户组数字也须为现有存在的用户组。预设的用户组数字为1。

-G group,[...]

注:定义此用户为此一堆groups的成员。每个用户组使用”,”区格开来,不可以夹杂空白字元。用户组名同-g选项的限制。定义值为用户的起始用户组。。

-m 注:用户目录如不存在则自动建立。如使用-k选项skeleton_dir内的档案将复制至用户目录下。然而在/etc/skel目录下的档案也会复制过去取代。任何在skeleton_dir or /etc/skel的目录也相同会在用户目录下一一建立。The-k同-m不建立目录以及不复制任何档案为预设值。

-M 不建立用户目录,即使/etc/login.defs系统档设定要建立用户目录。

-n 预设值用户用户组与用户名称会相同。此选项将取消此预设值。

-r 此参数是用来建立系统帐号。系统帐号的UID会比定义在系统档上/etc/login.defs.的UID_MIN来的小。注意useradd此用法所建立的帐号不会建立用户目录,也不会在乎纪录在/etc/login.defs.的定义值。如果你想要有用户目录须额外指定-m参数来建立系统帐号。

-s shell 注:用户登入后使用的shell名称。预设为不填写,这样系统会帮你指定预设的登入shell。

-u uid uid用户的ID值。必须为唯一的ID值,除非用-o选项。数字不可为负值。预设为以/etc/login.defs中的UID_MIN的值为准,0到UID_MIN的值之间,为系统保留的UID ;

useradd 这么多的参数看上去头有点晕,我们如何用呢??其实很简单;一个参数一个参数的试一试不就明白了??这是最好的学习方法。实践是检验真理的唯一标准;

如果useradd 后面直接跟用户名,不加任何参数,表示添加用户时按事先/etc/default/adduser 和/etc/login.defs 添加新用户的配置文件的规则来添加用户;其实我们为了方便,也可以把这两个文件修改以适合我们添加用户需要;

useradd 为什么还需要那么多的参数呢?

原因很简单,主要是为了管理员方便管理用户。useradd 是灵活的,可以跳过/dev/default/adduser 和/etc/login.defs 两个配置文件中的规则来自定义添加用户;比如在用户的家目录,在/etc/default/adduser 中可能定义在/home目录下建立,如果我们的机器/home独立占一个分区,并且有点紧张,但我们又不想改变/etc/default/adduser 关于家目录的定义,这里我们就可以通过 adduser -d 参数把新增用户家目录定义到空间比较空闭的分区;

通过下面的几个例子,可能有助于我们理解useradd ,其实很简单~,学习也是这样,先从简单的入手,一步一步的走过来,没有什么难的~~

实例四:以/etc/logins.defs和/etc/default/adduser 默认的规则添加用户;

[root@localhost ~]# useradd longcpu

注解:如果useradd 后面直接用户名,表示系统读取 /etc/login.defs和/etc/default/adduser 配置文件,根本这两个配置文件所定义的规则来添加用户,比如用户的家目录哪里,用什么SHELL,UID和GID的分配… … 查看/etc/passwd的新增记录,然后根据 /etc/login.defs和/etc/default/adduser 查看新增用户是否符合这两个配置文件所约定的规则;

实例五:练习参数的使用;

[root@localhost ~]# useradd -c ChinaCpu longcpu 注:添加一个新用户amdcpu ,使用参数-c;

[root@localhost ~]# more /etc/passwd |grep longcpu 注:查看/etc/passwd 文件,并抽取longcpu的记录;

longcpu:x:510:510:ChinaCpu:/home/longcpu:/bin/bash

注:看上去是已经有amdcpu用户了;x是密码段;UID和GID 都是510,ChinaCpu表示是什么意思? 家目录位于/home/amdcpu,SHELL是bash ;

[root@localhost ~]# finger longcpu 注:我们查询一下amdcpu 用户的信息;

Login: longcpu Name: ChinaCpu 注:-c ChinaCpu 表示用户真实的名字或全名;

Directory: /home/longcpu Shell: /bin/bash

Never logged in.

No mail.

No Plan.

注解:这个例子,我们做了添加用户、查看/etc/passwd 的变化; 并且通过finger 来查询longcpu用户的信息,目的是理解参数-c的用处;

参数-c 后面的就是就是UID:GID后面说明文字,这段文字中包括用户真实姓名,办公地址,办公电话等,可以通过chfn 来更改,我们可以通过chfn 来修改用户信息,然后查看 /etc/passwd 的变化,再来用finger 来查询用户信息。几个工具组合练习一下,也容易忘记;

实例六:自定义用户的家目录、SHELL类型、所归属的用户组等;

添加用户longcpu,并设置其用户真实名字为ChinaCpu,其家目录在/opt/longcpu,让其归属为用户组 linuxsir、root、beinan成员,其SHELL类型为tcsh ;

[root@localhost ~]# useradd -c ChinaCpu -d /opt/longcpu -G linuxsir,root,beinan -s /bin/tcsh longcpu

注:添加用户longcpu ,真实名是ChinaCpu ,家目录设置在 /opt/longcpu ,是linuxsir,root,beinan 用户组成员, SHELL是tcsh ;

[root@localhost ~]# ls -ld /opt/longcpu/ 注:是不是自动创建了longcpu的家目录?

drwxr-xr-x 3 longcpu longcpu 4096 11月 4 22:30 /opt/longcpu/

[root@localhost ~]# more /etc/passwd |grep longcpu 注:查看 /etc/passwd 中是否有longcpu用户记录;

longcpu:x:510:510:ChinaCpu:/opt/longcpu:/bin/tcsh

[root@localhost beinan]# finger longcpu 注:查询longcpu用户的信息 ;

Login: longcpu Name: ChinaCpu

Directory: /opt/longcpu Shell: /bin/tcsh

Never logged in.

No mail.

No Plan.

[root@localhost beinan]# id longcpu 注:查询UID和GID 以及所归属的用户组;

uid=510(longcpu) gid=510(longcpu) groups=510(longcpu),0(root),500(beinan),502(linuxsir)

关于在添加新用户时用户组,添加用户时,如果不使用-n 参数,系统会自动建一个与用户名同名的用户组;

实例七:练习用户有效期限;

在本例中,我们主要来看看-e参数,这个参数还是比较重要的,是设定用户的帐号什么时候过期;

在本例中,我们添加了一个帐号,并且设置其帐号在 2005年11月04日之前是有效的,一旦过了这个日期,便停止其登录;

[root@localhost ~]# useradd -e 11/04/2005 cooler 注:添加用户cooler,并设置其有效期为2005年11月04日;

[root@localhost ~]# passwd cooler 注:设置用户cooler密码;

Changing password for user cooler.

New UNIX password: 注:设定cooler的密码;

Retype new UNIX password: 注:核实设定密码;

passwd: all authentication tokens updated successfully. 注:设置成功;

如何验证-e 是不是真的有效?我写这篇文档的时间是 2005年11月05号,所以添加这个cooler用户肯定是过期的,就是他有密码也不能登录;

有的弟兄会问,他把有效期的记录放在哪里了呢?其实我们在以前的文档中已经说过了,是写在/etc/shadow文件中了;

请参考: 《用户(user)和用户组(group)配置文件详解》

2、adduser 工具;

在Fedora 系统中,adduser和useradd 用法是一样的,但在 Slackware 系统中 adduser 是通过人机交互的方法来添加用户,其实和useradd 加各项参数来自定义添加用户所达到的目的是一样的,只不过在Slackware 中,useradd 是以人机交互的提问式的进行;这样我们没有必要知道那么多的参数,一样可以达到自定义添加用户;

[root@localhost ~]# adduser 注:运行adduser命令;

Login name for new user []: bluemoon 注:添加新用户 bluemoon

User ID (‘UID’) [ defaults to next available ]: 1200 注:用户的UID ,UID 是唯一的;如果有提示说被占用,就选比较大的UID ,比如1300

Initial group [ users ]: users 注:初始化用户组(或主用户组)为users,这个用户组也是可以自己定义的,但用户组必须存在,如果不存在,您可以用groupadd来添加

Additional groups (comma separated) []: root,beinan 注:附加用户组,这个也是自己定义的,多个用户组之间用,号分割;

Home directory [ /home/bluemoon ] 注:定义用户的家目录位置,也是可以自己定义的,比如/opt/bluemoon ;

Shell [ /bin/bash ] 注:所用SHELL ,此处用的是bash ;

Expiry date (YYYY-MM-DD) []: 注:用户的有效日期,如果不设置就直接回车,表示从不过期;如果设置就以2005-11-05这样的格式来输入;

New account will be created as follows: 注:创建的用户情况如下;

—————————————

Login name…….: bluemoon

UID…………..: 1200

Initial group….: users

Additional groups: root

Home directory…: /home/bluemoon

Shell…………: /bin/bash

Expiry date……: [ Never ]

This is it… if you want to bail out, hit Control-C. Otherwise, press

ENTER to go ahead and make the account.

注:在这里按回车就开始创建,如果认为这样不合理,就按CTRL+C 来中断;

Creating new account… 这样就创建好了;系统会自动提示我们修改用户的信息,比如用户的全名、房间号、电话等…… 以及用户的密码;

Changing the user information for bluemoon

Enter the new value, or press ENTER for the default

Full Name []: bluemoon Linux

Room Number []: 503

Work Phone []: 0411-8888888

Home Phone []: 0411-9999999

Other []:

Changing password for bluemoon

Enter the new password (minimum of 5, maximum of 127 characters)

Please use a combination of upper and lower case letters and numbers.

New password: 注:设置用户bluemoon的密码;

Re-enter new password: 注:验证一次;

Password changed. 注:设置密码成功

Page 1 of 121234510... 最后一页 »