Skip to content Skip to main navigation Skip to footer

Linux

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

SNMP(简单网络管理协议)用于收集设备内部发生的数据,如负载、磁盘状态、带宽之类。像Cacti这样的网络监控工具用这些数据来生成图标以达到监控的目的。

在一个典型的Cacti和SNMP部署中,会有一台或多台启用了SNMP的设备,以及一台独立的用来从那些设备收集SNMP回馈的监控服务器。请记住,所有需要监控的设备必须启用SNMP。在本教程中,出于演示目的,我们将在同一台Linux服务器上配置Cacti和SNMP。

在Debian或Ubuntu上配置SNMP

要在基于Debian的系统上安装SNMP代理(snmpd),请运行以下命令:

root@server:~# apt-get install snmpd

然后,如下编辑配置文件。

root@server:~# vim /etc/snmp/snmpd.conf

# 使snmpd 监听再所有接口上
agentAddress  udp:161
# 定义一个只读的 community 'myCommunity' 和源网络
rocommunity myCommunity 172.17.1.0/24
sysLocation    Earth
sysContact     email@domain.tld

在编辑完配置文件后,重启snmpd。

root@server:~# service snmpd restart

在CentOS或RHEL上配置SNMP

要安装SNMP工具和库,请运行以下命令。

root@server:~# sudo yum install net-snmp

然后,如下编辑SNMP配置文件。

root@server:~# vim /etc/snmp/snmpd.conf

# 定义一个使用 community 'myCommunity' 和源网络 172.17.1.0/24 的用户 'myUser'
com2sec myUser 172.17.1.0/24 myCommunity
# 将 myUser 加到 'myGroup' 组,定义组权限
group    myGroup    v1        myUser
group    myGroup    v2c        myUser
view all included .1
access myGroup    ""    any    noauth     exact    all    all    none

root@server:~# service snmpd restart
root@server:~# chkconfig snmpd on

重启snmpd服务,然后添加到启动服务列表。

测试SNMP

SNMP可以通过运行snmpwalk命令进行测试。如果SNMP已经配置成功,该命令会生成大量输出。

root@server:~# snmpwalk -c myCommunity 172.17.1.44 -v1

iso.3.6.1.2.1.1.1.0 = STRING: "Linux mrtg 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:31:23 UTC 2012 x86_64"
iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
iso.3.6.1.2.1.1.3.0 = Timeticks: (2097) 0:00:20.97
~~ 输出截断 ~~
iso.3.6.1.2.1.92.1.1.2.0 = Gauge32: 1440
iso.3.6.1.2.1.92.1.2.1.0 = Counter32: 1
iso.3.6.1.2.1.92.1.2.2.0 = Counter32: 0
iso.3.6.1.2.1.92.1.3.1.1.2.7.100.101.102.97.117.108.116.1 = Timeticks: (1) 0:00:00.01
iso.3.6.1.2.1.92.1.3.1.1.3.7.100.101.102.97.117.108.116.1 = Hex-STRING: 07 DD 0B 12 00 39 27 00 2B 06 00

配置带有SNMP的Cacti

在本教程中,我们将在同一台Linux服务器上设置Cacti和SNMP。所以,到刚刚配置SNMP的Linux服务器上去[安装Cacti][2]吧。

安装完后,Cacti网页界面可以通过“http://172.17.1.44/cacti ”来访问,当然,在你的环境中,请将IP地址换成你的服务器的地址。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

安装过程中Cacti的路径一般都是正确的,但是如有必要,请再次检查以下。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

在首次安装过程中,Cacti默认的用户名和密码是“admin”和“admin”。在首次登录后会强制你修改密码。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

添加设备到Cacti并管理

Cacti将根据先前配置的SNMP字符串注册设备。在本教程中,我们将只添加启用了SNMP的本地服务器。

要添加设备,我们必须以管理员登录,然后转到Cacti管理员面板中的控制台。点击 控制台 > 设备。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

那里可能已经有一个名为‘localhost’的设备。我们不需要它,因为我们要创建全新的图表。我们可以将该设备从列表中删除,使用“添加”按钮来添加新设备。

接下来,我们设置设备参数。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

现在设备已经添加,我们来指定想要创建的图表模板。你可以在该页面的最后部分中找到这块内容。

然后,我们继续来创建图表。

这里,我们创建用于平均负载、RAM和硬盘、处理器的图表。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

接口的图表和64位计数器

默认情况下,Cacti在SNMP查询中使用32位计数器。32位计数器对于大多数带宽图表而言已经足够了,但是对于超过100Mbps的带宽,它就无能为力了。如果已经知道带宽会超过100Mbps,建议你使用64位计数器。使用64位计数器一点也不麻烦。

注意: Cacti会花费大约15分钟来产生新图表,除了耐心等待,你别无选择。

创建图表树

这些截图展示了如何创建图表树,以及如何添加图表到这些树中。

我们可以验证图表树中的图表。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

用户管理

最后,我们创建一个只具有查看我们刚创建的图表权限的用户。Cacti内建了用户管理系统,而且是高度可定制的。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

在完成这些步骤后,我们可以使用‘user1’来登录进去,并验证只有该用户可以查看该图表。

Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器
Linux:使用 SNMP 和 Cacti 监控 Linux 服务器

至此,我们在网络监控系统中部署了一台Cacti服务器。Cacti服务器比较稳定,可以处理大量图表而不会出问题。

希望本文对你有所帮助。


via: http://xmodulo.com/monitor-linux-servers-snmp-cacti.html

作者:Sarmed Rahman 译者:GOLinux 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5746-1.html

Linux:Linux 服务器安全技巧

毋庸置疑,对于系统管理员,提高服务器的安全性是最重要的事情之一。因此,也就有了许多针对这个话题而生的文章、博客和论坛帖子。

一台服务器由大量功能各异的部件组成,这一点使得很难根据每个人的需求去提供定制的解决方案。这篇文章尽可能涵盖一些有所裨益的小技巧来帮助管理员保证服务器和用户安全。

有一些常识是每个系统管理员都应该烂熟于心的,所以下面的几点在本文将不会提及:

  • 务必保证系统是最新的
  • 经常更换密码 – 使用数字、字母和非字母的符号组合
  • 给予用户最小的权限,满足他们日常使用所需即可
  • 只安装那些真正需要的软件包
Linux:Linux 服务器安全技巧
Linux:Linux 服务器安全技巧

下面是一些更有意思的内容:

更改SSH默认端口

在搭建好一台全新的服务器后要做的第一件事情就是更改SSH的默认端口。这个小小的改动能够使你的服务器避免受到成千上万的暴力攻击(LCTT 译注:不更改默认端口相当于黑客们知道你家的门牌号,这样他们只需要一把一把的试钥匙就可能打开你家的锁)。

要更改默认的SSH端口,先打开sshd_config文件:

sudo vim /etc/ssh/sshd_config

找到下面这行:

#Port 22

“#”号表示这行是注释。首先删除#号,然后把端口号改成目的端口。端口号不能超过65535,确保要指定的端口号没有被系统或其它服务占用。建议在[维基百科]上查看常用端口号列表。在本文中,使用这个端口号:

Port 16543

然后保存并关闭文件,等待更改生效。

接下来的一步是:

使用SSH密钥认证

在通过SSH访问服务器时,使用SSH密钥进行认证是尤其重要的。这样做为服务器增加了额外的保护,确保只有那些拥有密钥的人才能访问服务器。

在本地机器上运行下面命令以生成SSH密钥:

ssh-keygen -t rsa

你会看到下面的输出,询问要将密钥写到哪一个文件里,并且设置一个密码:

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): my_key
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in my_key.
Your public key has been saved in my_key.pub.
The key fingerprint is:
SHA256:MqD/pzzTRsCjZb6mpfjyrr5v1pJLBcgprR5tjNoI20A

完成之后,就得到两个文件:

my_key

my_key.pub

接下来把my_key.pub拷贝到~/.ssh/authorized_key中

cp my_key.pub ~/.ssh/authorized_keys

然后使用下面命令将密钥上传到服务器:

scp -P16543 authorized_keys user@yourserver-ip:/home/user/.ssh/

至此,你就可以从这台本地机器上无密码地访问服务器了。

关闭SSH的密码认证

既然已经有了SSH密钥,那么关闭SSH的密码认证就会更安全了。再次打开并编辑sshd_config,按如下设置:

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

关闭Root登录

下面关键的一步是关闭root用户的直接访问,而使用sudo或su来执行管理员任务。首先需要添加一个有root权限的新用户,所以编辑这个路径下的sudoers文件:

/etc/sudoers/

推荐使用如visudo这样的命令编辑该文件,因为它会在关闭文件之前检查任何可能出现的语法错误。当你在编辑文件时出错了,这就很有用了。

接下来赋予某个用户root权限。在本文中,使用用户sysadmin。确保在编辑后这个文件时使用的用户是系统已有的用户。找到下面这行:

root ALL=(ALL) ALL

拷贝这行,然后粘贴在下一行,然后把root更改为“sysadmin”,如下所示:

root ALL=(ALL) ALL
sysadmin ALL=(ALL) ALL

现在解释一下这行的每一个选项的含义:

(1) root  (2)ALL=(3)(ALL) (4)ALL

(1) 指定用户

(2) 指定用户使用sudo的终端

(3) 指定用户可以担任的用户角色

(4) 这个用户可以使用的命令

(LCTT 译注:所以上面的配置是意思是:root 用户可以在任何终端担任任何用户,执行任何命令。)

使用这个配置可以给用户访问一些系统工具的权限。

这时,可以放心保存文件了。

为了关闭通过SSH直接访问root,需要再次打开sshd_config,找到下面这行:

#PermitRootLogin yes

更改为:

PermitRootLogin no

然后保存文件,重启sshd守护进程使改动生效。执行下面命令即可:

sudo /etc/init.d/sshd restart

设置防火墙

防火墙有助于过滤出入端口和阻止使用暴力法的登录尝试。我倾向于使用SCF(Config Server Firewall)这个强力防火墙。它使用了iptables,易于管理,而且对于不擅于输入命令的用户提供了web界面。

要安装CSF,先登录到服务器,切换到这个目录下:

cd /usr/local/src/

然后以root权限执行下面命令:

wget https://download.configserver.com/csf.tgz
tar -xzf csf.tgz
cd csf
sh install.sh

只需等待安装程序完成,然后编辑CSF的配置文件:

/etc/csf/csf.conf

默认情况下CSF是以测试模式运行。通过将“TESTING”的值设置成0,切换到product模式。

TESTING = "0"

下面要设置的就是服务器上允许通过的端口。在csf.conf中定位到下面的部分,根据需要修改端口:

# 允许入站的 TCP 端口
TCP_IN = "20,21,25,53,80,110,143,443,465,587,993,995,16543"
# 允许出站的 TCP 端口
TCP_OUT = "20,21,22,25,53,80,110,113,443,587,993,995,16543"
# 允许入站的 UDP 端口
UDP_IN = "20,21,53"
# 允许出站的 UDP 端口
# 要允许发出 traceroute 请求,请加 33434:33523 端口范围到该列表
UDP_OUT = "20,21,53,113,123"

请根据需要逐一设置,推荐只使用那些需要的端口,避免设置对端口进行大范围设置。此外,也要避免使用不安全服务的不安全端口。比如只允许端口465和587来发送电子邮件,取代默认的SMTP端口25。(LCTT 译注:前提是你的邮件服务器支持 SMTPS)

重要:千万不要忘记允许自定义的 ssh 端口。

允许你的IP地址通过防火墙,而绝不被屏蔽,这一点很重要。IP地址定义在下面的文件中:

/etc/csf/csf.ignore

被屏蔽了的IP地址会出现在这个文件中:

/etc/csf/csf.deny

一旦完成更改,使用这个命令重启csf:

sudo /etc/init.d/csf restart

下面是在某台服务器上的csf.deny文件的部分内容,来说明CSF是很有用的:

211.216.48.205 # lfd: (sshd) Failed SSH login from 211.216.48.205 (KR/Korea, Republic of/-): 5 in the last 3600 secs - Fri Mar 6 00:30:35 2015
103.41.124.53 # lfd: (sshd) Failed SSH login from 103.41.124.53 (HK/Hong Kong/-): 5 in the last 3600 secs - Fri Mar 6 01:06:46 2015
103.41.124.42 # lfd: (sshd) Failed SSH login from 103.41.124.42 (HK/Hong Kong/-): 5 in the last 3600 secs - Fri Mar 6 01:59:04 2015
103.41.124.26 # lfd: (sshd) Failed SSH login from 103.41.124.26 (HK/Hong Kong/-): 5 in the last 3600 secs - Fri Mar 6 02:48:26 2015
109.169.74.58 # lfd: (sshd) Failed SSH login from 109.169.74.58 (GB/United Kingdom/mail2.algeos.com): 5 in the last 3600 secs - Fri Mar 6 03:49:03 2015

可以看到,尝试通过暴力法登录的IP地址都被屏蔽了,真是眼不见心不烦啊!

锁住账户

如果某个账户在很长一段时间内都不会被使用了,那么可以将其锁住以防止其它人访问。使用如下命令:

passwd -l accountName

当然,这个账户依然可以被root用户使用(LCTT 译注:可用 su 切换为该账号)。

了解服务器上的服务

服务器的本质是为各种服务提供访问功能。使服务器只运行所需的服务,关闭没有使用的服务。这样做不仅会释放一些系统资源,而且也会使服务器变得更加安全。比如,如果只是运行一个简单的服务器,显然不需要X显示或者桌面环境。如果不需要Windows网络共享功能,则可以放心关闭Samba。

使用下面的命令能查看伴随系统启动而启动的服务:

chkconfig --list | grep "3:on"

如果系统运行了systemd,执行这条命令:

systemctl list-unit-files --type=service | grep enabled

然后使用下面的命令关闭服务:

chkconfig service off
或
systemctl disable service

在上面的例子中,把“service”替换成真正想要停止的服务名称。实例如下:

chkconfig httpd off
或
systemctl disable httpd

小结

这篇文章的目的是涵盖一些通用的安全步骤以便帮助你保护服务器。你可以采取更多方式去增强对服务器的保护。请记住保证服务器安全是你的责任,在维护服务器安全时尽量做出明智的选择,尽管并没有什么容易的方式去完成这件事情,而建立“完善的”安全需要花费大量的时间和测试直到达到想要的结果。


via: http://www.linuxveda.com/2015/06/03/secure-linux-server/

作者:Marin Todorow 译者:KayGuoWhu 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5748-1.html

Linux:如何在 Cacti 中合并两幅图片

Cacti 是一个很棒的开源网络监视系统,它广泛使用于图形化地展示网络元素,例如带宽、存储、处理器和内存使用。使用它的基于Web 的界面,你可以轻松地创建和组织各种图表。然而,它默认并没有提供一些高级功能,例如合并图片、使用多个来源创建聚合图形、迁移 Cacti 到另一台服务器。使用 Cacti 的这些功能你还需要一些经验。在该教程中,我们会看到如何在将两幅 Cacti 图片合并为一幅。

看看这个例子。在过去的 6 个月中,客户端 A 连接到了交换机 A 的端口 5。端口 5 发生了错误,因此客户端迁移到了端口 6。由于 Cacti 为每个接口/元素使用不同的图,客户端的带宽历史会分成端口 5 和端口 6。结果是对于一个客户端我们有两幅图片 – 一幅是 6 个月的旧数据,另一幅保存了后续的数据。

在这种情况下,我们实际上可以合并两幅图片将旧数据加到新的图中,使得用一个单独的图为一个用户保存历史的和新数据。本教程将会解释如何做到这一点。

Cacti 将每幅图片的数据保存在它自己的 RRD(round robin database,循环数据库)文件中。当请求一幅图片时,根据保存在对应 RRD 文件中的值生成图。在 Ubuntu/Debian 系统中,RRD 文件保存在 /var/lib/cacti/rra,在 CentOS/RHEL 系统中则是 /var/www/cacti/rra

合并图片背后的思想是更改这些 RRD 文件使得旧 RRD 文件中的值能追加到新的 RRD 文件中。

情景

一个客户端的服务在 eth0 上运行了超过一年。由于硬件损坏,客户端迁移到了另一台服务器的 eth1 接口。我们想展示新接口的带宽,同时保留超过一年的历史数据。该客户端希望只在一幅图中显示。

确定图的 RRD 文件

图合并的首个步骤是确定与图相关联的 RRD 文件。我们可以通过以调试模式打开图检查文件。要做到这点,在 Cacti 的菜单中: 控制台 > 管理图 > 选择图 > 打开图调试模式。

旧图:

Linux:如何在 Cacti 中合并两幅图片
Linux:如何在 Cacti 中合并两幅图片

新图:

Linux:如何在 Cacti 中合并两幅图片
Linux:如何在 Cacti 中合并两幅图片

从样例输出(基于 Debian 系统)中,我们可以确定两幅图片的 RRD 文件:

  • 旧图: /var/lib/cacti/rra/old_graph_traffic_in_8.rrd
  • 新图: /var/lib/cacti/rra/new_graph_traffic_in_10.rrd

准备脚本

我们会用一个 RRD 剪接脚本 来合并两个 RRD 文件。下载该 PHP 脚本,并安装到 /var/lib/cacti/rra/rrdsplice.php (Debian/Ubuntu 系统) 或 /var/www/cacti/rra/rrdsplice.php (CentOS/RHEL 系统)。

下一步,确认 Apache 用户拥有该文件。

在 Debian 或 Ubuntu 系统中,运行下面的命令:

# chown www-data:www-data rrdsplice.php

并更新 rrdsplice.php。查找下面的行:

chown($finrrd, "apache");

用下面的语句替换:

chown($finrrd, "www-data");

在 CentOS 或 RHEL 系统中,运行下面的命令即可:

# chown apache:apache rrdsplice.php

合并两幅图

通过不带任何参数运行该脚本可以获得脚本的使用语法。

# cd /path/to/rrdsplice.php
# php rrdsplice.php

USAGE: rrdsplice.php --oldrrd=file --newrrd=file --finrrd=file

现在我们准备好合并两个 RRD 文件了。只需要指定旧 RRD 文件和新 RRD 文件的名称。我们会将合并后的结果重写到新 RRD 文件中。

# php rrdsplice.php --oldrrd=old_graph_traffic_in_8.rrd --newrrd=new_graph_traffic_in_10.rrd --finrrd=new_graph_traffic_in_10.rrd

现在旧 RRD 文件中的数据已经追加到了新 RRD 文件中。Cacti 会将任何新数据写到新 RRD 文件中。如果我们点击图,我们可以发现也已经添加了旧图的周、月、年记录。下面图表中的第二幅图显示了旧图的周记录。

Linux:如何在 Cacti 中合并两幅图片
Linux:如何在 Cacti 中合并两幅图片

总之,该教程显示了如何简单地将两幅 Cacti 图片合并为一幅。当服务迁移到另一个设备/接口,我们希望只处理一幅图片而不是两幅时,这个小技巧非常有用。该脚本非常方便,因为它可以不管源设备是不是相同都可以合并图片,例如 Cisco 1800 路由器和 Cisco 2960 交换机。

希望这些能对你有所帮助。


via: http://xmodulo.com/combine-two-graphs-cacti.html

作者:Sarmed Rahman 译者:ictlyh 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5747-1.html

Linux:MySQL 的隐式类型转换

隐式类型转换有无法命中索引的风险,在高并发、大数据量的情况下,命不中索引带来的后果非常严重。将数据库拖死,继而整个系统崩溃,对于大规模系统损失惨重。

MySQL 的隐式类型转换原则:

  • 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 <=> 对两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换
  • 两个参数都是字符串,会按照字符串来比较,不做类型转换
  • 两个参数都是整数,按照整数来比较,不做类型转换
  • 十六进制的值和非数字做比较时,会被当做二进制串,和数字做比较时会按下面的规则处理
  • 有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp
  • 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
  • 所有其他情况下,两个参数都会被转换为浮点数再进行比较

注意一个安全问题:假如 password 类型为字符串,查询条件为 int 0 则会匹配上。

由于 MySQL 隐式类型转换规则比较复杂,依赖 MySQL 隐式转换很容易出现各种想想不到的问题,而且 MySQL 隐式类型转换本身也是非常耗费 MySQL 服务器性能的,所以非常不推荐这样使用

来源:http://blog.eood.cn/mysql_params

Linux:提高 Vim 和 Shell 效率的 9 个建议

Linux:提高 Vim 和 Shell 效率的 9 个建议
Linux:提高 Vim 和 Shell 效率的 9 个建议

1. 重映射 CAPSLOCK 键

你上一次使用 CAPSLOCK 键是什么时候?很久没有了对不对?噢,我也是,它已经被遗忘了,它浪费了键盘上一个黄金位置。让我们把它重映射成 Control 键来发挥它的作用吧!这里告诉了你在不同的操作系统上的具体操作。

现在你可以保持标准键位手势,随意的敲击到 a键左边的 crtl 了。

2. 使用 ctrl-r 来搜索和自动重做历史命令

许多人都知道可以使用箭头键来都调用上一个历史命令,但相对的,很少有人知道可以使用 ctrl-r来迅速完成历史命令的调用。

Linux:提高 Vim 和 Shell 效率的 9 个建议
Linux:提高 Vim 和 Shell 效率的 9 个建议

一旦找到相应的命令,可以通过回车来执行,或者在执行前对命令进行修改,这很容易会养成习惯,特别是在你把 CAPSLOCK 键重映射以后。

3. 使用 OS X 系统的 iTerm

iTerm 不是必须要用的高效工具,但绝对能提升效率。它有如下特性:

  • 屏幕分割
  • 选中即复制
  • 剪切历史
  • 全屏切换
  • 系统热键
  • Exposé 所有 Tab
  • 保存当前快照

我还不知道有哪个人换到 iTerm 以后还愿意换回来的。上吧。

4. 把 Zsh 作为 Shell

大部分人会像我以前一样是用 Bash 的人,看了 Zsh 的优点之后,绝大多数人就会对它赞不绝口并且再也不愿意用 Bash 了。它的特性如下:

  • 目录补全:ve/pl/re --> vendor/plugins/redmine
  • 环境变量展开:$PATH --> /your/full/path
  • 智能修正:/pbulic/html 变 /public/html
  • 拼写修正
  • 命令历史共享
  • 行编辑高亮模式
  • 完美兼容 Bash 大部分配置
  • 运行/bin/sh的时候可以媲美Bash
  • 支持vim模式
  • OhMyZsh支持

最后一条是决定性的,ohmyzsh包含大量插件(包括 rails、git、OS X、brew 等等),有超过80个终端主题和自动更新。ohmyzsh通过这些来让 shell 用起来很爽。更详细请查看这里

5. 重映射 vim 的 ESCAPE 键

vim 有多个模式并不是什么大问题,但在模式间切换的时候会感觉很糟。ESC 键有点远,这太麻烦了。当我面对新的 vim 环境时,所做的第一件事就是添加如下映射

inoremap jj 

6. 重映射 Vim 的 Leader 键

如果你不熟悉 leader 键,也不知道它能为你做什么,那你就从这开始了解吧。它本质上是作为你快捷键的激活键,你可以自定义用哪个键作为你的 leader 键。所以,你可以:

nnoremap j VipJ

这可以让你按下 leader 键结合大写 ‘j’ 后可视化的选择整段并加入行。

我个人用 ‘,’ 键作为我的leader键,这样我可以用 ‘,’ 激活我所有的快捷键,然后通过 ‘jj’ 退出插入模式。你可以在 .vimrc中像这样映射:

let mapleader = ","

7. 在 Shell 中使用 vi 模式

无论是 zsh 还是 bash 你都会想尽可能的使用同样的肌肉记忆,如果你是 vim 用户,这意味着你应该把你的 shell 从 Emacs模式(默认)切换到 vi 模式

这意味着你可以用 vim 的方式编辑你的 shell 命令行:

  • b 返回上一个单词
  • dd 删除整行
  • 0, $移动到行末
  • …等等。

你可以通过添加下面这行代码到 .zshrc 或 .bashrc 文件来实现这一切:

bindkey -v

你也可以像 vim 一样映射你的 escape 键:

bindkey -M viins ‘jj’ vi-cmd-mode

另一个好处是可以通过j、k来自然的浏览历史记录。还可以在你的.zshrc文件中通过下面的代码添加ctrl-r的功能:

bindkey ‘^R’ history-incremental-search-backward

8. 把tmux加入工作流程

tmux是一个终端复用器,它允许你连接和管理多个服务器端会话。在tmux中可以启动并连接对话,还可以断开,然后在不同的时间地点再次连接。

你也许熟悉类似的解决方案,GNU Screen,但比起 screen,tmux 有如下优势

  • screen 是一个又大又重的项目,并且它的编码中有许多问题
  • tmux 是一个轻便的项目,有现代的、高效的代码库
  • tmux 是一个完整的客户端服务器项目,而 screen 是屏幕仿真软件
  • tmux 支持 vim 和 emacs 的键盘布局
  • tmux 支持运行时自动重命名窗口
  • tmux 能很方便的通过 shell 实现脚本化
  • tmux 自带垂直分屏功能,而 screen 里屏幕被固定死了

如果你用不上终端复用功能,也可以是尝试一下 tmux,你会获益的。[ 更新: 这有 tumx 的最全启蒙书。]

9. 同步工作环境

好了,在你的 MBP 能体验到酷炫的 shell 和 vim 了,但一旦你都 SSH 到你的 Linux 上,就会感觉完全不同,这太令人恼火了。还好,可以通过同步来处理这个问题。

  1. 在 git 上为你的配置文件创建一个仓库,例如:Bash、Zsh、Vim 等等。记得保持更新。
  2. 在你所用的每个系统上都克隆一份(配置文件)到对应系统的目录下。
  3. 有评论说也可以用 Dropbox 来同步,似乎很棒,但我不确定在 Headless(Headless指没有显示器、键盘、鼠标等设备)的 Linux 服务器上工作效果如何。

来源:http://blog.jobbole.com/86809/

Linux:如何用Perl访问SQLite数据库

SQLite是一个零配置、无服务端、基于文件的事务型数据库系统。由于它的轻量级,自包含和紧凑的设计,所以当你想要集成数据库到你的程序中时,SQLite是一个非常不错的选择。在这篇文章中,我会展示如何用Perl脚本来创建和访问SQLite数据库。我演示的Perl代码片段是完整的,所以你可以很简单地修改并集成到你的项目中。

Linux:如何用Perl访问SQLite数据库
Linux:如何用Perl访问SQLite数据库

访问SQLite的准备

我会使用SQLite DBI Perl驱动来连接到SQLite3。因此你需要在Linux中安装它(和SQLite3一起)。

Debian、 Ubuntu 或者 Linux Mint

$ sudo apt-get install sqlite3 libdbd-sqlite3-perl

CentOS、 Fedora 或者 RHEL

$ sudo yum install sqlite perl-DBD-SQLite

安装后,你可以检查SQLite驱动可以通过下面的脚本访问到。

#!/usr/bin/perl
my @drv = DBI->available_drivers();
print join("n", @drv), "n";

如果你运行脚本,你应该会看见下面的输出。

DBM
ExampleP
File
Gofer
Proxy
SQLite
Sponge

Perl SQLite 访问示例

下面就是Perl访问SQLite的示例。这个Perl脚本会演示下面这些SQLite数据库的常规管理。

  • 创建和连接SQLite数据库
  • 在SQLite数据库中创建新表
  • 在表中插入行
  • 在表中搜索和迭代行
  • 在表中更新行
  • 在表中删除行
use DBI;
use strict;
# 定义数据库名称和驱动
my $driver   = "SQLite";
my $db_name = "xmodulo.db";
my $dbd = "DBI:$driver:dbname=$db_name";
# sqlite 没有用户名密码的概念
my $username = "";
my $password = "";
# 创建并连接到数据库
# 以下创建的文件名为 xmodulo.db
my $dbh = DBI->connect($dbd, $username, $password, { RaiseError => 1 })
                      or die $DBI::errstr;
print STDERR "Database opened successfullyn";
# 创建表
my $stmt = qq(CREATE TABLE IF NOT EXISTS NETWORK
             (ID INTEGER PRIMARY KEY     AUTOINCREMENT,
              HOSTNAME       TEXT    NOT NULL,
              IPADDRESS      INT     NOT NULL,
              OS             CHAR(50),
              CPULOAD        REAL););
my $ret = $dbh->do($stmt);
if($ret < 0) {
   print STDERR $DBI::errstr;
} else {
   print STDERR "Table created successfullyn";
}
# 插入三行到表中
$stmt = qq(INSERT INTO NETWORK (HOSTNAME,IPADDRESS,OS,CPULOAD)
           VALUES ('xmodulo', 16843009, 'Ubuntu 14.10', 0.0));
$ret = $dbh->do($stmt) or die $DBI::errstr;
$stmt = qq(INSERT INTO NETWORK (HOSTNAME,IPADDRESS,OS,CPULOAD)
           VALUES ('bert', 16843010, 'CentOS 7', 0.0));
$ret = $dbh->do($stmt) or die $DBI::errstr;
$stmt = qq(INSERT INTO NETWORK (HOSTNAME,IPADDRESS,OS,CPULOAD)
           VALUES ('puppy', 16843011, 'Ubuntu 14.10', 0.0));
$ret = $dbh->do($stmt) or die $DBI::errstr;
# 在表中检索行
$stmt = qq(SELECT id, hostname, os, cpuload from NETWORK;);
my $obj = $dbh->prepare($stmt);
$ret = $obj->execute() or die $DBI::errstr;
if($ret < 0) {
   print STDERR $DBI::errstr;
}
while(my @row = $obj->fetchrow_array()) {
      print "ID: ". $row[0] . "n";
      print "HOSTNAME: ". $row[1] ."n";
      print "OS: ". $row[2] ."n";
      print "CPULOAD: ". $row[3] ."nn";
}
# 更新表中的某行
$stmt = qq(UPDATE NETWORK set CPULOAD = 50 where OS='Ubuntu 14.10';);
$ret = $dbh->do($stmt) or die $DBI::errstr;
if( $ret < 0 ) {
   print STDERR $DBI::errstr;
} else {
   print STDERR "A total of $ret rows updatedn";
}
# 从表中删除某行
$stmt = qq(DELETE from NETWORK where ID=2;);
$ret = $dbh->do($stmt) or die $DBI::errstr;
if($ret < 0) {
   print STDERR $DBI::errstr;
} else {
   print STDERR "A total of $ret rows deletedn";
}
# 断开数据库连接
$dbh->disconnect();
print STDERR "Exit the databasen";

上面的Perl脚本运行成功后会创建一个叫“xmodulo.db”的数据库文件,并会有下面的输出。

Database opened successfully
Table created successfully
ID: 1
HOSTNAME: xmodulo
OS: Ubuntu 14.10
CPULOAD: 0
ID: 2
HOSTNAME: bert
OS: CentOS 7
CPULOAD: 0
ID: 3
HOSTNAME: puppy
OS: Ubuntu 14.10
CPULOAD: 0
A total of 2 rows updated
A total of 1 rows deleted
Exit the database

错误定位

如果你尝试没有安装SQLite DBI驱动的情况下使用Perl访问SQLite的话,你会遇到下面的错误。你必须按开始说的安装DBI驱动。

Can't locate DBI.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at ./script.pl line 3.
BEGIN failed--compilation aborted at ./script.pl line 3.

via: http://xmodulo.com/access-sqlite-database-perl.html

作者:Dan Nanni 译者:geekpi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5764-1.html

Linux:玩转 Varnish 缓存代理

Varnish 是互联网架构中重要的缓存代理组件。Varnish 一般跑在流量入口处,作为最前端一道防御,非常重要。

Linux:玩转 Varnish 缓存代理
Linux:玩转 Varnish 缓存代理

虽然 Varnish 并不像 Nginx 那么流行。Varnish 就像 Nginx 一样稳定高效,如果使用得当,能极大提升整体服务性能、并且降低资源消耗。

常见互联网架构中的多级缓存

  1. 将内容推送到用户身边的 CDN 缓存
  2. 类似 Varnish 的缓存代理
  3. 应用层缓存 Redis,Memcache
  4. 数据库缓存

为什么缓存代理很重要

  1. 一些事实:内容的变动比不变少得多;用户内容最终一致的容忍性。基于这 2 个事实,可以节约大量重复计算和资源。
  2. 延迟一般情况下对用户体验、商业业务的影响很大。所有互联网公司都在努力降低延迟,提升用户体验。
  3. CDN 有些情况下会大量回源,比如清空 CDN 缓存的时候,应用架构本身需要能抗 100% 流量的能力。

Varnish 的几个功能

1. HTTP Header 的修改

请求头的修改

unset req.http.cookie;
set req.http.X-EOOD = "EOOD";

返回头的修改

unset beresp.http.Set-Cookie;
set beresp.http.Cache-Control = "public, max-age=31536000";

2. 内容在 Varnish 状态的暴露

缓存的命中与否

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

3. 负载均衡

Varnish 也支持后端服务器的轮询之类的简单负载均衡,但是慎用。

4. 后端保护和容错

这个功能可能有些人没有注意到,但是确实非常有用的功能,在后端挂掉的时候,只读页面仍然会成功返回给客户。

set req.grace = 48h;

5. 访问控制

可以根据规则路由或者屏蔽某些访问,比如:

req.http.User-Agent
req.http.X-Forwarded-For
req.http.referer
...

简单密码保护:Basic Auth

if (! req.http.Authorization ~ "Basic XXXXXXX") {
    error 401 "Restricted";
}

6. 多个后端合并

定义多个后端

backend ads {
    .host = "ads.eood.cn";
    .connect_timeout = 1s;
    .first_byte_timeout = 30s;
    .between_bytes_timeout = 5s;
}
backend blog {
    .host = "blog.eood.cn";
    .connect_timeout = 1s;
    .first_byte_timeout = 30s;
    .between_bytes_timeout = 5s;
}

根据域名、URL或者其他规则路由到不同的后端,这些规则可以是用户 IP, 甚至是用户 Cookie。

sub vcl_recv {
    if (req.http.host ~ "ads" || req.url ~ "^/ads/") {
        set req.backend = ads;
        ...
    } else if(eq.http.host ~ "blog") {
        set req.backend = blog;
    }
}

7. 根据规则进行缓存

set beresp.ttl = 120s;

Varnish 运维常用命令

请求 URL 热点排名, 根据热点优化缓存策略

varnishtop -i rxurl

实时请求日志

varnishlog

可以通过 grep 进行过滤查看你需要的信息

varnishlog -c | grep 'google'

Varnish 的注意事项

防止连接粘滞,假如你有多个不同的后端,不添加这个会导致混乱,估计很多人踩过这个坑:

sub vcl_pipe {
    set bereq.http.connection = "close";
}

URL 规划

一般缓存代理或者 CDN 都是可以通过配置 URL 规则实现不同 URL 模式使用不同的缓存策略,所以 URL 规划非常重要。将动态请求和静态请求进行区分;将不同缓存级别的 URL 进行区分。这也有利于根据 URL 进行缓存清理。

最后

Varnish 是网站应用或者移动应用必不可少的缓存模块。如果你还没开始使用,就立刻把他加入到现有架构中吧。

来源:http://blog.eood.cn/varnish-cache

Linux:如何清洗 Git Repo 代码仓库

相信不少团队的代码仓库 Git Repo 变得越来越大。除了代码的提交外,时常有人会把二进制文件比如 Jar 包或者不小心把不该提交到代码库的文件提交到代码库中,比如用户名密码之类的保密信息。如何清洗代码仓库 Git Repo,彻底从历史中删除此类文件呢?

Linux:如何清洗 Git Repo 代码仓库
Linux:如何清洗 Git Repo 代码仓库

手动清理

如果你们的代码仓库问题比较少,只有几个不该提交的文件,可以参考 Atlassian 的一篇关于维护 Git Repo 的文章

大致过程如下:

首先进行 Git 垃圾回收:

git gc --auto

其次查看 Git 仓库占用空间:

$ du -hs .git/objects
45M .git/objects

然后找出历史中超过一定大小的文件,最后在历史中删除并且提交。如果感兴趣手动处理这个过程可以参照文章后边的链接。

相关的几个命令:

清理历史中的文件:

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch ****/nohup.out' --prune-empty --tag-name-filter cat -- --all
git filter-branch --index-filter 'git rm --cached --ignore-unmatch ****/nohup.out' HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

强制提交覆盖:

git reflog expire --expire=now --all
git gc --prune=now
git push --all --force
git push --all --tags --force

但是这个方案有 2 个问题:

  1. 处理速度慢,尝试清理 2G 大小的代码库,用了一晚上还没跑完。
  2. 只能按文件名清理,如果不同的路径有同样的文件名就无法处理了,可能误删文件或者忽略某些文件。

当然有个非常好的解决方案完美解决了这个问题。如下:

自动清理

答案就是 bfg-repo-cleaner,这是一个 Java 写的清理工具,多线程处理清理过程,命令很简单,只需要几分钟就清理了之前 一晚上都跑不完的任务:

java -jar bfg-1.11.7.jar --delete-files *.zip myrepo.git
java -jar bfg-1.11.7.jar --delete-files *.log myrepo.git
java -jar bfg-1.11.7.jar --delete-files *.out myrepo.git
java -jar bfg-1.11.7.jar --strip-blobs-bigger-than 1M myrepo.git

附上几个常用的但又不常见的 git 小技巧:

复制代码仓库:

git clone --bare /var/www/html/myrepo.git

Git 后悔药,覆盖最后一次修改:

git add .
git commit --amend
git push origin master -f

Git 放弃本地修改:

git checkout .

Git 销毁最后一次提交:

git reset --hard HEAD^
git push -f origin HEAD^:master

打包时候嵌入版本号:

git rev-parse HEAD > version.txt

 

来源:http://blog.eood.cn/how-to-clean-up-git-repo

Linux:watch:定期重复Linux / Unix命令

服务器管理员需要维护系统并保持更新和安全。每天需要运行大量的指令。有些系统进程会记录日志。这些日志不断更新。为了检查这些更新,需要重复地执行命令。比如,为了读取一个日志文件需要使用head、tail、cat等命令。这些命令需要重复地执行。而watch命令可以用于定期地执行一个命令。

Linux:watch:定期重复Linux / Unix命令
Linux:watch:定期重复Linux / Unix命令

Watch 命令

watch是一个简单的命令,只有几个选项。watch命令的基本语法是:

watch [-dhvt] [-n ] [--differences[=cumulative]] [--help] [--interval=] [--no-title] [--version] 

watch命令默认每隔2秒执行后面参数给出的命令。这个时间根据的是命令执行结束到上次执行的间隔来算的。比如,watch命令可以用于监测日志更新,更新是在文件的后面追加新的内容,因此可以用tail命令来检测文件的更新(LCTT 译注:可以直接使用 tail -f主动跟踪某个文件的更新,而不用使用 watch。)。这个命令会持续地运行直到你按下 CTRL + C回到提示符。

例子

每两秒监测 errors/notices/warning 生成的情况。

watch tail /var/log/messages
Linux:watch:定期重复Linux / Unix命令
Linux:watch:定期重复Linux / Unix命令

按指定的时间间隔监测磁盘的使用率。

watch df -h

df -h

对磁盘管理员而言,关注高I/O等待导致的磁盘操作尤其是mysql事务是很重要的。

watch mysqladmin processlist
Linux:watch:定期重复Linux / Unix命令
Linux:watch:定期重复Linux / Unix命令

监测服务器负载和运行时间。

watch uptime

uptime

监测exim给用户发送通知的队列大小。

watch exim -bpc

exim -bpc

1) 指定延迟

watch [-n ] 

命令默认运行的时间间隔可用-n改变,下面的命令会在5秒后运行后面的命令:

watch -n 5 date

date 5 seconds

2) 连续输出比较

如果你使用-d选项,它会累次地高亮第一次和下一次命令之间输出的差别。

watch [-d or --differences[=cumulative]] 

例子 1,用下面的命令连续地输出时间并观察高亮出来的不同部分。

watch -n 15 -d date

第一次执行date的输出会被记录,15秒后会重复运行命令。

Difference A

在下一次执行时,可以看到输出除了被高亮的秒数从14到29之外其他的都一样。

Difference A

例子 2,让我们来体验一下两个连续的“uptime”命令输出的不同。

watch -n 20 -d uptime

uptime

现在列出了时间和3个负载快照之间的不同。

10b

3) 不带标题输出

如果你不希望显示更多关于延迟和实际命令的信息可以使用-t选项。

watch [-t | --no-title] 

让我们看下下面例子命令的输出:

watch -t date

watch without title

Watch 帮助

可以在ssh中输入下面的命令来得到watch的简要帮助。

watch -h [--help]

watch help

Watch 版本

在ssh终端中运行下面的命令来检查watch的版本。

watch -v [--version]

version

不足

不幸的是,在终端大小调整时,屏幕不能在下次运行前重画。所有用–difference高亮的内容也会在更新时丢失。

总结

watch对系统管理员而言是一个非常强大的工具,因为它可以用于监控、日志、运维、性能和系统运行时的吞吐量。人们可以非常简单地格式化和推延watch的输出。任何Linux命令/程序或脚本可以按照所需监测和连续输出。


via: http://linoxide.com/linux-command/linux-watch-command/

作者:Aun Raza 译者:geekpi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5765-1.html

Linux:在Ubuntu下安装Node.JS的不同方式

如果你要在Ubuntu 15.04上安装Node.js的话,这篇教程对你来说肯定很重要。Node.js从本质上来说就是一个运行在服务端上的封装好了输入输出流的javascript程序。Node.js巧妙的使用单线程的事件循环来处理高吞吐量和非阻塞IO。同时它也是一个提供了通过操作系统读写文件和网络操作功能的平台层。所以这篇文章将展示在Ubuntu 15.04 server上不同的安装Node.Js的方式。

Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

安装Node.JS 的方法

有许多安装Node.JS的不同的方法,我们可以选择其一。通过本篇文章我们将手把手带着你在Ubuntu 15.04上安装Node.Js,在此之前请卸载旧版本的包以免发生包冲突。

  • 从源代码安装Node.JS
  • 用包管理器安装Node.JS
  • 从Github远程库安装Node.JS
  • 用NVM安装Node.JS

1) 从源代码安装Node.JS

让我们开始从源代码安装Node.JS之前,请确认系统上的所有的依赖包都已经更新到最新版本。然后跟着以下步骤来开始安装:

步骤1: 升级系统

用以下命令来升级系统,并且安装一些Node.JS必要的包。

root@ubuntu-15:~# apt-get update
root@ubuntu-15:~# apt-get install python gcc make g++

步骤2: 获取Node.JS的源代码

安装好依赖包之后我们可以从官方网站上下载Node.JS的源代码。下载以及解压的命令如下:

root@ubuntu-15:~# wget http://nodejs.org/dist/v0.12.4/node-v0.12.4.tar.gz
root@ubuntu-15:~# tar zxvf node-v0.12.4.tar.gz

步骤3: 开始安装

现在我们进入源代码的目录,然后运行.configure文件

Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式
root@ubuntu-15:~# ls
node-v0.12.4 node-v0.12.4.tar.gz
root@ubuntu-15:~# cd node-v0.12.4/
root@ubuntu-15:~/node-v0.12.4# ./configure
root@ubuntu-15:~/node-v0.12.4# make install

安装后测试

只要运行一下上面的命令就顺利安装好了Node.JS,现在我们来确认一下版本信息和测试以下Node.JS是否可以运行输出。

root@ubuntu-15:~/node-v0.12.4# node -v
v0.12.4

Node.Js Test

创建一个以.js为扩展名的文件然后用Node的命令运行

root@ubuntu-15:~/node-v0.12.4# touch helo_test.js
root@ubuntu-15:~/node-v0.12.4# vim helo_test.js
console.log('Hello World');

现在我们用Node的命令运行文件

root@ubuntu-15:~/node-v0.12.4# node helo_test.js
Hello World

输出的结果证明我们已经成功的在Ubuntu 15.04安装好了Node.JS,同时我们也能运行JavaScript文件。

2) 利用包管理器安装Node.JS

在Ubuntu下用包管理器安装Node.JS是非常简单的,只要增加NodeSource的个人软件包档案(PPA)即可。

我们将下面通过PPA安装Node.JS。

步骤1: 用curl获取源代码

在我们用curl获取源代码之前,我们必须先升级操作系统,然后用curl命令获取NodeSource添加到本地仓库。

root@ubuntu-15:~#apt-get update
root@ubuntu-15:~# curl -sL https://deb.nodesource.com/setup | sudo bash -

curl将运行以下任务

## Installing the NodeSource Node.js 0.10 repo...
## Populating apt-get cache...
## Confirming "vivid" is supported...
## Adding the NodeSource signing key to your keyring...
## Creating apt sources list file for the NodeSource Node.js 0.10 repo...
## Running `apt-get update` for you...
Fetched 6,411 B in 5s (1,077 B/s)
Reading package lists... Done
## Run `apt-get install nodejs` (as root) to install Node.js 0.10 and npm

步骤2: 安装NodeJS和NPM

运行以上命令之后如果输出如上所示,我们可以用apt-get命令来安装NodeJS和NPM包。

root@ubuntu-15:~# apt-get install nodejs
Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

步骤3: 安装一些必备的工具

通过以下命令来安装编译安装一些我们必需的本地插件。

root@ubuntu-15:~# apt-get install -y build-essential

通过Node.JS Shell来测试

测试Node.JS的步骤与之前使用源代码安装相似,通过以下node命令来确认Node.JS是否完全安装好:

root@ubuntu-15:~# node
> console.log('Node.js Installed Using Package Manager');
Node.js Installed Using Package Manager

root@ubuntu-15:~# node
> a = [1,2,3,4,5]
[ 1, 2, 3, 4, 5 ]
> typeof a
'object'
> 5 + 2
7
>
(^C again to quit)
>
root@ubuntu-15:~#

使用NodeJS应用进行简单的测试

REPL是一个Node.js的shell,任何有效的JavaScript代码都能在REPL下运行通过。所以让我们看看在Node.JS下的REPL是什么样子吧。

root@ubuntu-15:~# node
> var repl = require("repl");
undefined
> repl.start("> ");
Press Enter and it will show out put like this:
> { domain: null,
_events: {},
_maxListeners: 10,
useGlobal: false,
ignoreUndefined: false,
eval: [Function],
inputStream:
{ _connecting: false,
_handle:
{ fd: 0,
writeQueueSize: 0,
owner: [Circular],
onread: [Function: onread],
reading: true },
_readableState:
{ highWaterMark: 0,
buffer: [],
length: 0,
pipes: null,
...
...

以下是可以在REPL下使用的命令列表

Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

使用NodeJS的包管理器

NPM是一个提供给node脚本持续生命力的命令行工具,它能通过package.json来安装和管理依赖包。最开始从初始化命令init开始

root@ubuntu-15:~# npm init
Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

3) 从Github远程库安装Node.JS

在这个方法中我们需要一些步骤来把Node.JS从Github的远程的仓库克隆到本地仓库目录

在开始克隆(clone)包到本地并且配制之前,我们要先安装以下依赖包

root@ubuntu-15:~# apt-get install g++ curl make libssl-dev apache2-utils git-core

现在我们开始用git命令克隆到本地并且转到配制目录

root@ubuntu-15:~# git clone git://github.com/ry/node.git
root@ubuntu-15:~# cd node/
Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

clone仓库之后,通过运行.config命令来编译生成完整的安装包。

root@ubuntu-15:~# ./configure
Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

运行make install命令之后耐心等待几分钟,程序将会安装好Node.JS。

root@ubuntu-15:~/node# make install
root@ubuntu-15:~/node# node -v
v0.13.0-pre

测试Node.JS

root@ubuntu-15:~/node# node
> a = [1,2,3,4,5,6,7]
[ 1, 2, 3, 4, 5, 6, 7 ]
> typeof a
'object'
> 6 + 5
11
>
(^C again to quit)
>
root@ubuntu-15:~/node#

4) 通过NVM安装Node.JS

在最后一种方法中我们我们将用NVM来比较容易安装Node.JS。安装和配制Node.JS,这是最好的方法之一,它可以供我们选择要安装的版本。

在安装之前,请确认本机以前的安装包已经被卸载。

步骤1: 安装依赖包

首先升级Ubuntu Server系统,然后安装以下安装Node.JS和使用NVM所要依赖的包。用curl命令从git上下载NVM到本地仓库:

root@ubuntu-15:~# apt-get install build-essential libssl-dev
root@ubuntu-15:~# curl https://raw.githubusercontent.com/creationix/nvm/v0.16.1/install.sh | sh
Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

步骤2: 修改Home环境

用curl从NVM下载必需的包到用户的home目录之后,我们需要修改bash的配置文件添加NVM,之后只要重新登录中断或者用如下命令更新即可。

root@ubuntu-15:~# source ~/.profile

现在我们可以用NVM来设置默认的NVM的版本,或者用如下命令来指定之前版本:

root@ubuntu-15:~# nvm ls
root@ubuntu-15:~# nvm alias default 0.12.4

NVM Default

步骤3: 使用NVM

我们已经通过NVM成功的安装了Node.JS,所以我们现在可以使用各种有用的命令。

Linux:在Ubuntu下安装Node.JS的不同方式
Linux:在Ubuntu下安装Node.JS的不同方式

总结

现在我们已经准备好了在服务端安装Node.JS,你可以从我们说的四种方式中选择最合适你的方式在最新的Ubuntu 15.04上来安装Node.JS,安装好之后你就可以利用Node.JS来编写你的代码。


via: http://linoxide.com/ubuntu-how-to/setup-node-js-ubuntu-15-04-different-methods/

作者:Kashif Siddique 译者:NearTan 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5766-1.html

Linux:Linux 下如何处理包含空格和特殊字符的文件名

我们经常会看到文件名和文件夹名。大多数时候文件/文件夹的名字和内容相关并以数字和字母开头。字母加数字的文件名最常见,应用也很广泛,但总会需要处理一些包含特殊字符的文件名/文件夹名。

注意:我们可能有各种类型的文件,但是为了简单以及方便实现,在本文中我们只用文本文件(.txt)做演示。

Linux:Linux 下如何处理包含空格和特殊字符的文件名
Linux:Linux 下如何处理包含空格和特殊字符的文件名

最常见的文件名例子:

abc.txt
avi.txt
debian.txt
...

数字文件名例子:

121.txt
3221.txt
674659.txt
...

字母数字文件名例子:

eg84235.txt
3kf43nl2.txt
2323ddw.txt
...

包含特殊字符的文件名的例子,并不常见:

#232.txt
#bkf.txt
#bjsd3469.txt
#121nkfd.txt
-2232.txt
-fbjdew.txt
-gi32kj.txt
--321.txt
--bk34.txt
...

一个显而易见的问题是 – 在这个星球上有谁会创建和处理包含井号(#),分号(;),破折号(-)或其他特殊字符的文件/文件夹啊。

我和你想的一样,这种文件名确实不常见,不过在你必须得处理这种文件名的时候你的 shell 也不应该出错或罢工。而且技术上来说,Linux 下的一切比如文件夹、驱动器或其他所有的都被当作文件处理。

处理名字包含破折号(-)的文件

创建以破折号(-)开头的文件,比如 -abx.txt。

$ touch -abc.txt

测试输出

touch: invalid option -- 'b'
Try 'touch --help' for more information.

出现上面错误的原因是,shell 把破折号(-)之后的内容认作参数了,而很明显没有这样的参数,所以报错。

要解决这个问题,我们得告诉 Bash shell(是的,这里以及本文后面的大多数例子都是基于 BASH 环境)不要将特殊字符(这里是破折号)后的字符解释为参数。

有两种方法解决这个错误:

$ touch -- -abc.txt     [方法 #1]
$ touch ./-abc.txt      [方法 #2]

你可以通过运行命令 ls 或 ls -l 列出详细信息来检查通过上面两种方式创建的文件。

$ ls -l
total 0
-rw-r--r-- 1 avi avi 0 Jun  8 11:05 -abc.txt

要编辑上述文件可以这样:

$ nano -- -abc.txt
或者
$ nano ./-abc.txt

注意:你可以将 nano 替换为任何其他你喜欢的编辑器比如说 vim:

$ vim -- -abc.txt
或者
$ vim ./-abc.txt

如果只是简单地移动文件可以这样:

$ mv -- -abc.txt -a.txt
或者
$ mv -- -a.txt -abc.txt

删除这种文件,可以这样:

$ rm -- -abc.txt
或者
$ rm ./-abc.txt

如果一个目录下有大量这种名字包含破折号的文件,要一次全部删除的话,可以这样:

$ rm ./-*

重要:

  1. 上面讨论的规则可以同样应用于名字中包含任意数量以及任意位置的连接符号的文件。就是说,-a-b-c.txt,ab-c.txt,abc-.txt,等等。

  2. 上面讨论的规则可以同样应用于名字中包含任意数量以及任意位置连接符号的文件夹,除了一种情况,在删除一个文件夹的时候你得这样使用rm -rf

    $ rm -rf — -abc 或者 $ rm -rf ./-abc

处理名字包含井号(#)的文件

符号#在 BASH 里有非常特别的含义。#之后的一切都会被认为是评论,因此会被 BASH 忽略。

通过例子来加深理解:

创建一个名字是 #abc.txt 的文件:

$ touch #abc.txt

测试输出

touch: missing file operand
Try 'touch --help' for more information.

出现上面错误的原因是,BASH 将 #abc.txt 解释为评论而忽略了。所以命令 touch没有收到任何文件作为参数,所以导致这个错误。

要解决这个问题,你可能需要告诉 BASH 不要将 # 解释为评论。

$ touch ./#abc.txt
或者
$ touch '#abc.txt'

检查刚创建的文件:

$ ls -l
total 0
-rw-r--r-- 1 avi avi 0 Jun  8 12:14 #abc.txt

现在创建名字中除了开头的其他地方包含 # 的文件。

$ touch ./a#bc.txt
$ touch ./abc#.txt
或者
$ touch 'a#bc.txt'
$ touch 'abc#.txt'

运行 ‘ls -l‘ 来检查:

$ ls -l
total 0
-rw-r--r-- 1 avi avi 0 Jun  8 12:16 a#bc.txt
-rw-r--r-- 1 avi avi 0 Jun  8 12:16 abc#.txt

如果同时创建两个文件(比如 a 和 #bc)会怎么样:

$ touch a.txt #bc.txt

检查刚创建的文件:

$ ls -l
total 0
-rw-r--r-- 1 avi avi 0 Jun  8 12:18 a.txt

很明显上面的例子中只创建了文件 a而文件 #bc被忽略了。对于上面的情况我们可以这样做,

$ touch a.txt ./#bc.txt
或者
$ touch a.txt '#bc.txt'

检查一下:

$ ls -l
total 0
-rw-r--r-- 1 avi avi 0 Jun  8 12:20 a.txt
-rw-r--r-- 1 avi avi 0 Jun  8 12:20 #bc.txt

可以这样移动文件:

$ mv ./#bc.txt ./#cd.txt
或者
$ mv '#bc.txt' '#cd.txt'

这样拷贝:

$ cp ./#cd.txt ./#de.txt
或者
$ cp '#cd.txt' '#de.txt'

可以使用你喜欢的编辑器来编辑文件:

$ vi ./#cd.txt
或者
$ vi '#cd.txt'
$ nano ./#cd.txt
或者
$ nano '#cd.txt'

这样删除:

$ rm ./#bc.txt
或者
$ rm '#bc.txt'

要删除所有以井号(#)开头的文件,可以这样:

# rm ./#*

处理名字包含分号(;)的文件

如果你还不知道的话,分号在 BASH 里起到命令分隔的作用,其他 shell 可能也是一样的。分号作为分隔符可以让你一次执行几个命令。你碰到过名字包含分号的文件吗?如果没有的话,这里有例子。

创建一个名字包含分号的文件。

$ touch ;abc.txt

测试输出

touch: missing file operand
Try 'touch --help' for more information.
bash: abc.txt: command not found

出现上面错误的原因是,在运行上面命令的时候 BASH 会把 touch 解释为一个命令但是在分号前没有任何文件参数,所以报告错误。然后报告的另一个错误找不到命令 abc.txt,只是因为在分号后 BASH 会期望另一个新的命令,而 abc.txt并不是一个命令。

要解决这个问题,我们得告诉 BASH 不要将分号解释为命令分隔符,例如:

$ touch ./';abc.txt'
或者
$ touch ';abc.txt'

注意:我们将文件名用单引号 '' 包含起来。这样可以告诉 BASH 分号 ; 是文件名的一部分而不是命令分隔符。

对名字包含分号的文件和文件夹的其他操作(就是,拷贝、移动、删除)可以直接将名字用单引号包含起来就好了。

处理名字包含其他特殊字符的文件/文件夹

文件名包含加号 (+)

不需要任何特殊处理,按平时的方式做就好了,比如下面测试的文件名。

$ touch +12.txt

文件名包含美元符 ($)

你需要将文件名用单引号括起来,像处理分号那样的方式。然后就很简单了。

$ touch '$12.txt'

文件名包含百分号 (%)

不需要任何特殊处理,当作一个普通文件就可以了。

$ touch %12.txt

文件名包含星号 (*)

需要用单引号括起来或使用反斜杠转义。(LCTT 译注:此处原文有误,已修改。)

$ touch *12.txt

注意:当你需要删除星号开头的文件时,千万不要用类似下面的命令。

$ rm *
或者
$ rm -rf *

而是用这样的命令,(LCTT 译注:此处原文有误,已修改)

$ rm ./'*.txt'

文件名包含叹号 (!)

只要将文件名用单引号括起来,其他的就一样了。

$ touch '!12.txt'

文件名包含小老鼠 (@)

没有什么特别的,可以将名字包含小老鼠的文件当作普通文件。

$ touch '@12.txt'

文件名包含 ^

不需要特殊处理。可以将名字包含 ^ 的文件当作普通文件。

$ touch ^12.txt

文件名包含 (&)

将文件名用单引号括起来,然后就可以操作了。

$ touch '&12.txt'

文件名包含括号 ()

如果文件名包含括号,你需要将文件名用单引号括起来。

$ touch '(12.txt)'

文件名包含花括号 {}

用单引号括起来或使用反斜杠转义。(LCTT 译注:此处原文有误,已修改)

$ touch '{12.txt}'

文件名包含尖括号 <>

名字包含尖括号的文件需要用单引号括起来。

$ touch '<12.txt>'

文件名包含方括号 [ ]

用单引号括起来或使用反斜杠转义。(LCTT 译注:此处原文有误,已修改)

$ touch '[12.txt]'

文件名包含下划线 (_)

这个非常普遍,不需要特殊对待。当作普通文件随意处理。

$ touch _12.txt

文件名包含等号 (=)

用单引号括起来或使用反斜杠转义。(LCTT 译注:此处原文有误,已修改)

$ touch '=12.txt'

处理反斜杠 ()

反斜杠会告诉 shell 忽略后面字符的特殊含义。你必须将文件名用单引号括起来,就像处理分号那样。其他的就没什么了。

$ touch '12.txt'

包含斜杠的特殊情形

除非你的文件系统有问题,否则你不能创建名字包含斜杠的文件。没办法转义斜杠。

所以如果你能创建类似 ‘/12.txt’ 或者 ‘b/c.txt’ 这样的文件,那要么你的文件系统有问题,或者支持 Unicode,这样你可以创建包含斜杠的文件。只是这样并不是真的斜杠,而是一个看起来像斜杠的 Unicode 字符。

文件名包含问号 (?)

用单引号括起来或使用反斜杠转义。(LCTT 译注:此处原文有误,已修改)

$ touch '?12.txt'

文件名包含点 (.)

在 Linux 里以点 (.)开头的文件非常特别,被称为点文件。它们通常是隐藏的配置文件或系统文件。你需要使用 ls 命令的 ‘-a‘ 或 ‘-A‘ 开关来查看这种文件。

创建,编辑,重命名和删除这种文件很直接。

$ touch .12.txt

注意:在 Linux 里你可能碰到名字包含许多点 (.)的文件。不像其他操作系统,文件名里的点并不意味着分隔名字和扩展后缀。你可以创建名字包含多个点的文件:

$ touch 1.2.3.4.5.6.7.8.9.10.txt

检查一下:

$ ls -l
total 0
-rw-r--r-- 1 avi avi 0 Jun  8 14:32 1.2.3.4.5.6.7.8.9.10.txt

文件名包含逗号 (,)

你可以在文件名中使用逗号,可以有任意多个而不用特殊对待。就像平时普通名字文件那样处理。

$ touch ,12.txt
或者
$ touch ,12,.txt

文件名包含冒号 (:)

用单引号括起来或使用反斜杠转义。(LCTT 译注:此处原文有误,已修改)

$ touch ':12.txt'
或者
$ touch ':12:.txt'

文件名包含引号(单引号和双引号)

要在文件名里使用引号,我们需要使用交替规则。例如,如果你需要在文件名里使用单引号,那就用双引号把文件名括起来。而如果你需要在文件名里使用双引号,那就用单引号把文件名括起来。(LCTT 译注:或者如果单引号和双引号混杂的情况,你也可以用反斜杠转义。)

$ touch "15'.txt"
以及
$ touch '15".txt'

文件名包含波浪号 (~)

Linux 下一些像 emacs 这样的文本编辑器在编辑文件的时候会创建备份文件。这个备份文件的名字是在原文件名后面附加一个波浪号。你可以在文件名任意位置使用波浪号,例如:

$ touch ~1a.txt
或者
$touch 2b~.txt

文件名包含空格

创建名字的字符/单词之间包含空格的文件,比如 “hi my name is avishek.txt”。

最好不要在文件名里使用空格,如果你必须要分隔可读的名字,可以使用下划线或横杠。不过,你还是需要创建这样的文件的话,你可以用反斜杠来转义下一个字符。要创建上面名字的文件可以这样做。

$ touch hi my name is avishek.txt
hi my name is avishek.txt

我已经尝试覆盖你可能碰到的所有情况。上面大多数测试都在 BASH Shell 里完成,可能在其他 shell 下会有差异。

如果你觉得我遗漏了什么(这很正常也符合人性),请把你的建议发表到下面的评论里。保持联系,多评论。不要走开!求点赞求分享求扩散!


via: http://www.tecmint.com/manage-linux-filenames-with-special-characters/

作者:Avishek Kumar 译者:zpl1025 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5777-1.html

Linux:纯手工玩转 Nginx 日志

Nginx 日志对于大部分人来说是个未被发掘的宝藏,总结之前做某日志分析系统的经验,和大家分享一下 Nginx 日志的纯手工分析方式。

Linux:纯手工玩转 Nginx 日志
Linux:纯手工玩转 Nginx 日志

Nginx 日志相关配置有 2 个地方:access_log 和 log_format 。

默认的格式:

access_log /data/logs/nginx-access.log;
log_format old '$remote_addr [$time_local] $status $request_time $body_bytes_sent '
    '"$request" "$http_referer" "$http_user_agent"';

相信大部分用过 Nginx 的人对默认 Nginx 日志格式配置都很熟悉,对日志的内容也很熟悉。但是默认配置和格式虽然可读,但是难以计算。

Nginx 日志刷盘相关策略可配置:

比如,设置 buffer,buffer 满 32k 才刷盘;假如 buffer 不满 5s 钟强制刷盘的配置如下:

access_log /data/logs/nginx-access.log buffer=32k flush=5s;

这决定了是否实时看到日志以及日志对磁盘 IO 的影响。

Nginx 日志能够记录的变量还有很多没出现在默认配置中:

比如:

  • 请求数据大小:$request_length
  • 返回数据大小:$bytes_sent
  • 请求耗时:$request_time
  • 所用连接序号:$connection
  • 当前连接发生请求数:$connection_requests

Nginx 的默认格式不可计算,需要想办法转换成可计算格式,比如用控制字符 ^A (Mac 下 ctrl+v ctrl+a 打出)分割每个字段。

log_format 的格式可以变成这样:

log_format new '$remote_addr^A$http_x_forwarded_for^A$host^A$time_local^A$status^A'
    '$request_time^A$request_length^A$bytes_sent^A$http_referer^A$request^A$http_user_agent';

这样之后就通过常见的 Linux 命令行工具进行分析了:

  • 查找访问频率最高的 URL 和次数:
    cat access.log | awk -F ‘^A’ ‘{print $10}’ | sort | uniq -c
  • 查找当前日志文件 500 错误的访问:
    cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’
  • 查找当前日志文件 500 错误的数量:
    cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’ | wc -l
  • 查找某一分钟内 500 错误访问的数量:
    cat access.log | awk -F ‘^A’ ‘{if($5 == 500) print $0}’ | grep ’09:00’ | wc-l
  • 查找耗时超过 1s 的慢请求:
    tail -f access.log | awk -F ‘^A’ ‘{if($6>1) print $0}’
  • 假如只想查看某些位:
    tail -f access.log | awk -F ‘^A’ ‘{if($6>1) print $3″|”$4}’
  • 查找 502 错误最多的 URL:
    cat access.log | awk -F ‘^A’ ‘{if($5==502) print $11}’ | sort | uniq -c
  • 查找 200 空白页
    cat access.log | awk -F ‘^A’ ‘{if($5==200 && $8 < 100) print $3″|”$4″|”$11″|”$6}’
  • 查看实时日志数据流
    tail -f access.log | cat -e

    或者

    tail -f access.log | tr ‘^A’ ‘|’

总结

照着这个思路可以做很多其他分析,比如 UA 最多的访问;访问频率最高的 IP;请求耗时分析;请求返回包大小分析;等等。

这就是一个大型 Web 日志分析系统的原型,这样的格式也是非常方便进行后续大规模 batching 和 streaming 计算。

来源:http://blog.eood.cn/nginx_logs

Linux:SSH 使用密钥登录并禁止口令登录实践

Linux:SSH 使用密钥登录并禁止口令登录实践
Linux:SSH 使用密钥登录并禁止口令登录实践

前言

无论是个人的VPS还是企业允许公网访问的服务器,如果开放22端口的SSH密码登录验证方式,被众多黑客暴力猜解捅破菊花也可能是经常发生的惨剧。企业可以通过防火墙来做限制,普通用户也可能借助修改22端口和强化弱口令等方式防护,但目前相对安全和简单的方案则是让SSH使用密钥登录并禁止口令登录。

这是最相对安全的登录管理方式

生成PublicKey

建议设置并牢记passphrase密码短语,以Linux生成为例

Linux:ssh-keygen -t rsa

[私钥 (id_rsa) 与公钥 (id_rsa.pub)]

Windows:SecurCRT/Xshell/PuTTY

[SSH-2 RSA 2048]

#生成SSH密钥对
ssh-keygen -t rsa
Generating public/private rsa key pair.
#建议直接回车使用默认路径
Enter file in which to save the key (/root/.ssh/id_rsa):
#输入密码短语(留空则直接回车)
Enter passphrase (empty for no passphrase):
#重复密码短语
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
aa:8b:61:13:38:ad:b5:49:ca:51:45:b9:77:e1:97:e1 root@localhost.localdomain
The key's randomart image is:
+--[ RSA 2048]----+
|    .o.          |
|    ..   . .     |
|   .  . . o o    |
| o.  . . o E     |
|o.=   . S .      |
|.*.+   .         |
|o.*   .          |
| . + .           |
|  . o.           |
+-----------------+

复制密钥对

也可以手动在客户端建立目录和authorized_keys,注意修改权限

#复制公钥到无密码登录的服务器上,22端口改变可以使用下面的命令
#ssh-copy-id -i ~/.ssh/id_rsa.pub "-p 10022 user@server"
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.15.241

修改SSH配置文件

#编辑sshd_config文件
vi /etc/ssh/sshd_config
#禁用密码验证
PasswordAuthentication no
#启用密钥验证
RSAAuthentication yes
PubkeyAuthentication yes
#指定公钥数据库文件
AuthorsizedKeysFile .ssh/authorized_keys

重启SSH服务前建议多保留一个会话以防不测

#RHEL/CentOS系统
service sshd restart
#ubuntu系统
service ssh restart
#debian系统
/etc/init.d/ssh restart

手动增加管理用户

可以在== 后加入用户注释标识方便管理

echo 'ssh-rsa XXXX' >>/root/.ssh/authorized_keys
# 复查
cat /root/.ssh/authorized_keys

扩展阅读

来源:http://wsgzao.github.io/post/ssh/

Linux:MariaDB Galera Cluster 部署

MariaDB作为Mysql的一个分支,在开源项目中已经广泛使用,例如大热的openstack,所以,为了保证服务的高可用性,同时提高系统的负载能力,集群部署是必不可少的。

MariaDB Galera Cluster 介绍

MariaDB Galera Cluster 是开源的 MariaDB同步多主机集群。它仅支持XtraDB/ InnoDB存储引擎(虽然有对MyISAM实验支持 – 看wsrep_replicate_myisam系统变量)。

Linux:MariaDB Galera Cluster 部署
Linux:MariaDB Galera Cluster 部署

主要功能:

  • 同步复制
  • 真正的multi-master,即所有节点可以同时读写数据库
  • 自动的节点成员控制,失效节点自动被清除
  • 新节点加入数据自动复制
  • 真正的并行复制,行级
  • 用户可以直接连接集群,使用感受上与MySQL完全一致

优势:

  • 因为是多主,所以不存在Slavelag(延迟)
  • 不存在丢失事务的情况
  • 同时具有读和写的扩展能力
  • 更小的客户端延迟
  • 节点间数据是同步的,而Master/Slave模式是异步的,不同slave上的binlog可能是不同的

技术:

Galera集群的复制功能基于Galeralibrary实现,为了让MySQL与Galera library通讯,特别针对MySQL开发了wsrep API。

Galera插件保证集群同步数据,保持数据的一致性,靠的就是可认证的复制,工作原理如下图: 

Linux:MariaDB Galera Cluster 部署
Linux:MariaDB Galera Cluster 部署

当客户端发出一个commit的指令,在事务被提交之前,所有对数据库的更改都会被 write-set 收集起来,并且将write-set 纪录的内容发送给其他节点。

write-set 将在每个节点进行认证测试,测试结果决定着节点是否应用write-set更改数据。

如果认证测试失败,节点将丢弃 write-set ;如果认证测试成功,则事务提交。

1 安装环境准备

安装MariaDB集群至少需要3台服务器(如果只有两台的话需要特殊配置,请参照官方文档

在这里,我列出试验机器的配置:

操作系统版本:centos7

  • node4:10.128.20.16
  • node5:10.128.20.17
  • node6:10.128.20.18

以第一行为例,node4为 hostname ,10.128.20.16为 ip ,在三台机器修改 /etc/hosts 文件,我的文件如下:

10.128.20.16 node4
10.128.20.17 node5
10.128.20.18 node6

为了保证节点间相互通信,需要禁用防火墙设置(如果需要防火墙,则参照官方网站增加防火墙信息设置)

在三个节点分别执行命令:

systemctl stop firewalld

然后将 /etc/sysconfig/selinux 的 selinux 设置成 disabled ,这样初始化环境就完成了。

2 安装 MariaDB Galera Cluster

[root@node4 ~]# yum install -y mariadb mariadb-galera-server mariadb-galera-common galera rsync
[root@node5 ~]# yum install -y mariadb mariadb-galera-server mariadb-galera-common galera rsync
[root@node6 ~]# yum install -y mariadb mariadb-galera-server mariadb-galera-common galera rsync

3 配置 MariaDB Galera Cluster

初始化数据库服务,只在一个节点进行

[root@node4 mariadb]# systemctl start mariadb
[root@node4 mariadb]# mysql_secure_installation
NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!
In order to log into MariaDB to secure it, we'll need the current
password for the root user.  If you've just installed MariaDB, and
you haven't set the root password yet, the password will be blank,
so you should just press enter here.
Enter current password for root (enter for none):
OK, successfully used password, moving on...
Setting the root password ensures that nobody can log into the MariaDB
root user without the proper authorisation.
Set root password? [Y/n]
New password:
Re-enter new password:
Password updated successfully!
Reloading privilege tables..
 ... Success!
By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.
Remove anonymous users? [Y/n] n
 ... skipping.
Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.
Disallow root login remotely? [Y/n] y
 ... Success!
By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.
Remove test database and access to it? [Y/n] n
 ... skipping.
Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.
Reload privilege tables now? [Y/n] y
 ... Success!
Cleaning up...
All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.
Thanks for using MariaDB!

关闭数据库,修改 /etc/my.cnf.d/galera.cnf

[root@node4 mariadb]# systemctl stop mariadb
[root@node4 ~]# vim /etc/my.cnf.d/galera.cnf

修改以下内容:

[mysqld]
......
wsrep_provider = /usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address = "gcomm://node4,node5,node6"
wsrep_node_name = node4
wsrep_node_address=10.128.20.16
#wsrep_provider_options="socket.ssl_key=/etc/pki/galera/galera.key; socket.ssl_cert=/etc/pki/galera/galera.crt;"

提示:如果不用ssl的方式认证的话,请把 wsrep_provider_options 注释掉。

将此文件复制到node5、node6,注意要把 wsrep_node_name 和 wsrep_node_address 改成相应节点的hostname 和 ip

4 启动 MariaDB Galera Cluster 服务

[root@node4 ~]# /usr/libexec/mysqld --wsrep-new-cluster --user=root &

观察日志:

[root@node4 ~]# tail -f /var/log/mariadb/mariadb.log
150701 19:54:17 [Note] WSREP: wsrep_load(): loading provider library 'none'
150701 19:54:17 [Note] /usr/libexec/mysqld: ready for connections.
Version: '5.5.40-MariaDB-wsrep'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MariaDB Server, wsrep_25.11.r4026

出现 ready for connections ,证明我们启动成功,继续启动其他节点:

[root@node5 ~]# systemctl start mariadb
[root@node6 ~]# systemctl start mariadb

可以查看 /var/log/mariadb/mariadb.log,在日志可以看到节点均加入了集群中。

警告⚠:--wsrep-new-cluster 这个参数只能在初始化集群使用,且只能在一个节点使用。

5 查看集群状态

Linux:MariaDB Galera Cluster 部署
Linux:MariaDB Galera Cluster 部署

我们可以关注几个关键的参数:

wsrep_connected = on 链接已开启

wsrep_local_index = 1 在集群中的索引值

wsrep_cluster_size =3 集群中节点的数量

wsrep_incoming_addresses = 10.128.20.17:3306,10.128.20.16:3306,10.128.20.18:3306 集群中节点的访问地址

6 验证数据同步

我们在 node4 上新建数据库 galera_test ,然后在 node5 和 node6 上查询,如果可以查询到 galera_test 这个库,说明数据同步成功,集群运行正常。

[root@node4 ~]# mysql  -uroot  -proot  -e  "create database galera_test"
[root@node5 ~]# mysql  -uroot  -proot  -e  "show databases"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| galera_test        |
| mysql              |
| performance_schema |
+--------------------+
[root@node6 ~]# mysql  -uroot  -proot  -e  "show databases"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| galera_test        |
| mysql              |
| performance_schema |
+--------------------+

至此,我们的 MariaDB Galera Cluster 已经成功部署。

参考文章

来源:http://code.oneapm.com/database/2015/07/02/mariadb-galera-cluster/

Linux:Percona Xtrabackup快速备份MySQL

老规矩,开场白,刚开始用mysqldump,备份100G+的数据库,再加上服务器繁忙,备份速度像蜗牛似的,于是寻找更高效的备份方法。网上都说用xtrabackup比较适合备份大的数据库,而且备份效率也高,就尝试使用一次,结果明显感觉比mysqldump 备份与恢复速度就是快不少,那以后就用它了。大礼拜日的在家也没事,结合生产环境,写了这篇文档,刚接触的朋友,可以参考下,不多说,入正题!

Linux:Percona Xtrabackup快速备份MySQL
Linux:Percona Xtrabackup快速备份MySQL

1、初次备份前准备工作

1.1 了解备份方式

  • 热备份:读写不受影响(mysqldump–>innodb)
  • 温备份:仅可以执行读操作(mysqldump–>myisam)
  • 冷备份:离线备份,读写都不可用
  • 逻辑备份:将数据导出文本文件中(mysqldump)
  • 物理备份:将数据文件拷贝(xtrabackup、mysqlhotcopy)
  • 完整备份:备份所有数据
  • 增量备份:仅备份上次完整备份或增量备份以来变化的数据
  • 差异备份:仅备份上次完整备份以来变化的数据

   1.2 创建备份用户

mysql> grant reload,lock tables,replication client on *.* to 'bak'@'localhost' identified by 'bak2015';
mysql> flush privileges;

1.3 安装方式

CentOS:

# rpm -ivh http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
# yum install percona-xtrabackup

xtrabackup2.2不支持MySQL5.1的Innodb引擎,如需要可安装2.0版本

Ubuntu:

# sudo apt-get install xtrabackup  

14.04默认有这个包,14.04之前版本如果没有在这个地址下载对应的版本。

1.4 了解常用参数

  • –user=     #指定数据库备份用户
  • –password=  #指定数据库备份用户密码
  • –port=     #指定数据库端口
  • –host=     #指定备份主机
  • –socket=    #指定socket文件路径
  • –databases=  #备份指定数据库,多个空格隔开,如–databases=”dbname1 dbname2″,不加备份所有库
  • –defaults-file=       #指定my.cnf配置文件
  • –apply-log         #日志回滚
  • –incremental=          #增量备份,后跟增量备份路径
  • –incremental-basedir=     #增量备份,指上次增量备份路径
  • –redo-only         #合并全备和增量备份数据文件
  • –copy-back         #将备份数据复制到数据库,数据库目录要为空
  • –no-timestamp          #生成备份文件不以时间戳为目录名
  • –stream=             #指定流的格式做备份,–stream=tar,将备份文件归档
  • –remote-host=user@ip DST_DIR #备份到远程主机

2、完整备份与恢复

2.1 完整备份 

# innobackupex --user=bak --password='bak2015' /mysql_backup  

2.2 备份恢复

# innobackupex --defaults-file=/etc/mysql/my.cnf --copy-back /home/loongtao/mysql_backup/2015-02-08_11-56-48/

2.3 备份文件说明

# ls 2015-02-08_11-56-48
  • backup-my.cnf:记录innobackup使用到mysql参数
  • xtrabackup_binary:备份中用到的可执行文件
  • xtrabackup_checkpoints:记录备份的类型、开始和结束的日志序列号
  • xtrabackup_logfile:备份中会开启一个log copy线程,用来监控innodb日志文件(ib_logfile),如果修改就会复制到这个文件

3、完整备份+增量备份与恢复

3.1 完整备份

# innobackupex --user=bak --password='bak2015' /mysql_backup

备份后位置是:/mysql_backup/2015-02-08_11-56-48

3.2 增量备份1

# innobackupex --user=bak --password='bak2015' --incremental /data1/mysql_backup --incremental-basedir=/mysql_backup/2015-02-08_11-56-48  #指定上次完整备份目录

3.3 增量备份2

# innobackupex --user=bak --password='bak2015' --incremental /data1/mysql_backup --incremental-basedir=/mysql_backup/2015-02-08_12-16-06  #指定上次增量备份目录

3.4 查看xtrabackup_checkpoints文件

一目了然,可以看到根据日志序号来增量备份

Linux:Percona Xtrabackup快速备份MySQL
Linux:Percona Xtrabackup快速备份MySQL

3.5 备份恢复

3.5.1 备份恢复思路

将增量备份1、增量备份2…合并到完整备份,加到一起出来一个新的完整备份,将新的完整备份以拷贝的形式到数据库空目录(rm /var/lib/mysql/* -rf)

3.5.2 预备完整备份

xtrabackup把备份过程中可能有尚未提交的事务或已经提交但未同步数据文件的事务,写到xtrabackup_logfile文件,所以要先通过这个日志文件回滚,把未完成的事务同步到备份文件,保证数据文件处于一致性。

# innobackup --apply-log --redo-only 2015-02-08_11-56-48
3.5.3 合并第一个增量备份
# innobackupex --apply-log --redo-only /mysql_backup/2015-02-08_11-56-48/ --incremental-dir=mysql_backup/2015-02-08_12-16-06
3.5.4 合并第二个增量备份
# innobackupex --apply-log --redo-only /mysql_backup/2015-02-08_11-56-48/ --incremental-dir=mysql_backup/2015-02-08_16-06-53
3.5.5 恢复完整备份

这时2015-02-08_11-56-48完整备份已经包含所有增量备份,可以通过查看checkpoints来核实

# innobackupex --defaults-file=/etc/mysql/my.cnf --copy-back /mysql_backup/2015-02-08_11-56-48/
3.5.6 修改恢复数据文件权限
# chown -R mysql.mysql /var/lib/mysql
3.5.7 启动MySQL,查看数据库恢复情况
# /etc/init.d/mysqld start

4、备份文件归档压缩

4.1 归档并发送到备份服务器

# innobackupex --databases=test --user=bak --password='bak2015' --stream=tar /mysql_backup 2>/mysql_backup/bak.log |ssh root@192.168.18.251 "cat - > /mysql_backup/`date +%F`.tar"

解压:tar -ixvf `date +%F`.tar

4.2 归档备份

# innobackupex --databases=test --user=bak --password='bak2015' --stream=tar /mysql_backup > /mysql_backup/`date +%F`.tar

解压:tar -ixvf `date +%F`.tar

4.3 压缩归档备份

# innobackupex --databases=test --user=bak --password='bak2015' --stream=tar /mysql_backup |gzip >/mysql_backup/`date +%F`.tar.gz

解压:tar -izxvf `date +%F`.tar.gz

来源:http://lizhenliang.blog.51cto.com/7876557/1612800

Linux:在 RHEL/CentOS 7.0 中安装 LAMP

跳过 LAMP 的介绍,因为我认为你们大多数已经知道了。这个教程会集中在如何在升级到 Apache 2.4 的 Red Hat Enterprise Linux 7.0 和 CentOS 7.0 中安装和配置 LAMP:Linux、Apache、 MariaDB、 PHP/PhpMyAdmin。

Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

在 RHEL/CentOS 7.0 中安装 LAMP

前置要求

根据使用的发行版是 RHEL 还是 CentOS 7.0,按照下面的链接来进行最小化的系统安装,网络使用静态 IP。

对于 RHEL 7.0

对于 CentOS 7.0

第一步:使用基本配置安装apache

1、在完成最小化系统安装,并在 RHEL/CentOS 7.0 上配置静态 IP 后,就可以使用下面的命令从官方仓库安装最新的 Apache 2.4 httpd 服务了。

# yum install httpd
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

安装 apache 服务

2、安装完成后,使用下面的命令来管理apache守护进程,因为 RHEL 和 CentOS 7.0 都将 init 脚本从 SysV 升级到了systemd,所以同时你还可以使用 SysV 脚本和 Apache 脚本来管理服务。

# systemctl status|start|stop|restart|reload httpd
或者
# service httpd status|start|stop|restart|reload
或者
# apachectl configtest| graceful
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

启动apache服务

3、在使用 systemd 初始化脚本来启动 apache 服务后,要用 firewall-cmd打开 RHEL/CentOS 7.0 防火墙规则, 这是通过 firewalld 守护进程管理 iptables 的默认命令。**

# firewall-cmd --add-service=http

注意:上面的命令会在系统重启或者 firewalld 服务重启后失效,因为它是即时的规则,它不会永久生效。要使 iptables 规则在 fiewalld 中持久化,使用 –permanent选项并重启 firewalld 服务来生效。(LCTT 译注:也可以不重启 firewalld 服务,而是再执行一遍不带 –permanent选项的命令。)

# firewall-cmd --permanent --add-service=http
# systemctl restart firewalld
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

在 CentOS 7 中启用防火墙

下面是 firewalld 其他的重要选项:

# firewall-cmd --state
# firewall-cmd --list-all
# firewall-cmd --list-interfaces
# firewall-cmd --get-service
# firewall-cmd --query-service service_name
# firewall-cmd --add-port=8080/tcp

4、要验证 apache 的功能,打开一个远程浏览器并使用 http 协议访问你服务器的 IP 地址(http://server_IP), 应该会显示下图中的默认页面。

Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

Apache 默认页

5、现在 apache 的根地址在 /var/www/html,该目录中没有提供任何索引文件。如果你想要看见根目录下的文件夹列表,打开 apache 欢迎配置文件并设置 Indexes前的状态从-+,下面的截图就是一个例子。

# nano /etc/httpd/conf.d/welcome.conf
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

Apache 目录列出

6、关闭文件,重启 apache 服务来使设置生效,重载页面来看最终效果。

# systemctl restart httpd
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

Apache 索引文件

第二步:为 Apache 安装 php5 支持

7、在为 apache 安装 php 支持之前,使用下面的命令的得到所有可用的php模块和扩展。

# yum search php
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

在 CentOS 7 上安装 PHP*

8、根据你所要使用的应用类型,安装上述列表中所需的 PHP 模块。对于 PHP 中的基本的 MariaDB 支持和 PhpMyAdmin,你需要安装如下模块。

# yum install php php-mysql php-pdo php-gd php-mbstring

Install PHP Modules in CentOS 7

安装 PHP 模块

Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

安装 PHP mbstring 模块

9、 要在你的浏览器上显示 PHP 的全部信息,用 root 账号执行如下命令在 Apache 的文档根目录下创建一个 info.php文件,然后重启 httpd 服务,并在你的浏览器里面访问 http://server_IP/info.php 。

# echo "" > /var/www/html/info.php
# systemctl restart httpd
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

查看 CentOS 7 上的 PHP 信息

10、如果你得到一个 PHP 的日期和时区错误,打开配置文件 php.ini,取消 date.timezone语句的注释,加上你的实际时区参数,然后重启 Apache 守护进程。

# nano /etc/php.ini

找到并如下修改date.timezone,参考 PHP 支持的时区列表。(LCTT 译注:对于中国,可以使用 Asia/Shanghai、Asia/Chongqing 等,但是不建议使用向后兼容而保留的 PRC。)

date.timezone = Continent/City
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

设置 PHP 的时区

第三步:安装和配置 MariaDB 数据库

11、 Red Hat Enterprise Linux/CentOS 7.0 使用 MariaDB 替换 MySQL 为默认数据库管理系统。使用如下命令安装 MariaDB 数据库。

# yum install mariadb-server mariadb
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

在 CentOS 7中安装 MariaDB

12、安装 MariaDB 后,启动数据库守护进程并使用 mysqlsecureinstallation 脚本来保护数据库(设置数据库的 root 密码、禁止远程 root 登录、移除测试数据库、移除匿名用户等)。

# systemctl start mariadb
# mysql_secure_installation
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

启动 MariaDB 数据库

Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

MariaDB 安全设置

13、要测试数据库功能,使用 root 账户登录 MariaDB 并用 quit 退出。

mysql -u root -p
MariaDB > SHOW VARIABLES;
MariaDB > quit
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

连接 MariaDB 数据库

第四步:安装 PhpMyAdmin

14、 RHEL 7.0 或者 CentOS 7.0 仓库默认没有提供 PhpMyAdmin 二进制安装包。如果你不适应使用 MySQL 命令行来管理你的数据库,你可以通过下面的命令启用 CentOS 7.0 rpmforge 仓库来安装 PhpMyAdmin。

# yum install http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm

启用 rpmforge 仓库后,下面安装 PhpMyAdmin。

# yum install phpmyadmin
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

启用 RPMForge 仓库

15、下面配置 PhpMyAdmin 的 phpmyadmin.conf来允许远程连接,它位于 Apache 的 conf.d目录下,并注释掉下面的行。

# nano /etc/httpd/conf.d/phpmyadmin.conf

使用#来注释掉下列行。

# Order Deny,Allow
# Deny from all
# Allow from 127.0.0.1
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

允许远程 PhpMyAdmin 访问

16、 要使用 cookie 验证来登录 PhpMyAdmin,像下面的截图那样使用生成的秘密字符串来添加一个 blowfish 字符串到 config.inc.php文件中,重启 apache 服务并打开 URL:http://server_IP/phpmyadmin/。

# nano /etc/httpd/conf.d/phpmyadmin.conf
# systemctl restart httpd
Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

在 PhpMyAdmin 中添加 Blowfish

Linux:在 RHEL/CentOS 7.0 中安装 LAMP
Linux:在 RHEL/CentOS 7.0 中安装 LAMP

PhpMyAdmin 面板

第五步:在系统范围内启用 LAMP

17、 如果你需要在重启后自动运行 MariaDB 和 Apache 服务,你需要在系统级地启用它们。

# systemctl enable mariadb
# systemctl enable httpd

Enable Services System Wide

系统级启用服务

这就是在 Red Hat Enterprise 7.0 或者 CentOS 7.0 中安装 LAMP 的过程。在 CentOS/RHEL 7.0 上关于 LAMP 的系列文章接下来将会讨论在 Apache 中创建虚拟主机,生成 SSL 证书、密钥和添加 SSL 事务支持。


via: http://www.tecmint.com/install-lamp-in-centos-7/

作者:Matei Cezar 译者:geekpi 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5789-1.html

Linux:Web 应用性能和压力测试工具 Gor

常见的 Web 应用的压力测试工具

Web 应用压力测试工具有很多,比如 Apache ab,node-ab,Apache JMeter, LoadRunner, httperf。但是这些工具都没能解决一个问题:

如何正确模拟生产环境的流量

如今 Web 应用的架构变得非常复杂,内部包含复杂的各种负载均衡、 服务和 RPC 调用关系,简单的发送 GET 请求到某些 URL 或者 API 接口完全无法模拟真实的流量。假如回放 HTTP 日志,操作又异常麻烦。Tcpcopy 虽然能够复制实时流量,但是操作也很复杂。之前的 亚马逊云平台的迁移 就用到了 Gor 这个工具。

Linux:Web 应用性能和压力测试工具 Gor
Linux:Web 应用性能和压力测试工具 Gor

Gor 是 Web 应用压力测试的完美方案

我一直在找一个简单又方便的解决方案,直到找到了 Gor 。Gor 是用 Golang 写的一个 HTTP 实时流量复制工具。只需要在 LB 或者 Varnish 入口服务器上执行一个进程,就可以把生产环境的流量复制到任何地方,比如 Staging 环境、Dev 环境。完美解决了 HTTP 层实时流量复制和压力测试的问题。

Gor 的功能

Gor 支持流量的放大和缩小、频率限制,这样不需要搭建和生产环境一致的服务器集群也可以正确测试。Gor 还支持根据正则表达式过滤流量,这意味着可以单独测试某个 API 服务。还可以修改 HTTP 请求头,比如替换 User-Agent, 或者增加某些 HTTP Header 。

Gor 还可以把请求记录到文件,以备回放和分析。Gor 支持和 ElasticSearch 集成,将流量存入 ES 进行实时分析。

Gor 的常用命令

简单的 HTTP 流量复制:

gor –input-raw :80 –output-http “http://staging.com”

HTTP 流量复制频率控制:

gor –input-tcp :28020 –output-http “http://staging.com|10″

HTTP 流量复制缩小:

gor –input-raw :80 –output-tcp “replay.local:28020|10%”

HTTP 流量记录到本地文件:

gor –input-raw :80 –output-file requests.gor

HTTP 流量回放和压测:

gor –input-file “requests.gor|200%” –output-http “staging.com”

HTTP 流量过滤复制:

gor –input-raw :8080 –output-http staging.com –output-http-url-regexp ^www.

最后

这个 Golang 写的 Gor 是开源的,意味着可以方便的集成到自己的架构中,可以用在压力测试平台、实时流量分析、应用层防火墙等等方面。

有用的链接

来源:http://blog.eood.cn/web-performance-testing-gor

Linux:BDA 谈互联网 MySQL 开发规范

写在前面:无规矩不成方圆。对于刚加入互联网的朋友们,肯定会接触到MySQL,MySQL作为互联网最流行的关系型数据库产品,它有它擅长的地方,也有它不足的短板,针对它的特性,结合互联网大多应用的特点,笔者根据自己多年互联网公司的MySQL DBA经验,现总结出互联网MySQL的一些开发规范,仅供参考。

Linux:BDA 谈互联网 MySQL 开发规范
Linux:BDA 谈互联网 MySQL 开发规范

基础规范 

(1) 使用INNODB存储引擎

(2) 表字符集使用UTF8

(3) 所有表都需要添加注释

(4) 单表数据量建议控制在5000W以内

(5) 不在数据库中存储图⽚、文件等大数据

(6) 禁止在线上做数据库压力测试

(7) 禁⽌从测试、开发环境直连数据库

命名规范 

(1) 库名表名字段名必须有固定的命名长度,12个字符以内

(2) 库名、表名、字段名禁⽌止超过32个字符。须见名之意

(3) 库名、表名、字段名禁⽌止使⽤用MySQL保留字

(4) 临时库、表名必须以tmp为前缀,并以⽇日期为后缀

(5) 备份库、表必须以bak为前缀,并以日期为后缀

Linux:BDA 谈互联网 MySQL 开发规范
Linux:BDA 谈互联网 MySQL 开发规范

库、表、字段开发设计规范

(1) 禁⽌使用分区表

(2) 拆分大字段和访问频率低的字段,分离冷热数据

(3) 用HASH进⾏散表,表名后缀使⽤⼗进制数,下标从0开始

(4) 按日期时间分表需符合YYYY[MM][DD][HH]格式

(5) 采用合适的分库分表策略。例如千库十表、十库百表等 

Linux:BDA 谈互联网 MySQL 开发规范
Linux:BDA 谈互联网 MySQL 开发规范

(6) 尽可能不使用TEXT、BLOB类型

(7) 用DECIMAL代替FLOAT和DOUBLE存储精确浮点数

(8) 越简单越好:将字符转化为数字、使用TINYINT来代替ENUM类型

(9) 所有字段均定义为NOT NULL

(10) 使用UNSIGNED存储非负整数

(11) INT类型固定占用4字节存储

(12) 使用timestamp存储时间

(13) 使用INT UNSIGNED存储IPV4

(14) 使用VARBINARY存储大小写敏感的变长字符串

(15) 禁止在数据库中存储明文密码,把密码加密后存储

Linux:BDA 谈互联网 MySQL 开发规范
Linux:BDA 谈互联网 MySQL 开发规范

(16) 用好数值类型字段

  • Tinyint (1Byte)
  • smallint (2Byte)
  • mediumint (3Byte)
  • int (4Byte)
  • bigint (8Byte)

类型

字节

最小值

最大值

   

(带符号的/无符号的)

(带符号的/无符号的)

TINYINT

1

-128

127

无符号

 

0

255

SMALLINT

2

-32768

32767

无符号

 

0

65535

MEDIUMINT

3

-8388608

8388607

无符号

 

0

16777215

INT

4

-2147483648

2147483647

无符号

 

0

4294967295

BIGINT

8

-9223372036854775808

9223372036854775807

无符号

 

0

18446744073709551615

如果数值字段没有那么大,就不要用 bigint

(17) 存储ip最好用int存储而非char(15)

(18) 不允许使用ENUM

(19) 避免使用NULL字段

NULL字段很难查询优化,NULL字段的索引需要额外空间,NULL字段的复合索引无效

(20) 少用text/blob,varchar的性能会比text高很多,实在避免不了blob,请拆表

(21) 数据库中不允许存储大文件,或者照片,可以将大对象放到磁盘上,数据库中存储它的路径

索引规范

(1) 索引的数量要控制:

a、单张表中索引数量不超过5个

b、单个索引中的字段数不超过5个

c、对字符串使⽤用前缀索引,前缀索引长度不超过8个字符

d、建议优先考虑前缀索引,必要时可添加伪列并建立索引

(2) 主键准则

a、表必须有主键

b、不使用更新频繁的列作为主键

c、尽量不选择字符串列作为主键

d、不使用UUID MD5 HASH这些作为主键(数值太离散了)

e、默认使⽤非空的唯一键作为主键

f、建议选择自增或发号器

(3) 重要的SQL必须被索引,比如:

a、UPDATE、DELETE语句的WHERE条件列

b、ORDER BY、GROUP BY、DISTINCT的字段

(4) 多表JOIN的字段注意以下:

a、区分度最大的字段放在前面

b、核⼼SQL优先考虑覆盖索引

c、避免冗余和重复索引

d、索引要综合评估数据密度和分布以及考虑查询和更新比例

(5) 索引禁忌

a、不在低基数列上建立索引,例如“性别”

b、不在索引列进行数学运算和函数运算

(6) 尽量不使用外键

a、外键用来保护参照完整性,可在业务端实现

b、对父表和子表的操作会相互影响,降低可用性

(7) 索引命名

非唯一索引必须以 idx_字段1_字段2命名,唯一所以必须以uniq_字段1_字段2命名,索引名称必须全部小写

(8) 新建的唯一索引必须不能和主键重复

(9) 索引字段的默认值不能为NULL

要改为其他的default或者空。NULL非常影响索引的查询效率。

(10) 反复查看与表相关的SQL,符合最左前缀的特点建立索引。

多条字段重复的语句,要修改语句条件字段的顺序,为其建立一条联合索引,减少索引数量

(11) 能使用唯一索引就要使用唯一索引,提高查询效率

(12)研发要经常使用explain,如果发现索引选择性差,必须让他们学会使用hint

SQL规范

(1) sql语句尽可能简单

大的sql想办法拆成小的sql语句(充分利用QUERY CACHE和充分利用多核CPU)

(2) 事务要简单,整个事务的时间长度不要太长

(3) 避免使用触发器、函数、存储过程

(4) 降低业务耦合度,为sacle out、sharding留有余地

(5) 避免在数据库中进⾏数学运算(MySQL不擅长数学运算和逻辑判断)

(4) 不要用select *,查询哪几个字段就select 这几个字段

(5) sql中使用到OR的改写为用 IN() (or的效率没有in的效率高)

(6) in里面数字的个数建议控制在1000以内

(7) limit分页注意效率。Limit越大,效率越低。可以改写limit,比如例子改写:

select id from tlimit 10000, 10; => select id from t where id > 10000 limit10;

(9) 使用union all替代union

(10) 避免使⽤大表的JOIN

(11) 使用group by 分组、自动排序

(12) 对数据的更新要打散后批量更新,不要一次更新太多数据

(13) 减少与数据库的交互次数

(13) 注意使用性能分析工具:Sql explain / showprofile / mysqlsla

(14) SQL语句要求所有研发,SQL关键字全部是大写,每个词只允许有一个空格

(15) SQL语句不可以出现隐式转换,比如:select id from 表 where id=’1′

(16) IN条件里面的数据数量要少,我记得应该是500个以内,要学会使用exist代替in,exist在一些场景查询会比in快

(17) 能不用NOT IN就不用NOTIN,坑太多了。。会把空和NULL给查出来

(18) 在SQL语句中,禁止使用前缀是%的like

(19) 不使用负向查询,如 not in/like

(19) 关于分页查询:程序里建议合理使用分页来提高效率limit,offset较大要配合子查询使用

(20) 禁止在数据库中跑大查询

(21) 使⽤预编译语句,只传参数,比传递SQL语句更高效;一次解析,多次使用;降低SQL注入概率

(22) 禁止使⽤order by rand()

(23) 禁⽌单条SQL语句同时更新多个表

流程规范

(1) 所有的建表操作需要提前告知该表涉及的查询sql;

(2) 所有的建表需要确定建立哪些索引后才可以建表上线;

(3) 所有的改表结构、加索引操作都需要将涉及到所改表的查询sql发出来告知DBA等相关人员;

(4) 在建新表加字段之前,要求研发至少要提前3天邮件出来,给dba们评估、优化和审核的时间

(5)批量导入、导出数据必须提前通知DBA协助观察

(6) 禁⽌在线上从库执行后台管理和统计类查询

(7) 禁⽌有super权限的应用程序账号存在

(8) 推广活动或上线新功能必须提前通知DBA进⾏行流量评估

(9) 不在业务高峰期批量更新、查询数据库

本文转自《运维帮》

Linux:BDA 谈互联网 MySQL 开发规范
Linux:BDA 谈互联网 MySQL 开发规范

来源:http://mp.weixin.qq.com/s?__biz=MzA3MzYwNjQ3NA==∣=207132223&idx;=1&sn;=f5d98146f28235d91fe3e675cead4ce5&scene;=5#rd

Linux:Sphinx : 高性能SQL全文检索引擎

Sphinx是一款基于SQL的高性能全文检索引擎,Sphinx的性能在众多全文检索引擎中也是数一数二的,利用Sphinx,我们可以完成比数据库本身更专业的搜索功能,而且可以有很多针对性的性能优化。

Linux:Sphinx : 高性能SQL全文检索引擎
Linux:Sphinx : 高性能SQL全文检索引擎

Sphinx的特点

  • 快速创建索引:3分钟左右即可创建近100万条记录的索引,并且采用了增量索引的方式,重建索引非常迅速。
  • 闪电般的检索速度:尽管是1千万条的大数据量,查询数据的速度也在毫秒级以上,2-4G的文本量中平均查询速度不到0.1秒。
  • 为很多脚本语言设计了检索API,如PHP,Python,Perl,Ruby等,因此你可以在大部分编程应用中很方便地调用Sphinx的相关接口。
  • 为MySQL设计了一个存储引擎插件,因此如果你在MySQL上使用Sphinx,那简直就方便到家了。
  • 支持分布式搜索,可以横向扩展系统性能。

PHP+MySQL+Sphinx 搜索引擎架构图

Linux:Sphinx : 高性能SQL全文检索引擎
Linux:Sphinx : 高性能SQL全文检索引擎

在MySQL中安装Sphinx

Sphinx在MySQL上安装有两种方式:

  • 第一种方式是采用API调用,我们可以使用PHP,Python,Perl,Ruby等编程语言的API函数进行查询,这种方式不必重新编译MySQL,模块间改动比较少,相对灵活。
  • 第二种需要重新编译MySQL,将Sphinx以插件的方式编译到MySQL中去,这种方式对程序改动比较少,仅仅需要改动SQL语句即可,但前提是你的MySQL版本必须在5.1以上。

下面是第一种安装方式:

#下载最新稳定版
wget http://www.sphinxsearch.com/downloads/sphinx-0.9.9.tar.gz
tar xzvf sphinx-0.9.9.tar.gz
cd sphinx-0.9.9
./configure --prefix=/usr/local/sphinx/   --with-mysql  --enable-id64
make
make install

Sphinx中文分词插件Coreseek安装

注:coreseek的安装教程来自这里,下面是详细过程:

安装升级autoconf

因为coreseek需要autoconf 2.64以上版本,因此需要升级autoconf,不然会报错。从http://download.chinaunix.net/download.php?id=29328&ResourceID=648 下载autoconf-2.64.tar.bz2,安装方法如下:

tar -jxvf autoconf-2.64.tar.bz2
cd autoconf-2.64
./configure
make
make install

下载coreseek

新版本的coreseek将词典和sphinx源程序放在了一个包中,因此只需要下载coreseek包就可以了。

wget http://www.wapm.cn/uploads/csft/3.2/coreseek-3.2.14.tar.gz

安装mmseg(coreseek所使用的词典)

tar xzvf coreseek-3.2.14.tar.gz
cd mmseg-3.2.14
./bootstrap    #输出的warning信息可以忽略,如果出现error则需要解决
./configure --prefix=/usr/local/mmseg3
make && make install
cd ..

安装coreseek(sphinx)

cd csft-3.2.14
sh buildconf.sh    #输出的warning信息可以忽略,如果出现error则需要解决
./configure --prefix=/usr/local/coreseek  --without-unixodbc --with-mmseg --with-mmseg-includes=/usr/local/mmseg3/include/mmseg/ --with-mmseg-libs=/usr/local/mmseg3/lib/ --with-mysql
make && make install
cd ..

测试mmseg分词和coreseek搜索

备注:需要预先设置好字符集为zh_CN.UTF-8,确保正确显示中文,我的系统字符集为en_US.UTF-8也是可以的。

cd testpack
cat var/test/test.xml  #此时应该正确显示中文
/usr/local/mmseg3/bin/mmseg -d /usr/local/mmseg3/etc var/test/test.xml
/usr/local/coreseek/bin/indexer -c etc/csft.conf --all
/usr/local/coreseek/bin/search -c etc/csft.conf 网络搜索
此时正确的应该返回
words:
1. '网络': 1 documents, 1 hits
2. '搜索': 2 documents, 5 hits

生成 mmseg词库及配置文件

新版本的已经自动生成。

总结

Sphinx作为一款高性能的SQL全文检索引擎,值得开发者继续关注,尤其是它多语言的API支持,使开发者可以更方便地应用。

来源:http://www.codeceo.com/article/sphinx-sql-search-engine.html

Linux:不停止 MySQL 服务增加从库的两种方式

现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库。前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作。

 一般在线增加从库有两种方式,一种是通过mysqldump备份主库,恢复到从库,mysqldump是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长。另一种是通过xtrabackup工具备份主库,恢复到从库,xtrabackup是物理备份,备份速度快,不锁表。为什么不锁表?因为自身会监控主库日志,如果有更新的数据,就会先写到一个文件中,然后再回归到备份文件中,从而保持数据一致性。

Linux:不停止 MySQL 服务增加从库的两种方式
Linux:不停止 MySQL 服务增加从库的两种方式

服务器信息:

  • 主库:192.168.18.212(原有)
  • 从库1:192.168.18.213(原有)
  • 从库2:192.168.18.214(新增)
  • 数据库版本:MySQL5.5
  • 存储引擎:Innodb
  • 测试库名:weibo

一、mysqldump方式

MySQL主从是基于binlog日志,所以在安装好数据库后就要开启binlog。这样好处是,一方面可以用binlog恢复数据库,另一方面可以为主从做准备。

原有主库配置参数如下:

# vi my.cnf
server-id = 1             #id要唯一
log-bin = mysql-bin         #开启binlog日志
auto-increment-increment = 1   #在Ubuntu系统中MySQL5.5以后已经默认是1
auto-increment-offset = 1
slave-skip-errors = all      #跳过主从复制出现的错误

1. 主库创建同步账号

mysql> grant all on *.* to 'sync'@'192.168.18.%' identified by 'sync';

2. 从库配置MySQL

# vi my.cnf
server-id = 3             #这个设置3
log-bin = mysql-bin         #开启binlog日志
auto-increment-increment = 1   #这两个参数在Ubuntu系统中MySQL5.5以后都已经默认是1
auto-increment-offset = 1
slave-skip-errors = all      #跳过主从复制出现的错误

3. 备份主库

# mysqldump -uroot -p123 --routines --single_transaction --master-data=2 --databases weibo > weibo.sql

参数说明:

–routines:导出存储过程和函数

–single_transaction:导出开始时设置事务隔离状态,并使用一致性快照开始事务,然后unlock tables;而lock-tables是锁住一张表不能写操作,直到dump完毕。

–master-data:默认等于1,将dump起始(change master to)binlog点和pos值写到结果中,等于2是将change master to写到结果中并注释。

4. 把备份库拷贝到从库

# scp weibo.sql root@192.168.18.214:/home/root

5. 在主库创建test_tb表,模拟数据库新增数据,weibo.sql是没有的

mysql> create table test_tb(id int,name varchar(30));

6. 从库导入备份库

# mysql -uroot -p123 -e 'create database weibo;'
# mysql -uroot -p123 weibo < weibo.sql

7. 在备份文件weibo.sql查看binlog和pos值

# head -25 weibo.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=107;   #大概22行

8. 从库设置从这个日志点同步,并启动

mysql> change master to master_host='192.168.18.212',
    -> master_user='sync',
    -> master_password='sync',
    -> master_log_file='mysql-bin.000001',
    -> master_log_pos=107;
mysql> start slave;
mysql> show slave statusG;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id:    90
Current database: *** NONE ***
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.18.212
                  Master_User: sync
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 358
               Relay_Log_File: mysqld-relay-bin.000003
                Relay_Log_Pos: 504
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
......

9. 从库查看weibo库里面的表

可以看到IO和SQL线程均为YES,说明主从配置成功。

mysql> show tables;
+---------------------------+
| Tables_in_weibo           |
+---------------------------+
| test_tb                   |

发现刚才模拟创建的test_tb表已经同步过来!

二、xtrabackup方式(推荐)

在上面配置基础上做实验,先删除掉从库配置:

mysql> stop slave;         #停止同步
mysql> reset slave;        #清除从连接信息
mysql> show slave statusG;   #再查看从状态,可以看到IO和SQL线程都为NO
mysql> drop database weibo;   #删除weibo库

此时,从库现在和新装的一样,继续前进!

1. 主库使用xtrabackup备份

# innobackupex --user=root --password=123 ./

生成一个以时间为命名的备份目录:2015-07-01_16-49-43

# ll 2015-07-01_16-49-43/
total 18480
drwxr-xr-x 5 root root     4096 Jul  1 16:49 ./
drwx------ 4 root root     4096 Jul  1 16:49 ../
-rw-r--r-- 1 root root      188 Jul  1 16:49 backup-my.cnf
-rw-r----- 1 root root 18874368 Jul  1 16:49 ibdata1
drwxr-xr-x 2 root root     4096 Jul  1 16:49 mysql/
drwxr-xr-x 2 root root     4096 Jul  1 16:49 performance_schema/
drwxr-xr-x 2 root root    12288 Jul  1 16:49 weibo/
-rw-r--r-- 1 root root       21 Jul  1 16:49 xtrabackup_binlog_info
-rw-r----- 1 root root       89 Jul  1 16:49 xtrabackup_checkpoints
-rw-r--r-- 1 root root      563 Jul  1 16:49 xtrabackup_info
-rw-r----- 1 root root     2560 Jul  1 16:49 xtrabackup_logfile

2. 把备份目录拷贝到从库上

# scp -r 2015-07-01_16-49-43 root@192.168.18.214:/home/root

3. 从库上把MySQL服务停掉,删除datadir目录,将备份目录重命名为datadir目录

# sudo rm -rf /var/lib/mysql/
# sudo mv 2015-07-01_16-49-43/ /var/lib/mysql
# sudo chown mysql.mysql -R /var/lib/mysql
# sudo /etc/init.d/mysql start
# ps -ef |grep mysql    #查看已经正常启动
mysql     8832     1  0 16:55 ?        00:00:00 /usr/sbin/mysqld

4. 在主库创建test_tb2表,模拟数据库新增数据

mysql> create table test_tb2(id int,name varchar(30));

5. 从备份目录中xtrabackup_info文件获取到binlog和pos位置

# cat /var/lib/mysql/xtrabackup_info
uuid = 201af9db-1fce-11e5-96b0-525400e4239d
name =
tool_name = innobackupex
tool_command = --user=root --password=... ./
tool_version = 1.5.1-xtrabackup
ibbackup_version = xtrabackup version 2.2.11 based on MySQL server 5.6.24 Linux (x86_64) (revision id: )
server_version = 5.5.43-0ubuntu0.12.04.1-log
start_time = 2015-07-01 16:49:43
end_time = 2015-07-01 16:49:46
lock_time = 1
binlog_pos = filename 'mysql-bin.000001', position 429    #这个位置
innodb_from_lsn = 0
innodb_to_lsn = 1598188
partial = N
incremental = N
format = file
compact = N
compressed = N

6. 从库设置从这个日志点同步,并启动

mysql> change master to master_host='192.168.18.212',
    -> master_user='sync',
    -> master_password='sync',
    -> master_log_file='mysql-bin.000001',
    -> master_log_pos=429;
mysql> start slave;
mysql> show slave statusG;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.18.212
                  Master_User: sync
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 539
               Relay_Log_File: mysqld-relay-bin.000002
                Relay_Log_Pos: 363
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
......

7. 从库查看weibo库里面的表

可以看到IO和SQL线程均为YES,说明主从配置成功。

mysql> show tables;
+---------------------------+
| Tables_in_weibo           |
+---------------------------+
| test_tb                   |
| test_tb2                  |

发现刚才模拟创建的test_tb2表已经同步过来。

来源:http://lizhenliang.blog.51cto.com/7876557/1669829

Linux:谈谈软件包

Linux:谈谈软件包
Linux:谈谈软件包
我学习C语言的时候是在大学课程上,老实说,能理解那些语言概念就很不容易了,对于软件包管理这件事听都没听说过。但真实情况下,大部分的软件项目都不可能是从零开始的,我们总要依赖某些开源的或者团队自己开发的工具和框架库来帮助工作,我是学习java的时候才慢慢听说了maven
maven的核心配置是pom.xml文件,开发者可以根据需要在其中列出项目的依赖包,像这样:

org.springframework
spring-core
4.1.5.RELEASE

maven命令在工作时会找到spring-core所依赖的其它库

$ mvn dependency:tree
......
[INFO] sample_java:sample_java:war:1.0-SNAPSHOT
[INFO] +- org.springframework:spring-core:jar:4.1.5.RELEASE:compile
[INFO] |  - commons-logging:commons-logging:jar:1.2:compile
......

但是这样有个问题,某些间接依赖会导致在不同时候打出不同的包,比如上述这样个例子,两次打包期间如果commons-logging发布了新版本,那么两次打包的内容就不一样了,如果遇到新版本的差异,开发人员可能会莫名其妙。
ruby社区针对这个问题发明了一个叫做bundle的工具,它也有个Gemfile文件用来记录直接的依赖库,类似mvn,但是bundle多了一个功能,工程师可以在当前项目下执行bundle install 命令,bundle系统将根据当前的软件仓库状态计算出间接依赖,并将这些间接依赖锁定到某个版本,内容写在 Gemfile.lock 文件中。比如这个简单的例子:

source 'https://ruby.taobao.org'
gem 'activesupport'

生成的Gemfile.lock是这样:

GEM
remote: https://ruby.taobao.org/
specs:
activesupport (4.2.3)
  i18n (~> 0.7)
  json (~> 1.7, >= 1.7.7)
  minitest (~> 5.1)
  thread_safe (~> 0.3, >= 0.3.4)
  tzinfo (~> 1.1)
i18n (0.7.0)
json (1.8.3)
minitest (5.7.0)
thread_safe (0.3.5)
tzinfo (1.2.2)
  thread_safe (~> 0.1)
PLATFORMS
ruby
DEPENDENCIES
activesupport

当再次执行bundle命令时,bundle系统会根据Gemfile.lock文件来决定间接依赖,所以开发者通常把这个文件放入版本控制系统,确保所有人和线上都用同一份Gemfile.lock,就能避免上述的问题。
我一直觉得bundle的做法是最先进的,不过和做nodejs开发的同学聊天时,了解到了npm的做法颇为特别,虽然不见得比bundle更好,却是各有优劣。
npm的做法是直接把被依赖的库放入当前库的node_modules目录,依赖库也以此类推,它的核心文件是package.json,比如这个例子:

$  cat package.json
{
"name": "sample_js",
"version": "1.0.0",
"dependencies": {
"browserify": "10.2.4"
}
}
$ npm install
$ npm dedupe

查看一下依赖库

$  ls node_modules/browserify/node_modules
JSONStream             concat-stream          glob                   labeled-stream-splicer readable-stream        syntax-error
acorn                  console-browserify     has                    module-deps            readable-wrap          through2
assert                 constants-browserify   htmlescape             os-browserify          resolve                timers-browserify
browser-pack           crypto-browserify      http-browserify        parents                sha.js                 tty-browserify
browser-resolve        defined                https-browserify       path-browserify        shasum                 url
browserify-zlib        deps-sort              indexof                process                shell-quote            util
buffer                 domain-browser         inherits               punycode               stream-browserify      vm-browserify
builtins               duplexer2              insert-module-globals  querystring-es3        string_decoder         xtend
commondir              events                 isarray                read-only-stream       subarg

查看一下依赖库的依赖库

$ ls node_modules/browserify/node_modules/crypto-browserify/node_modules
bn.js           browserify-aes  browserify-sign create-hash     diffie-hellman  parse-asn1      public-encrypt
brorand         browserify-rsa  create-ecdh     create-hmac     elliptic        pbkdf2          randombytes

这种做法实际上是在开发环节就确定并下载了间接依赖的库,可以看做在开发者手里就完成了打包,这么做有什么好处?
相比mavennpmbundle更具备一致性,无论到哪里,bundle系统都保证使用lock版本,不会有“失控”的依赖库;而相对于bundlenpm可以允许在一个项目中依赖同一个库的不同版本,这比较灵活。
但是这么做也有缺点,有些js开发者就吐槽这一点,认为浪费了内存——不同库依赖同一个库时,都会在自己的node_modules目录下存放一份被依赖库的代码。从这个角度看,bundle又显得有些优势,因为require在同一个ruby进程中是有缓存的,不会额外浪费内存。
打个比方吧,bundle就好像大规模的军事单位,除了作战部队外还有专门的,好处是可以统一划拨管理,降低了维护成本,缺点是有些细微的差别不好满足。而npm就好像一个精干的小分队,每个人带自己适合的食物,虽然可能并不丰富,但是每个单兵都是一个可以独立生存的单元。
我把npm这种方式称为“自带干粮”。软件技术中,“自带干粮”的设计思想有很多应用场景,比如动态编译和静态编译。
如果你喜欢自己从源码编译软件,那么多半熟悉LD_LIBRARY_PATH这个环境变量,这是用来指明动态链接库查找路径的,我们常常把一些模块代码编译为后缀为 so 的动态链接库文件,然后再运行时动态载入。
与之相比,还有一种做法叫静态编译,比如这样的命令:

/opt/apache_src $ ./configure --prefix=/usr/ --enable-file-cache

其中的enable-file-cache是静态编译的选项,使用这类选项,编译工具会将模块直接编译进入最终的执行文件(比如apache的执行文件就是httpd)。
使用动态链接库还是选择静态编译?应该说两种方式各有优劣,前者可以减少内存消耗,避免装入暂时用不到的代码,而后者则是某种角度的“自带干粮”,这样编译的可执行程序,迁移起来比较容易,不会由于目标系统上没有相应的动态链接库而运行失败。
Go语言是 google 创建的一门语言,它有很多独特的设计,其中之一就是——它是静态编译的,这一点曾经让很多人诟病,认为它写一个hello world都要输出很大的可执行文件。
但是从另外一个角度看这个做法很有价值,Go语言的定位是系统级编程,这类程序和应用软件不同,它往往比较底层,本身就是其它软件的基础,因此对稳定性很重视,除了硬件这种不得不考虑的因素,其它方面干扰越少越好,使用静态链接方式产生两个好处:

  • 降低迁移成本:在一个linux里编译好的Go程序,通常可以直接copy到其它linux上使用,而如果依赖动态链接库,那么可能由于目标系统上缺乏动态链接库而失败,这样,Go程序的安装复杂性会很高,这对基础的系统软件是不利的。
  • 外部错误干扰bug定位:即使目标系统上有所需的动态链接库,也不一定就没有问题,由于版本依赖等问题,目标系统的动态链接库未必和本来设想的相同,如果由于外部错误导致bug,而开发人员并不知道这一情况,对bug定位无疑是一个灾难。

Go语言具备这些好处并不是偶然的,作为大规模集群计算起家的互联网公司,Google对于系统的横向扩展能力、可靠性、故障恢复能力都有很高的要求,自带干粮的语言可以很好的帮助实现这些目标:

  • 横向扩展能力:这个和迁移成本相关,由于不再需要动态链接库的配合,应用程序可以很方便完整的在新系统上部署,因此,一旦需要横向扩展,至少在软件安装方面,Go语言就有了很大的便利性。
  • 可靠性:Google的哲学是,通过软件而不是硬件提供可靠性。那么,如果硬件的可靠性不可依赖,软件系统的可靠性和容错就要通过类似备份之类的冗余计算来得到,这时,一个“自带干粮”的应用程序显然很容易部署为幂等的集群,因此可以在很大程度上帮助实现冗余计算。
  • 故障恢复能力:这将受益于对外部干扰的排除,由于“自带干粮”,Go程序已经包含了bug分析的几乎全部信息,开发人员不需要依靠线上环境,在线下就能分析界定问题。

这样看来,“自带干粮”的做法其实非常适合互联网应用的场景,这里充斥着“集群”、“弹性扩展”、“服务幂等化”的做法,如果我们从事互联网应用领域,那么理解“自带干粮”的做法很有价值。
这个做法其实并不神秘,“自带干粮”的理念的一个重要体现,就是我们很熟悉的“打包”环节。

Linux服务端开发的项目,通常都会有一个“打包”环节,很多人并不完全理解这个环节的作用,实际上,这只是“自带干粮”原则在项目管理中的落实而已。

举两个例子,ruby bundle的打包是这样的:

$ bundle package
...
$ ls -l vendor/cache
total 1744
-rw-r--r--  1 john  staff   322K  7  9 03:48 activesupport-4.2.3.gem
-rw-r--r--  1 john  staff    57K  7  9 03:48 i18n-0.7.0.gem
-rw-r--r--  1 john  staff   149K  7  9 03:48 json-1.8.3.gem
-rw-r--r--  1 john  staff    70K  7  9 03:48 minitest-5.7.0.gem
-rw-r--r--  1 john  staff   118K  7  9 03:48 thread_safe-0.3.5.gem
-rw-r--r--  1 john  staff   144K  7  9 03:48 tzinfo-1.2.2.gem

bundle packge命令把需要使用的gem包统统放入vendor/cache目录,那么当前目录就是一个“自带干粮”的体系。
再看Java:

$ mvn pacakge
...
$ ls -l target/*.war
-rw-r--r--  1 john  staff   1.0M  7  9 03:51 target/sample_java.war

mvn命令最后会输出一个war文件,按照javaEE的相关规范,它自身包含了所有依赖的第三方jar,所以这也是一个“自带干粮”的产出。
结合上面的例子,我们可以得出结论:打包这个行为本质上就是通过“自带干粮”的方式把相关依赖完全纳入控制,这使得我们的交付物能够很容易的在线上水平扩展并减少环境影响。
那么,考虑到大多数语言或者框架都有打包机制,是不是Go语言相对与ruby或者java其实没有什么优势呢?答案是未必,这里需要分开讨论:

  • ruby(使用bundle作为包管理工具):因为是虚拟机语言,通常情况下,bundle的“打包”仅限于ruby语言的各种gem,有些对动态链接库的依赖并没有纳入管理,因此,虽然“自带干粮”却会有“忘记带饭碗”的尴尬情况
  • java(使用maven作为包管理工具):同上,也是虚拟机语言,不过,和ruby不同的是,java由于社区风格的差异,通常习惯于使用pure java的方式解决问题,因此,虽然理论上也可能依赖其它动态链接库,但是实践中很少遇到这种软件包(当然,很少不等于没有)。

显然,由于考虑到操作系统层面的动态链接库问题,ruby和java这种虚拟机语言必须面对打包不完整的问题(与之相比,Go语言除了Glibc基本算是没有依赖),ruby的bundle没有处理这个问题,java则付出了“自己重新搞一遍”的代价。

说到这里自然会产生一个问题——即使是Go,也需要glibc,因此切换OS时还是需要交叉编译技术的,那有没有更“完备”的方案呢?比如把所有依赖都隔离开?
答案是Docker,它把基础库也放入了镜像,因此,从打包这件事来看是Docker image是真正的“自带干粮”并且没有遗漏的做法,未来的Build系统,以Docker image进行交付是大势所趋。

包管理的做法各不相同,然而基本思路差别不大,理解“打包”的目的,是学生和软件工程师的一个重要区别。
来源:http://dockone.io/article/497

Linux:godoc 技巧与注意事项

意义

文档对于代码的意义不用多说。在golang bolg中已经给出了详细的描述http://blog.golang.org/godoc-documenting-go-code

Linux:godoc 技巧与注意事项
Linux:godoc 技巧与注意事项

我在实战中踩到了不少坑,这里给出更详细的解释以及注意事项。

我们针对golang源码中的注释进行分析得到如下结果。

针对Package的文档

Synopsis

参考http://golang.org/pkg/中的Synopsis。这句话主要出现在针对Package注释中的开头位置。

OverView

参考http://golang.org/pkg/archive/tar/。是针对Package中的注释出现的。如果出现连接,无需标注,生成文档的时候自动会处理成连接

参考例子与注意事项

包: [$GOROOT/src/encoding/json]

文件:encode.go

// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package json implements encoding and decoding of JSON objects as defined in
// RFC 4627. The mapping between JSON objects and Go values is described
// in the documentation for the Marshal and Unmarshal functions.
//
// See "JSON and Go" for an introduction to this package:
// http://golang.org/doc/articles/json_and_go.html
package json

从注释中可以看出第四行是断开的,从第四行开始到package json都为针对包的注释。

目录中Synopsis出现内容为:Package json implements encoding and decoding of JSON objects as defined in RFC 4627.

参考注意事项:

  1. 在代码的package上面
  2. 在上面不能有空行
  3. 注释不能断开(中间不能有空行)
  4. 最前面一句话会模块的summary会出现在package index中
  5. 第一句话以及之后的内容会出现在OverView中

对比文件:decode.go

// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Represents JSON data structure using native Go types: booleans, floats,
// strings, arrays, and maps.
package json

在package上面有空行,因此只是针对文件的注释不显示在godoc中。

针对Function

例子:

// Marshaler is the interface implemented by objects that
// can marshal themselves into valid JSON.
type Marshaler interface {
	MarshalJSON() ([]byte, error)
}

我们可以看到:

  1. 在函数上面进行注释
  2. 中间不能有空行
  3. 开始需要 [空格]FunctionName[空格] Summary
  4. 然后继续说明
  5. 想圈起来说明参数: 加缩进

进阶技巧:

例子同理于:Function Package

// Marshaler is the interface implemented by objects that
/*
can marshal themselves into valid JSON.
*/
type Marshaler interface {
	MarshalJSON() ([]byte, error)
}

这样不算断开,写文档的时候就方便多了。

针对BUG

// BUG(src): Mapping between XML elements and data structures is inherently flawed:
// an XML element is an order-dependent collection of anonymous
// values, while a data structure is an order-independent collection
// of named values.
// See package json for a textual representation more suitable
// to data structures.

godoc会先查找:[空格]BUG

然后显示在Package说明文档最下面,例子:http://golang.org/pkg/encoding/xml/

针对Example

  1. 文件名惯用:example_test.go(其他也可以)
  2. 包名: apckage_test
  3. 方法名:
    • OverView中: Example
    • 方法中: Example[FuncName]
    • 方法中+一些模式:Example[FuncName]_[Mod]

例子查看:http://golang.org/pkg/errors/

Example文件(example_test.go):

// Copyright 2012 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package errors_test
import (
	"fmt"
	"time"
)
// MyError is an error implementation that includes a time and message.
type MyError struct {
	When time.Time
	What string
}
func (e MyError) Error() string {
	return fmt.Sprintf("%v: %v", e.When, e.What)
}
func oops() error {
	return MyError{
		time.Date(1989, 3, 15, 22, 30, 0, 0, time.UTC),
		"the file system has gone away",
	}
}
func Example() {
	if err := oops(); err != nil {
		fmt.Println(err)
	}
	// Output: 1989-03-15 22:30:00 +0000 UTC: the file system has gone away
}
  1. 注意文件名为:example_test.go
  2. 注意package名为 errors_test
  3. 针对Function的注释会出现在网页的Example中
  4. 如果函数名直接叫Example会直接显示在OverView中

参考文件(errors_test.go):

// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package errors_test
import (
	"errors"
	"fmt"
	"testing"
)
func TestNewEqual(t *testing.T) {
	// Different allocations should not be equal.
	if errors.New("abc") == errors.New("abc") {
		t.Errorf(`New("abc") == New("abc")`)
	}
	if errors.New("abc") == errors.New("xyz") {
		t.Errorf(`New("abc") == New("xyz")`)
	}
	// Same allocation should be equal to itself (not crash).
	err := errors.New("jkl")
	if err != err {
		t.Errorf(`err != err`)
	}
}
func TestErrorMethod(t *testing.T) {
	err := errors.New("abc")
	if err.Error() != "abc" {
		t.Errorf(`New("abc").Error() = %q, want %q`, err.Error(), "abc")
	}
}
func ExampleNew() {
	err := errors.New("emit macho dwarf: elf header corrupted")
	if err != nil {
		fmt.Print(err)
	}
	// Output: emit macho dwarf: elf header corrupted
}
// The fmt package's Errorf function lets us use the package's formatting
// features to create descriptive error messages.
func ExampleNew_errorf() {
	const name, id = "bimmler", 17
	err := fmt.Errorf("user %q (id %d) not found", name, id)
	if err != nil {
		fmt.Print(err)
	}
	// Output: user "bimmler" (id 17) not found
}
  1. ExampleNew就是针对New的例子
  2. ExampleNew_errorf 给例子加名字详细效果可以查看这里

针对godoc命令

我常用两种方式:

  1. godoc -http=:6060 直接运行网页上的版本,很方便
  2. godoc package [name ...] 在开发的时候文档速查

总结

一般工程中搞定这些基本就够了。详细的还是要动手做一做。

我没搞定的:怎么能显示成Main函数的,并且能跑Goplayground

来源:http://www.philo.top/2015/07/10/golang-doc/

Linux:lolcat :一个在 Linux 终端中输出彩虹特效的命令行工具

那些相信 Linux 命令行是单调无聊且没有任何乐趣的人们,你们错了,这里有一些有关 Linux 的文章,它们展示着 Linux 是如何的有趣和“淘气” 。

在本文中,我将讨论一个名为“lolcat”的小工具 – 它可以在终端中生成彩虹般的颜色。

为终端生成彩虹般颜色的输出的 Lolcat 命令

为终端生成彩虹般颜色的输出的 Lolcat 命令

何为 lolcat ?

Lolcat 是一个针对 Linux,BSD 和 OSX 平台的工具,它类似于 cat 命令,并为 cat的输出添加彩虹般的色彩。 Lolcat 主要用于在 Linux 终端中为文本添加彩虹般的色彩。

在 Linux 中安装 Lolcat

1. Lolcat 工具在许多 Linux 发行版的软件仓库中都可获取到,但可获得的版本都有些陈旧,而你可以通过 git 仓库下载和安装最新版本的 lolcat。

由于 Lolcat 是一个 ruby gem 程序,所以在你的系统中必须安装有最新版本的 RUBY。

# apt-get install ruby      [在基于 APT 的系统中]
# yum install ruby          [在基于 Yum 的系统中]
# dnf install ruby          [在基于 DNF 的系统中]

一旦 ruby 软件包安装成功,请确保验证安装的 ruby 的版本。

# ruby --version
ruby 2.1.5p273 (2014-11-13) [x86_64-linux-gnu]

2. 接着使用下面的命令来从 lolcat 的 git 仓库中下载和安装最新版本的 lolcat。

# wget https://github.com/busyloop/lolcat/archive/master.zip
# unzip master.zip
# cd lolcat-master/bin
# gem install lolcat

一旦 lolcat 安装后,你可以检查它的版本号。

# lolcat --version
lolcat 42.0.99 (c)2011 moe@busyloop.net

Lolcat 的用法

3. 在开始使用 lolcat 之前,使用下面的命令来了解它可用的选项和其帮助文档。

# lolcat -h

Lolcat 的帮助文档

Lolcat 的帮助文档

4. 接着, 通过管道连接 lolcat 和其他命令,例如 ps, date 和 cal:

# ps | lolcat
# date | lolcat
# cal | lolcat

ps 命令的输出

ps 命令的输出

Date 的输出

Date 的输出

Calendar 的输出

Calendar 的输出

5. 使用 lolcat 来展示一个脚本文件的代码:

# lolcat test.sh

用 lolcat 来展示代码

用 lolcat 来展示代码

6. 通过管道连接 lolcat 和 figlet 命令。Figlet 是一个展示由常规的屏幕字符组成的巨大字符串的应用。我们可以通过管道将 figlet 的输出连接到 lolcat 中来展示出如下的多彩输出:

# echo I ❤ Tecmint | lolcat
# figlet I Love Tecmint | lolcat

多彩的文字

多彩的文字

: 注意, ❤ 是一个 unicode 字符。要安装 figlet,你需要像下面那样使用 yum 和 apt 来得到这个软件包:

# apt-get figlet
# yum install figlet
# dnf install figlet

7. 给文本赋予彩虹颜色的动画:

$ echo I ❤ Tecmit | lolcat -a -d 500

动的文本

动的文本

这里选项 -a指的是 Animation(动画), -d指的是 duration(持续时间)。在上面的例子中,持续 500 次动画。

8. 在彩虹般的颜色下阅读 man 页(例如 man ls):

# man ls | lolcat

多彩地显示文件

多彩地显示文件

9. 通过管道连接 lolcat 和 cowsay。cowsay 是一个可配置的正在思考或说话的奶牛,这个程序也支持其他的动物。

使用下面的命令来安装 cowsay :

# apt-get cowsay
# yum install cowsay
# dnf install cowsay

安装后,使用下面的命令来显示在 cowsay 中的所有动物:

# cowsay -l

样例输出

Cow files in /usr/share/cowsay/cows:
apt beavis.zen bong bud-frogs bunny calvin cheese cock cower daemon default
dragon dragon-and-cow duck elephant elephant-in-snake eyes flaming-sheep
ghostbusters gnu head-in hellokitty kiss kitty koala kosh luke-koala
mech-and-cow meow milk moofasa moose mutilated pony pony-smaller ren sheep
skeleton snowman sodomized-sheep stegosaurus stimpy suse three-eyes turkey
turtle tux unipony unipony-smaller vader vader-koala www

通过管道连接 lolcat 和 cowsay 后的输出,并且使用了‘gnu’形象的 cowfile。

# cowsay -f gnu ☛ Tecmint ☚ is the best Linux Resource Available online | lolcat

使用 Lolcat 的 Cowsay

使用 Lolcat 的 Cowsay

: 你可以在将 lolcat 和其他任何命令用管道连接起来在终端中得到彩色的输出。

10. 你可以为最常用的命令创建别名来使得命令的输出呈现出彩虹般的色彩。你可以像下面那样为 ‘ls -l‘ 命令创建别名,这个命令输出一个目录中包含内容的列表。

# alias lolls="ls -l | lolcat"
# lolls

多彩的 Alias 命令

多彩的 Alias 命令

你可以像上面建议的那样,为任何命令创建别名。为了使得别名永久生效,你需要添加相关的代码(上面的代码是 ls -l 的别名) 到 ~/.bashrc 文件中,并登出后再重新登录来使得更改生效。

现在就是这些了。我想知道你是否曾经注意过 lolcat 这个工具?你是否喜欢这篇文章?欢迎在下面的评论环节中给出你的建议和反馈。喜欢并分享我们,帮助我们传播。


via: http://www.tecmint.com/lolcat-command-to-output-rainbow-of-colors-in-linux-terminal/

作者:Avishek Kumar 译者:FSSlc 校对:wxy

本文由 LCTT 原创翻译,Linux中国 荣誉推出

来源:https://linux.cn/article-5798-1.html

Linux:Ubuntu Linux 系统的分区方案

一、Linux 分区概念   首先介绍一下linux中的分区概念,这个可是把一开始学习的我害苦了。在 Linux 中规定,每一个硬盘设备最多能有 4 个主分区(其中包含扩展分区)构成,任何一个扩展分区都要占用一个主分区号码,也就是在一个硬盘中,主分区和扩展分区一共最多是 4 个。对于早期的 DOS 和 Windows(Windows 2000 以前的版本),系统只承认一个主分区,可以通过在扩展分区上增加逻辑盘符(逻辑分区)的方法,进一步地细化分区。   主分区的作用就是计算机用来进行启动操作系统的,因此每一个操作系统的启动,或者称作是引导程序,都应该存放在主分区上。这就是主分区和扩展分区及逻辑分区 的最大区别。我们在指定安装引导 Linux 的 bootloader 的时候,都要指定在主分区上,就是最好的例证。   Linux规定了主分区(或者扩展分区)占用 1 至 16 号码中的前 4 个号码。以第一个 IDE 硬盘为例说明,主分区(或者扩展分区)占用了 hda1、hda2、hda3、hda4,而逻辑分区占用了 hda5 到 hda16 等 12 个号码。因此,Linux 下面每一个硬盘总共最多有 16 个分区。   对于逻辑分区,Linux 规定它们必须建立在扩展分区上(在 DOS 和 Windows 系统上也是如此规定),而不是主分区上。因此,我们可以看到扩展分区能够提供更加灵活的分区模式,但不能用来作为操作系统的引导。   以前对这些概念不熟,分区上走了很多弯路。那么,到底什么样是一个好的分区方案,我认为见仁见智,我是这样分的。原则上/ 和/home基本上最好是要单独挂载两个分区,因为home可以看成是windows中的my document,自己个人资料多的话home要大一些。/小一点无所谓,据说至少2G,我也没有试验过。其他的诸如/tmp和/var由于活动文件特别 多,为了避免他们的文件碎片对其他区的影响,最好他们挂一个区。最后/opt主要安装大型软件,如果有多余的分区就给他挂一个吧。 二、开始分区   ok, 我就这样看,首先分一个100M的主分区出来,挂载boot.grub启动时需要的文件都在/ b o o t 目录。这样就算工作分区出了问题,只要这个分区没有问题,同样可以启动。因此最好的办法就是专门为根文件分一个区,大小一般最多64M,我为了保险给了 100M。   之后的分区全部以扩展分区形式存在,扩展分区下很多逻辑分区。   首先创建一个交换分区,大小是无力内存的一倍到两倍大。如果你的内存和我一样是1G,就划1G好了。事实上基本用不到这么大。分区格式记着改成linux-swap。   然后创建一个尽量大的分区,给/usr,因为这里存放有大部分的系统软件,包括X Server等图形界面程序。我分了20G。   接下来创建/home的挂载分区。考虑到我的工作文档比较多,源代码和程序也经常放到这里,所以给了10G。   其他的诸如tmp,var等来说,单用户工作机是不用考虑的。当然不知道我的机器以后会不会有服务器应用,我还是给var分了2G的空间。   其他空间就全部挂载给/。虽然一般2G就够了,但是多多益善么。   注意:很多时候,如果你使用了ubuntu光盘自带的安装工具分区,会出现很多问题。如果遇到问题过不去,推荐两个办法:   1、在live CD的环境中,在终端下直接用

sudo fdisk /dev/xxx

  来分区,然后w保存后reboot,之后再进安装工具,手工编辑注册表时它认得的就是你编辑的分区表,不用修改直接下一步即可。   2、你也可以同样用livecd的fdisk分好区后,用光盘上的livecd   installer程序,在命令行下安装。不过这个安装程序只需要你挂载/和swap。那么其他分区怎么办呢?可以先在分好,也可以安装完系统再分。如果将其他分区挂载到希望的目录下?举个例子。如果你想把/home/user挂载到新的sda8分区下,可以这样做:   首先,将 /dev/sda8 mount 到 /mnt/sda8中。如果没有这个目录就自己 mkdir。   然后,cp -R /home/user/* /mnt/sda8/user ,和cp -R /home/user/.* /mnt/sda8/user   最后修改/etc/fstab,增加一行/dev/sda8 /home ext3 defaults 0 2(参数自己确定)即可。

 

本文内容由 南瓜大叔 提供

 

Linux:完全抛弃Windows

上个星期四,我成功的将Windows从硬盘上删除,并把Windows的ntfs分区合并到Linux的/root分区。 现在谈谈具体的过程: 一、用acronis的磁盘软件将C:,D:,E:合并成一个分区。 首先把扩展分区D:,E:合并成一个扩展分区D:。然后再把D:合并到主分区C:,这步需要重启,而且对于双系统来说重启时会进入grub>提示符的状态。所以由grub>提示符正确启动Windows这个小技巧就显得格外重要。依次打入如下命令来正常启动Windows: root (hd0,0) chainloader (hd0,0)+1 boot 然后acronis会自动完成剩余的分区合并操作。 注:这步会根据数据的多少而有所不同,我的机器实际操作时,用了43分钟。 二、由CD-Linux或Live-USB、Live-CD启动机器。 启动后,打开刚才合并好的唯一一个Windows分区。复制里面的重要文件来完成对Windows分区的备份。 三、打开Gparted(如果没有就先安装) 删除唯一的一个Windows分区。然后,调整Linux的/root分区使其占用刚才删除的所有Windows分区的空间。点“应用”来完成整个“完全抛弃Windows”计划。顺便提醒一下:Linux的所有分区必须卸载且swap分区关闭才能调整/root分区的大小。 注:这步也会根据数据的多少而有所不同,我的机器实际操作时,用了37分钟。 四、修复grub对Linux的引导(Live-CD或Live-USB环境下进行操作) #mount /dev/sda /mnt/system // 其中:/dev/sda为机器上的硬盘;/mnt/system为挂载点,可以为任意不重要的文件夹。 #mount -t proc none /mnt/system/proc #mount -o bind /dev /mnt/system/dev #chroot /mnt/system /bin/bash #grub grub>root (hd0,x)   //x为Linux所在的分区,如果不知道,可以从0开始试,哪个数没有错误提示就是哪个数。 grub>setup (hd0)  //如果只有一块硬盘就是hd0 grub>quit #vi /boot/grub/menu.lst  //修改menu.lst:改所有原来的路径为(hd0,x) #reboot //重启即可 最后,再鄙视一下Windows: Linux的Gparted只有1.1MB大小就可以独挡Linux分区这一面;而Windows的acronis必须有76MB才能独挡Windows分区这一面。真是差距啊,同是天底下的两个分区软件怎么差距就这么大呢?? [本话题由 breezegrowing 于 2010-03-29 22:25:36 编辑]

 

本文内容由 breezegrowing 提供

 

来源:https://linux.cn/article-5-1.html

Linux:Linux 快速启动技巧十技巧

1.撤消多余的服务   根据机器的用途,很多服务是不需要的。要是Linux只用作桌面,就不需要sendmail、httpd和另外许多服务。如果你的服务器只是Web服务器,也可以关掉许多服务。为此,可转到管理菜单,检查服务项目。只需撤消所有不想启动的服务选项。 2.撤消多余的内核模块   假如你的桌面连接到以太网,就不需要装载无线内核模块。这是较为困难的任务,可能需要重新编译内核,而编译内核不是可以轻松担当的工作。为此,你大概需要内核源代码。接着,按照编译内核的标准步骤进行。不同在于你要搜查系统,撤除所有不需要的模块。   查明系统中当前安装和运行的内核模块的最好方法是安装Bootchart。它不仅会给你一个适宜的模块清单,而且还会说明系统启动过程中发生的事情。还可以发出命令:chkconfig –list |grep 3n,弄清楚正在运行什么服务。一旦知道装载了什么不需要的模块,就可以在内核重新编译期间将其移除。只要这样处理,编译的内核就完全适合你的体系结构。 3.使用轻型窗口管理器代替GNOME或KDE   我插入小脚印窗口管理器的原因是——它们大幅度减少图形(界面)启动时间。代替不得不额外等待启动GNOME或KDE的30到60秒,为什么不等待用于启动Enlightenment或者XFCE的2到10秒呢?它们不仅节省启动时间,还会节省内存并解救处理臃肿软体(bloatware)这种令人头痛的事。 4.使用基于文本的登录而不是图形登录   我的大多数Linux机器启动run level 3而非run level 5.这个运行级别将停在文本登录模式,我就在这个地方登录并发出startx命令,开始选择桌面。图形登录模式做两件事:增加装入时间并引起头痛的问题即试图从拙劣的X windows挣脱出来。 5.使用轻型发行版   不要装载重型的Fedora,为什么不试一下Gentoo、Arch或Puppy Linux呢?这也是让linux快速启动的方法。这些较小的发行版的启动时间比更加臃肿的Fedora(甚至Ubuntu)要快很多。在较大的发行版中,OpenSuSE声称可让linux快速启动,但我还没有亲自试验。在最新的Fedora和Ubuntu之间,Ubuntu击败Fedora的启动时间(而且是即开即用)。 6.使用Open BIOS   要是你相当聪明能干,准备升级PC固件,可以考虑迁移到开源BIOS。一个附加说明,使用开放固件允许Linux启动时真正初始化硬件(而不依赖BIOS)。最重要的是,许多开放BIOS可以设置满足机器的特殊需要。如果不走开放BIOS之路,至少也可以设置BIOS不寻找不存在的软盘驱动器,即直接启动第一个硬盘驱动器(首先不是CD驱动器)。 7.回避DHCP   如果你工作在地址租约不是问题的家庭网络(或者小型企业网络)上,那么,机器就用静态IP地址。这将使机器不必出外访问DHCP服务器来获得IP地址。如果采取这种途径,就要确保配置文件/etc/resolve.conf也表达你的DNS服务器地址。 8.热插拔可免就免   热插拔是指允许把新设备插上电源并立即使用的系统。如果你知道你的服务器不需要这种系统,就删除它。这将减少启动时间。在许多系统上,热插拔消耗大量启动时间。排除热插拔将发生的变化取决于你所用的发行版。注意:就绝大部分而言,udev已经取代热插拔。但如果你还在运行老一点的发行版,这样做还是适合的。 9.要是真的大胆无畏,可尝试一下initng   initng系统充当sysvinit系统的替换物,并承诺彻底减少类UNIX操作系统的启动时间。如果你愿意了解运行中的initng系统,可以试一试Pingwinek LiveCD。 10.利用Debian具有的代码   要是正在使用Debian,就有一行可用来将你的启动脚本转换成并行运行的简单代码。如果检查一下/etc/init.d/rc脚本,就会看到:大约在24行有CONCURRENCY=none。把这一行改为CONCURRENCY=shell,你有可能目睹启动时间的减少。

 

本文内容由 DeadFire 提供

 

Linux:制作简单启动兼容性好的U盘维护工具

这款U盘启动工具盘是本人使用syslinux启动工具,选用其他人出的工具盘映像文件制作而成,已使用三年多了,兼容性非常好,目前还没有遇到不能启动的机器,感兴趣的朋友可以试用一下。   启动信息由syslinux制作,解决了之前使用DOS启动再调动dos4grub和直接使用grub启动方式时,一些机器不能启动的问题。   包括的工具说明:   1、DOS工具使用了深度出的DOS工具、PM8.05 DOS版以及MAXDOS7.1工具盘的img映像文件;   2、WINPE使用的是深度4.0 U盘工具中的映像文件。之前使用的是老毛桃版,因不能识别SATA硬盘,本想自己加入SATA驱动,最近看到深度这个版本已支持intel和sis等多家的SATA驱动,所以就直接使用了。使用时作了以下修改:   a、为了将winpe启动文件都放到一个特定目录下,对原版中的winpe.ini及映像中的pecmd.ini文件作了修改。   b、更改映像文件大小为128M。因为原版深度映像为100M,启动后启用显卡驱动,网络功能后,因映像空间已使用完,无法再加载输入法等其他模块。   3、puppy linux是一款出现最早的live linux, 对linux感兴趣的朋友可以试用一下。使用的是英文版+中文包,支持上网,QQ等,功能非常全。   启动采用两级菜单,第一级菜单是syslinux菜单,此菜单下可以启动所有工具;为了加快映像文件装载的速度,使用了syslinux调用grub启动的方式,增加了第二级grub菜单,内容与第一级菜单完全相同。   为了解决一些U盘启动盘根目录下文件非常多,显得非常杂乱不便管理,本款U盘工具对目录进行了分类,根目录下只有三个目录:boot目录下是启动配置文件和三个DOS工具映像文件;MINIPE目录下是WINPE的启动文件及映像文件;puppy目录下是puppy linux。这三个目录请不要改名,否则无法启动。   制作过程非常简单,不需要安装额外的工具,步骤见下:   1、根据自己需求从附件中下载相应的压缩包。   2、如果U盘已经是FAT32/FAT16可跳过此步,制作过程不会损坏U盘数据。否则先备份U盘数据到硬盘中,然后在我的电脑中窗口中,在U盘上击右键选择“格式化”,文件系统选择FAT32,格式化U盘。   3、将下载的压缩包解压到U盘根目录下,U盘根目录下应该有boot, MINIPE, puppy三个目录(由于这三个目录是隐藏的,需要在文件夹选项中设置显示隐藏文件)   4、打开U盘中的boot目录,双击makeboot.bat文件,开始制作U盘启动信息。制作过程中只需正确输入U盘盘符,不需要输入额外的命令。完成后即可重启机器,选择从U盘启动。   压缩包1共有240M,名称为usb.part01.rar—usb.part13.rar, 包括上述的DOS工具、WINPE、PUPPY LINUX,解压到U盘后共占用248M空间,winpe 110M,puppy linux 120M。   压缩包2共有13M,名称为usb_boot.rar,只有DOS工具。   新下载的朋友从两个压缩包中选择下载其中一个即可。   压缩包3,makeboot.rar是U盘启动制作批处理,上面两个压缩包已经有这个文件。之前从纳米盘下载的朋友由于没有这个文件,可以单独下载,将解压后的makeboot.bat文件放在U盘boot目录下即可。   如果你对syslinux和grub启动菜单文件比较熟悉,你可以修改syslinux和grub启动菜单文件,使用自己喜欢的工具映像,DIY自己的启动盘。

 

本文内容由 cfan85 提供

 

Linux:LAMP 系统性能调优之内核调优措施

 

LAMP

LAMP的一些快速的内核调优措施 大多数 Linux 发布版都定义了适当的缓冲区和其他 Transmission Control  Protocol(TCP)参数。可以修改这些参数来分配更多的内存,从而改进网络性能。设置内核参数的方法是通过 proc 接口,也就是通过读写  /proc 中的值。幸运的是,sysctl 可以读取 /etc/sysctl.conf 中的值并根据需要填充  /proc,这样就能够更轻松地管理这些参数。清单 2 展示在互联网服务器上应用于 Internet 服务器的一些比较激进的网络设置。 清单 2. 包含较为激进的网络设置的 /etc/sysctl.conf

  • # Use TCP syncookies when needed  
  • net.ipv4.tcp_syncookies = 1  
  • # Enable TCP window scaling  
  • net.ipv4.tcp_window_scaling: = 1  
  • # Increase TCP max buffer size  
  • net.core.rmem_max = 16777216  
  • net.core.wmem_max = 16777216  
  • # Increase Linux autotuning TCP buffer limits  
  • net.ipv4.tcp_rmem = 4096 87380 16777216  
  • net.ipv4.tcp_wmem = 4096 65536 16777216  
  • # Increase number of ports available  
  • net.ipv4.ip_local_port_range = 1024 65000  

将这些设置添加到 /etc/sysctl.conf 的现有内容中。第一个设置启用 TCP SYN cookie。当从客户机发来新的 TCP  连接时,数据包设置了 SYN 位,服务器就为这个半开的连接创建一个条目,并用一个 SYN-ACK  数据包进行响应。在正常操作中,远程客户机用一个 ACK 数据包进行响应,这会使半开的连接转换为全开的。有一种称为 SYN 泛滥(SYN  flood) 的网络攻击,它使 ACK 数据包无法返回,导致服务器用光内存空间,无法处理到来的连接。SYN cookie  特性可以识别出这种情况,并使用一种优雅的方法保留队列中的空间(细节参见 参考资料  一节)。大多数系统都默认启用这个特性,但是确保配置这个特性更可靠。 启用 TCP 窗口伸缩使客户机能够以更高的速度下载数据。TCP 允许在未从远程端收到确认的情况下发送多个数据包,默认设置是最多 64 KB,在与延迟比较大的远程客户机进行通信时这个设置可能不够。窗口伸缩会在头中启用更多的位,从而增加窗口大小。 后面四个配置项增加 TCP 发送和接收缓冲区。这使应用程序可以更快地丢掉它的数据,从而为另一个请求服务。还可以强化远程客户机在服务器繁忙时发送数据的能力。 最后一个配置项增加可用的本地端口数量,这样就增加了可以同时服务的最大连接数量。 在下一次引导系统时,或者下一次运行 sysctl -p /etc/sysctl.conf 时,这些设置就会生效。 通过文章的描述和代码的分析,我们可以通过内核调优措施来对LAMP进行调优!

 

本文内容由 evremonder 提供

 

Linux:Ubuntu 下的 5 款图像查看软件

  查看图片已经成为我们计算机日常使用中不可缺少的一项事情。那么在 Ubuntu 下有什么好的看图软件呢?下面给大家介绍五个被大家普遍接受的看图软件: 一、Gwenview   是较好的一项应用,支持几乎所有图片格式,可进行基本的编辑、标签、缩略图、全屏、幻灯显示功能等等。官方网站:http://gwenview.sourceforge.net/   安装命令:

  1. sudo apt-get install gwenview

复制代码

 

Gwenview

二、Eye of GNOME   是GNOME环境下较好的图片查看器,支持JPG, PNG, BMP, GIF, SVG, TGA, TIFF or XPM等图片格式,也可放大、幻灯显示图片、全屏、缩略图等功能。官方网站:http://projects.gnome.org/eog/   安装命令:

  1. sudo apt-get install eog

复制代码

 

Eye of GNOME

三、gThumb   是另一GTK图片查看器,可导入Picasa或Flickr图片,也可导出到 Facebook, Flickr, Photobucker, Picasa 和本地文件夹。官方网站:http://live.gnome.org/gthumb   安装命令:

  1. sudo apt-get install gthumb

复制代码

 

gThumb

四、Viewnior   是小型化的图片查看器,支持JPG和PNG格式。官方网站:http://xsisqox.github.com/Viewnior/index.html   安装命令:

  1. sudo apt-get install viewnior

复制代码

 

Viewnior

五、gPicView   是LXDE下的默认图片查看器,操作按钮位于窗口底部。只需右击图片,实现所有相关功能。支持JPG, TIFF, BMP, PNG , ICO格式。官方网站:http://lxde.sourceforge.net/gpicview/   安装命令:

  1. sudo apt-get install gpicview

复制代码

5.jpg

本文内容由 DeadFire 提供

 

Linux:CairoPlot 让 Linux 服务器的日志文件更直观

  确实有些Linux服务器管理员很享受阅读及核对日志文件的艰辛过程,但为什么不创建一个美观的列表及图形体系来突出那些故障和问题,而非要受这份罪呢?试试这款优秀的工具——CairoPlot吧,它会提供给你美观且信息可视化的服务器日志文件分析途径。   作为一个需要整天跟数据打交道的从业者,我一直致力于寻找更好的方法来将纷繁复杂的数据显示为列表和图形,尤其是利用Python来实现这一目标。时下存在很多利用Python制作的整合软件包可供使用,但如果你希望输出的结果不会因为粗糙的视觉效果而遭到那些苹果使用者们的耻笑,那么我向你强力推荐CairoPlot。   CairoPlot并未像大多数发行版软件那样进行封包,但它的安装过程依然简便易行。目前在CairoPlot Launchpad page(CairoPlot官方主页)上提供的最新版本是1.1版。你可以在那里下载到cairoplot-1.1.tar.gz这个文件,或是根据你自己的喜好,从BZR上搜索(一旦1.2版本发布,CairoPlot项目可能会整体转移到Sourceforge.net上)。   解压压缩包:

  1. $ tar xvf cairoplot-1.1.tar.gz

复制代码

  然后复制下面这个文件:cairoplot-1.1/CairoPlot.py,并粘贴到你要开发的Python脚本所在的目录下。   用扇形图说明:谁在发送垃圾邮件?   展开测绘工作之前,找到一个良好的数据源永远是我们的首要任务。针对这个项目,让我们先来分析一个Postfix日志文件,/var/log/mail.info,借以观察一系列垃圾邮件的众多来源。   通过对文件的随机检查,我们会发现有许多提出接收请求的邮件都来自一个客观上根本不存在的地址,举例说明:   Mar 5 15:05:45 mailserver postfix/smtpd[29764]: NOQUEUE: reject: RCPT from 212.199.94.45.static。012.net.il[212.199.94.45]: 450 4.7.1 : Helo command rejected: Host not found; from=<> to=<aiglance@mydomain.com> proto=ESMTP helo=   我们的posifix服务器一般会拒绝这样的邮件,因为通常情况下它们都是垃圾邮件。配置正确的邮件服务器应该不会编造这些虚假的地址——当然在有些配置有误的服务器上是会发生这种状况。   但是这些虚假的接收请求从何而来?他们是否来自特定的一些国家?而在这些特定国家的垃圾邮件来源中,存在多少.com类型网站,又有多少.net类型网站?   为了找到答案,我将创建一个Python索引系统,然后使用CairoPlot工具来测绘出一幅扇形图。索引中的每个关键字都将涵盖一个顶级域,例如“.com”;而其数值则为从该类型域中发来的被拒收邮件的数量。   剖析日志文件   要填充索引系统中的词条项目,意味着我们需要对/var/log/mail.info文件进行剖析。每封邮件的真正发出地址能够从RCPT中查询到;将结果应用到Python的re模块中。因为这一过程是针对CairoPlot的,因此我们不必遵循Python的描述方式,只需按照以下代码的形式表达:

  1. #! /usr/bin/env python
  2. import CairoPlot, re
  3. MAIL_INFO = “/var/log/mail.info”
  4. # Dictionary to store the results as (domain : number of rejects)
  5. rejected = {}
  6. # Parse mail.info to find all the ‘NOQUEUE: reject’ lines and
  7. # figure out what top-level domains (TLDs) they’re coming from.
  8. f = open(MAIL_INFO)
  9. for line in f :
  10. if line.find(‘status=sent’) > 0 :
  11. pass
  12. elif line.find(‘NOQUEUE: reject’) > 0 :
  13. # An attempt we rejected. Look for a pattern like
  14. # RCPT from foo.example.com[nnn.nnn.nnn.nnn]
  15. rcpt = re.search(“RCPT from ([^[]*)\[([0-9\.]+)\]”, line)
  16. if not rcpt :
  17. continue
  18. # Now rcpt.group(1) is the reverse-DNS hostname (if any)
  19. # from the log file, rcpt.group(2) is the IP address.
  20. if rcpt.group(1) and rcpt.group(1) != ‘unknown’ :
  21. hostname = rcpt.group(1)
  22. else :
  23. hostname = None
  24. # Find the part after the last “.”
  25. tld = “Unknown” # default there’s no “.” in the hostname
  26. if hostname :
  27. dot = hostname.rfind(“.”)
  28. if dot >= 0 :
  29. tld = hostname[dot+1:]
  30. if tld in rejected :
  31. # We’ve seen this TLD before; add 1.
  32. rejected[tld] += 1
  33. else :
  34. # First time we’ve seen this TLD.
  35. rejected[tld] = 1
  36. f.close()

复制代码

  在结尾部分,通过以下内容将索引系统中的“拒收”标准传达给CairoPlot。

  1. {‘ru’: 3, ‘ch’: 1, ‘ma’: 2, ‘rs’: 2, ‘it’: 4, ‘hu’: 1, ‘cz’: 1, ‘ar’: 2, ‘il’: 35, ‘br’: 16, ‘es’: 1, ‘co’: 2, ‘net’: 4, ‘com’: 24, ‘pl’: 7, ‘at’: 2}

复制代码

创建扇形图   你要如何依据索引系统来创建一个扇形图?事实上一行命令即可实现:

  1. CairoPlot.pie_plot(“piechart”, rejected, 500, 500, None, True, False,
  2. None)

复制代码

  CairoPlot将生成一个名为pie.svg的图形文件(如图一所示)。

1.jpg

  1. pie_plot(name,
  2.          data,
  3.          width, height,
  4.          background=None,
  5.          gradient=False, shadow=False,
  6.          colors=None)

复制代码

  Name(名称)指文件名:如果你希望加入一个诸如.jpg之类的扩展名,那么CairoPlot将使用你所设定的格式来取代svg格式,因为在某些情况下你可能会需要一个IE用户能够通过页面正常浏览的图像。   Data(数据),当然了,代表索引系统中的数值。   Width(宽度)和Height(高度)代表你所希望的图形绘制尺寸。需要注意的是,CairoPlot预留给扇形图周边的空白区域是相当有限的,所以一定要注意整体规划。   Background(背景),你需要指定一种背景颜色,其选色方法为标准的RGB形式。因此,通过background=(0,1,0)这一指令,你将获得一个全绿的背景。你在这里也可以使用Cairo gradient(色阶)来进行设定.gradient(色阶)功能可以让你选择是否将你扇形图中的某一块显示出色彩渐变的效果,以使整个图形更加美观.shadow(阴影)功能将让你可以为整个扇形图增加底部阴影效果,并且如果你不喜欢系统默认的阴影颜色,也可以随意为其定义新的颜色。当然,阴影颜色同样即可以是单色也可以包含色阶。需要强调的是,所选颜色的数量必须与索引系统中的项目数量相同。   图一中的示例存在一个小问题:它显示绝大多数无效的接收请求来自根本无法解析的服务器地址,而表示状况的图形被压成极细小的一块,根本无法解读。而且显然你从那一大块“无法解析“的服务器来源中根本折腾不出什么有用的信息。在这种情况下,你可以在指令中if hostname:后面添加如下内容

  1. if hostname :
  2. dot = hostname.rfind(“.”)
  3. if dot >= 0 :
  4. ext = hostname[dot+1:]
  5. else :
  6. continue

复制代码

  运行上述命令,这时扇形图变为如图二所示。很有意思吧。直到编写这个实例,我才意识到相比起其它国家,我从以色列和巴西收到了这么多的垃圾邮件。有时候一幅清晰的示意图绝对胜过千言万语。

2.jpg

条形图   CairoPlot也可以制作出很棒的条形图。但遗憾的是,CairoPlot的各种规则不太适合条形图数据的导入。条形图需要的是列表,而非索引。   这都不叫事儿!只要把上文中的索引系统转换为两个列表——一个包含标签信息,一个包含具体数据——再进行条形图绘制(如图三所示):

  1. h_labels = [ k for k in rejected.keys() ]
  2. rejlist = [ rejected[k] for k in rejected.keys() ]
  3. CairoPlot.bar_plot (‘bars’, rejlist, 500, 400,
  4. border=5, three_dimension=True,
  5. h_labels=h_labels)

复制代码

 

3.jpg

  同制作扇形图一样,你可以导入一个颜色列表来使用自定义颜色,而且还有其它一些诸如背景、风格、圆滑边角、沙盘模型高度、象限体积以及必然具备的标签体积和标签高度等调节选项。   当然,CairoPlot同样可以制作其它类型的图形。这有一些实例文档,你也可以使用Python的交互式解析工具并输入如下内容:

  1. import CairoPlot
  2. help(CairoPlot.pie_plot)

复制代码

  CairoPlot站点将很可能迁移至Sourceforge网站,并提供更加完备的访问页面。与此同时,如果你已经有过一些实践经验,你一定会深切体会到CairoPlot在制作美观艳丽的图形方面绝对称得上是顶尖工具之一。 原文地址:http://www.linuxplanet.com/linuxplanet/tutorials/7317/1/ 译文来自:http://os.51cto.com/art/201103/250253.htm 译者:核子可乐

 

本文内容由 砖瓦匠 提供