Skip to content Skip to main navigation Skip to footer

Linux

Linux:早该知道的7个JavaScript技巧

我写JavaScript代码已经很久了,都记不起是什么年代开始的了。对于JavaScript这种语言近几年所取得的成就,我感到非常的兴奋;我很幸运也是这些成就的获益者。我写了不少的文章,章节,还有一本专门讨论它的书,然而,我现在依然能发现一些关于这种语言的新知识。下面的描述的就是过去让我不由得发出“啊!”的感叹的编程技巧,这些技巧你应该现在就试试,而不是等着未来的某个时候偶然的发现它们。

简洁写法

JavaScript里我最喜欢的一种东西就是生成对象和数组的简写方法。在过去,如果你想创建一个对象,你需要这样:

var car = new Object();
car.colour = 'red';
car.wheels = 4;
car.hubcaps = 'spinning';
car.age = 4;

下面的写法能够达到同样的效果:

var car = {
    colour:'red',
    wheels:4,
    hubcaps:'spinning',
    age:4
}

简单多了,你不需要反复使用这个对象的名称。这样 car 就定义好了,也许你会遇到 invalidUserInSession 的问题,这只有你在使用IE时会碰到,只要记住一点,不要右大括号前面写逗号,你就不会有麻烦。

另外一个十分方便的简写是针对数组的。传统的定义数组的方法是这样:

var moviesThatNeedBetterWriters = new Array(
    'Transformers','Transformers2','Avatar','IndianaJones 4'
);

简写版的是这样:

var moviesThatNeedBetterWriters = [
    'Transformers','Transformers2','Avatar','IndianaJones 4'
];

对于数组,这里有个问题,其实没有什么图组功能。但你会经常发现有人这样定义上面的 car ,就像这样

var car = new Array();
car['colour'] = 'red';
car['wheels'] = 4;
car['hubcaps'] = 'spinning';
car['age'] = 4;

数组不是万能的;这样写不对,会让人困惑。图组实际上是对象的功能,人们混淆了这两个概念。(转载注,这里所称的图组通常称为关联数组、散列、hash,而且这种写法其实是合法的)

另外一个非常酷的简写方法是使用与三元条件符号。你不必写成下面的样子…

var direction;
if(x < 200){
    direction = 1;
} else {
    direction = -1;
}

…你可以使用三元条件符号简化它:

var direction = x < 200 ? 1 : -1;

当条件为true 时取问号前面的值,否则取冒号后面的值。

用 JSON 形式存储数据

在我发现JSON之前,我使用各种疯狂的方法把数据存贮在JavaScript固有的数据类型里面,例如:数组,字符串,中间夹杂着容易进行拆分的标志符号以及其它的令人讨厌的东西。Douglas Crockford 发明了JSON 之后,一切全变了。使用JSON,你可以使用JavaScript自有功能把数据存贮成复杂的格式,而且不需要再做其它的额外转换,直接可以访问使用。JSON 是 “JavaScript Object Notation” 的缩写,它用到了上面提到的两种简写方法。于是,如果你想描述一个乐队,你可能会像这样写:

var band = {
    "name":"The Red Hot Chili Peppers",
    "members":[
        {
        "name":"Anthony Kiedis",
        "role":"lead vocals"
        },
        {
        "name":"Michael 'Flea' Balzary",
        "role":"bass guitar, trumpet, backing vocals"
        },
        {
        "name":"Chad Smith",
        "role":"drums,percussion"
        },
        {
        "name":"John Frusciante",
        "role":"Lead Guitar"
        }
    ],
"year":"2009"
}

你可以在JavaScript里直接使用JSON,可以把它封装在函数里,甚至作为一个API的返回值形式。我们把这称作 JSON-P ,很多的API都使用这种形式。你可以调用一个数据提供源,在script代码里直接返回 JSON-P 数据:

这是调用 Delicious 网站提供的 Web service 功能,获得JSON格式的最近的无序书签列表。

基本上,JSON是最轻便的描述复杂数据结构的方法,而且它能在浏览器里运行。你甚至可以在PHP里用 json_decode() 函数来运行它。JavaScript的自带函数(Math, Array 和 String)让我感到惊奇的一个事情是,当我研究了JavaScript里的math和String函数后,发现它们能极大的简化我的编程劳动。使用它们,你可以省去复杂的循环处理和条件判断。例如,当我需要实现一个功能,找出数字数组里最大的一个数时,我过去是这样写出这个循环的,就像下面:

var numbers = [3,342,23,22,124];
var max = 0;
for(var i=0;i max){
        max = numbers[i];
    }
}
alert(max);

我们不用循环也能实现:

var numbers = [3,342,23,22,124];
numbers.sort(function(a,b){return b - a});
alert(numbers[0]);

需要注意的是,你不能对一个数字字符数组进行 sort() ,因为这种情况下它只会按照字母顺序进行排序。如果你想知道更多的用法,可以阅读 这篇不错的关于 sort() 的文章。

再有一个有意思的函数就是 Math.max()。这个函数返回参数里的数字里最大的一个数字:

Math.max(12,123,3,2,433,4); // returns 433

因为这个函数能够校验数字,并返回其中最大的一个,所以你可以用它来测试浏览器对某个特性的支持情况:

var scrollTop=Math.max(
    doc.documentElement.scrollTop,
    doc.body.scrollTop
);

这个是用来解决IE问题的。你可以获得当前页面的 scrollTop 值,但是根据页面上 DOCTYPE的不同,上面这两个属性中只有一个会存放这个值,而另外一个属性会是 undefined,所以你可以通过使用 Math.max() 得到这个数。阅读这篇文章你会得到更多的关于使用数学函数来简化JavaScript的知识。

另外有一对非常有用的操作字符串的函数是 split() 和 join()。我想最有代表性的例子应该是,写一个功能,用来给页面元素附加CSS样式。

是这样的,当你给页面元素附加一个CSS class时,要么它是这个元素的第一个CSS class,或者是它已经有了一些class, 需要在已有的class后加上一个空格,然后追加上这个class。而当你要去掉这个class时,你也需要去掉这个class前面的空格(这个在过去非常重要,因为有些老的浏览器不认识后面跟着空格的class)。

于是,原始的写法会是这样:

function addclass(elm,newclass){
    var c = elm.className;
    elm.className = (c === '') ? newclass : c+' '+newclass;
}

你可以使用 split() 和 join() 函数自动完成这个任务:

function addclass(elm,newclass){
    var classes = elm.className.split(' ');
    classes.push(newclass);
    elm.className = classes.join(' ');
}

这会确保所有的class都被空格分隔,而且你要追加的class正好放在最后。

Linux:Cookies 的跨域脚本攻击 – Github 迁移域名的安全详解

上周五我们宣布并完成了把所有的GitHub页面迁移到新域名github.io。 这是个计划已久的行动,此举是为了防止恶意网站攻击和跨域cookie的漏洞,这些漏洞是通过在我们主站的子域名下控制客户内容产生的。

关于这些跨域攻击漏洞的可怕影响,大家可能会有一些困惑。我们希望这篇技术博客可以消除这些困惑。

一个二级域名传过来的Cookie

当你登陆GitHub.com时,我们通过响应的HTTP头部来设置session的cookie。这个cookie包含着唯一标识你的session数据:

Set-Cookie: _session=THIS_IS_A_SESSION_TOKEN; path=/; expires=Sun, 01-Jan-2023 00:00:00 GMT; secure; HttpOnly

这些GitHub发送给浏览器的session的cookie是设定在默认的域名上(github.com),这就意味着这些cookie是不能从二级域名*.github.com访问到的。而且我们也指定了HttpOnly属性,这意味着cookie也不能通过JavaScript 的API:document.cookie来读取。最后,我们指定了Secure属性,这意味着这些cookie只能通过HTTPS来传输。

因此,从GitHub托管网站读取或”窃取”session的cookie是不太可能的。通过在GitHub网站托管的用户代码是不容易获取到session的cookie,但由于浏览器通过HTTP请求来发送cookie,这种方式有可能把cookie从GitHub网站抛到GitHub父域名上。

当浏览器执行一个HTTP请求时,它通过header里单独的cookie发送一些和URL匹配的cookie,这些发送的cookie是以键-值对存在的。只有和请求的URL匹配的cookie才会发送出去,比如,当执行一个对github.com的请求时,设置在域名github.io上的cookie是不会发送的,但在github.com上的cookie将会发送。

GET / HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=THIS_IS_A_SESSION_TOKEN;

Cookie抛出的问题是因为header中的cookie只包含了一系列键值对的cookie,并没有一些其他信息, 通过这些额外信息可以知道cookie设置在哪个域名上,比如路径或者域名。

最直接的跨域攻击涉及到:在GitHub托管网站页面,通过document.cookie这个JavaScript API设置一个_session的cookie。假设这个网站托管在*.github.com,那么这个cookie将会被设置到父域名的所有请求里,尽管事实是它只设置在了二级域名里。

/* set a cookie in the .github.com subdomain */
document.cookie = "_session=EVIL_SESSION_TOKEN; Path=/; Domain=.github.com"

 

GET / HTTP/1.1
Cookie: logged_in=yes; _session=EVIL_SESSION_TOKEN; _session=THIS_IS_A_SESSION_TOKEN;
Host: github.com

在这个示例中,通过JavaScript在二级域名上设置的cookie被发送旁边合法的cookie字段中,并设置到父域名里。如果域名,路径,Secure和HttpOnly属性未设置的话,根本 没有方法去判断哪个cookie来自哪里。

这对大部分web服务器来说是一个大问题,因为在一个域及其子域中的cookies的顺序并不是有RFC6265指定的,并且web浏览器可以选择以任何顺序发送它们。

对于Rack–为Rails和Sinatra提供动力的web服务器界面,包括其他的,cookis解析如下:

def cookies
  hash = {}
  cookies = Utils.parse_query(cookie_header, ';,')
  cookies.each { |k,v| hash[k] = Array === v ? v.first : v }
  hash
end

如果在Cookie:header里有不止一个有着相同名字的cookie时,第一个cookie将会被假定成任意值。

这是一个很显而易见的攻击:几周之前,安全专家Egor Homakov在博客中就用这个方法证明了该攻击确实存在.这个漏洞的影响是不严重的(每次登录后,跨站点伪造请求的令牌会被重置,所以它们不会一直固定不变),但这是个非常实际的例子,人们可以很容易伪造注销用户,令人很郁闷.这使得我们必须尽快完成把GitHub页面迁移的他们自己的域名,但只留给我们几周的时间(到迁移完成之前),在这期间我们必须减轻已知的攻击数量. 幸运的是,已知的攻击在服务端很容易减轻.我们预想到会有一些其他的攻击,这些攻击或者很难处理,或者根本不可能存在.那么让我们一起看看这些它们. 

免受cookie抛出的伤害

第一步是减轻cookie抛出造成的攻击.这个攻击暴露出浏览器将会发送2个相同名字的cookie令牌,不让我们知道它们是设置在哪个域名上的.

我们没法判断每个cookie是来自哪里的,但如果我们跳过cookie的解析,我们就能看出每个请求是否包含2个相同的_session的cookie.这个极有可能是由于有些人从二级尝试域名抛出这些cookie,所以我们不是猜测哪个cookie是合法的,哪个是被抛过来的,而是简单地通知浏览器在继续执行之前放弃二级域名上设置的cookie.

为了完成这个示例,我们创造了一个特殊的响应:我们让浏览器跳转到刚刚请求的URL,但带着一个Set-Cookie的header,这个header放弃了二级域名上的cookie. 

GET /libgit2/libgit2 HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=EVIL_SESSION_TOKEN; _session=THIS_IS_A_SESSION_TOKEN;

 

HTTP/1.1 302 Found
Location: /libgit2/libgit2
Content-Type: text/html
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;

我们决定按照Rack中间件来实现这个功能.这种方式在 应用运行之前可以执行检查cookie和顺序重定向的工作. 

当触发Rack的中间件时,在用户不会意识到的情况下,这个重定向会自动发生,并且第二个请求将只会包含一个_session的cookie:合法的那一个.

这个”破解”足够减缓大部分人所遇到的直接抛出cookie的攻击,但还有一些更复杂的攻击也需要我们思考一下.

Cookie路径方案

如果一个恶意的cookie设置到一个具体的路径,这个路径不是根路径(例如,/notifications),当用户访问github.com/notifications时,浏览器会发送那个cookie,当我们在根路径上清除这个cookie时,我们的header不会起作用.

document.cookie = "_session=EVIL_SESSION_TOKEN; Path=/notifications; Domain=.github.com"

 

GET /notifications HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=EVIL_SESSION_TOKEN; _session=THIS_IS_A_SESSION_TOKEN;

 

HTTP/1.1 302 Found
Location: /notifications
Content-Type: text/html
# This header has no effect; the _session cookie was set
# with `Path=/notifications` and won't be cleared by this,
# causing an infinite redirect loop
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;

这个方案非常直截了当,虽然不太雅:对于任何指定的请求URL,如果其路径部分匹配请求的URL,浏览器将只会发送一个恶意的JavaScript cookie.所以我们只需要在每个路径的元素上放弃这个cookie就可以了.  

HTTP/1.1 302 Found
Location: /libgit2/libgit2/pull/1457
Content-Type: text/html
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2/libgit2; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2/libgit2/pull; Domain=.github.com;
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/libgit2/libgit2/pull/1457; Domain=.github.com;

当谈到cookie时,我们需要在服务端做关联.我们唯一目的是用这个强力方式清楚那些cookie,这种方式虽然暴力,但完成github.io的迁移后,效果非常好. 

Cookie溢出

让我们加强我们的游戏:另一种攻击将会执行,它利用RFC 6265没有明确指明一种cookie的溢出行为.大部分web服务器/接口,包括Rack,假定cookie的名字可以加密(如果他们包含不是ASCII的字符时,这就是个疯狂的假设),所以当生成cookie列表时不会溢出:

cookies = Utils.parse_query(string, ';,') { |s| Rack::Utils.unescape(s) rescue s }

这就允许一个恶意用户去设置一个cookie,这个cookie能被web框架理解成_session,尽管在浏览器里这个cookie的名字并不是_session.这个攻击会把没必要溢出的cookie字符溢出掉:

GET / HTTP/1.1
Host: github.com
Cookie: logged_in=yes; _session=chocolate-cookie; _%73ession=bad-cookie; 

 

{
  "_session" : ["chocolate-cookie", "bad-cookie"]
}

如果我们试着丢弃Rack产生的cookie列表中的第二个,我们的header就会失效.在Rack解析以后,我们会失去重要的信息:通过加密后的cookie名字和web框架接收到的名字将不一致.

# This header has no effect: the cookie in
# the browser is actually named `_%73ession`
Set-Cookie: _session=; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.github.com;

为了解决这个问题,我们必须跳过Rack的cookie解析,可以通过禁用不溢出,然后找到所有和我们目标匹配的那些cookie名字.

cookie_pairs = Rack::Utils.parse_query(cookies, ';,') { |s| s }
cookie_pairs.each do |k, v|
  if k == '_session' && Array === v
    bad_cookies << k
  elsif k != '_session' && Rack::Utils.unescape(k) == '_session'
    bad_cookies << k
  end
end

这种方式我们可以丢弃对的cookie(它或者设置成_session,或者作为溢出的偏差).在这种中间件的帮助下,我们可以解决所有的能在服务端解决的cookie抛出引起的攻击.不幸的是,我们意识到有另一种攻击会使得中间件的保护失效.

Cookie溢出

如果你遇到了cookie的问题,我为你惋惜. 我已经有了99个cookie,我的域名不能再增加一个了.

这是一个稍微更高级的攻击,它暴露出所有web浏览器对每个域名设置的cookie的数量限制.

比如,火狐设置的数量限制是150,谷歌浏览器设置的是180.问题是这个限制不是在每个cookie的域名属性上设置的,而是通过cookie设在的实际域名来定义的.一个单独的HTTP请求访问主域名和子域名上的任一页面,将会发送最大数量的cookie,但哪些cookie被使用的规则确实没有定义的.

例如谷歌浏览器不会关心父域名上的那些cookie,这些cookie是通过HTTP设置或者用Secure设置的:它将会发送180个新的cookie.这使得非常容易"剔除"每一个单独的从父域名过来的cookie,并用一些子域名上用JavaScript运行的假的cookie来替代它们:

for (i = 0; i < 180; i++) {
    document.cookie = "cookie" + i + "=chocolate-chips; Path=/; Domain=.github.com"
}

在子域名上设置了180个这样的cookie之后,所有从父域名过来的cookie就消失了.如果现在我们终止我们刚刚设置的cookie,也包含JavaScript那部分,那么子域名和父域名上的cookie列表就会变空:

for (i = 0; i < 180; i++) {
    document.cookie = "cookie" + i + "=chocolate-chips; Path=/; Domain=.github.com; Expires=Thu, 01-Jan-1970 00:00:01 GMT;"
}
/* all cookies are gone now; plant the evil one */
document.cookie = "_session=EVIL_SESSION_TOKEN; Path=/; Domain=.github.com"

这允许我们执行一个只带有一个_session的cookie的单独的请求:这个cookie是我们用JavaScript创造的.原来的Secure和HttpOnly在_session的cookie里没有了,并且没有方法在web服务端检测发送的cookie既不是Secure,HttpOnly,也不是在父域名中设置的,但是完全虚构的.

在服务端只设置一个_session的cookie,就没有方法知道cookie是否被抛出了.即使我们发现了一个不合法的cookie,这样的攻击也仅能把用户从GitHub注销.

结论

正如我们看到的,通过在浏览器溢出cookie,我们可以制造带有恶意cookie的请求,这些请求不能在服务端阻隔.这里没有什么新的知识:Egnor的原始概念攻击的证据和暴露在这里的变种攻击都早已被世人所知.

现在看起来,在子域名上控制用户自定义的内容是一种安全的自杀行为,尤其在谷歌浏览器当前实现方案下,更加剧了这种自杀行为.火狐处理父域和子域上cookie区别的方式更优雅(用更一致的排序来发送它们,并且分离它们的存储来防止子域的溢出),谷歌浏览器就没有这种区别,并且对通过JavaScript设置的cookie和服务器通过Secure,HttpOnly设置的cookie一视同仁,导致一个非常完美的抛出攻击.

不管如何,通过HTTP header来传输cookie的行为是模糊的和依赖于实现的,迟早会有人提出另一种跨域抛出cookie的方式,和目标浏览器无关.

当cookie抛出的攻击并不是太危险的(比如,拦截用户session,或者实行网络欺诈/骚扰用户是不太可能的),它们会直截了当的进行,这非常使人恼火.

我们希望这篇文章能帮助大家提高这些攻击问题的防范意识和不通过迁移域名来防止这些攻击的困难点,所以迁移域名是一个激进的但最终必须的措施.

via https://github.com/blog/1466-yummy-cookies-across-domains 

via http://www.oschina.net/translate/yummy-cookies-across-domains 

 

Linux:运维经验分享:关于系统运维监控的几点建议

目前很多企业信息化系统都有自己的监控平台和监控手段,无论是采用哪种手段去实现对系统的实时监控和故障告警,大多采用的方式也只有两种:集中式监控和分布式监控。本文作者根据自身公司监控存在的问题,总结了一些经验并提出一些在监控平台的建议,以供大家参考学习,如有考虑不周的地方还希望大家多多批评指正。

为了更好、更有效的保障系统上线后的稳定的运行。对于服务器的硬件资源、性能、带宽、端口、进程、服务等都必须有一个可靠和可持续的监测机制,统计分析每天的各种数据,从而能及时反映出服务器哪里存在性能瓶颈、安全隐患等。另外是要有危机意识,就是了解服务器有可能出现哪些严重的问题,出现这些问题后该如何去迅速处理。比如数据库的数据丢失,日志容量过大,被黑客入侵等等。

一、上线之前的准备工作

1、首先是备份,做好定时备份策略,备份所有你认为重要的数据,并且定期检查你的备份是否有效、全面;

2、日志轮换,无论你想用哪种轮换方式,控制日志增长避免驱动器已满是你的目的;

3、做一定的安全措施,如防火墙iptables的访问控制,用denyhosts防止黑客远程暴力破解;

4、mysql远程登录权限等等;

5、最后就是服务器、网元设备的监控。

二、监控策略

1、定义告警优先级策略

一般的监控到的结果是成功或者失败,如Ping不通、访问网页出错、连接不到Socket,发生时这些称之为故障,故障是最优先的告警。除此之外,还能监控到返回的延时、内容等,如Ping返回的延时、访问网页的时间、访问网页取到的内容等。利用返回的结果可以自定义告警条件,如Ping监控的返回延时一般是10-30ms之间,当延时大于100ms时候,表示网络或者服务器可能出现问题,引起网络响应慢,需要立即检查是否流量过大或者服务器CPU太高等问题。

2、定义告警信息内容标准

当服务器或应用发生故障时告警信息内容非常多,如告警运行业务名称、服务器IP、监控的线路、监控的服务错误级别、出错信息、发生时间等。预先定义告警内容及标准使收到的告警内容具有规范性及可读性。这点对于用短信接受告警内容特别有意义,短信内容最多是70个字符,要在70个字符完全知道故障内容比较困难,更需要预先定义内容规范。如:“视频直播服务器10.0.211.65 在2012-10-18 13:00电信线路监控第到1次失败”,清晰明了的知道故障信息。

3、通过邮件接收汇总报表

每天收到一封网站服务器监控的汇总报表邮件,花个两三分钟就大致了解网站和服务器状态。

4、 集中监控和分布式监控相结合

  • 主动(集中)监控虽然能不需要安装代码和程序,非常安全和方便,但缺少很多细致的监控内容,如无法获取硬盘大小、CPU的使用率、网络的流量等,这些监控内容非常有用,如CPU太高表示有网站或者程序出问题,流量太高表示可能被攻击等。
  • 被动(分布式)监控常用的是SNMP(简单网络管理协议),通过SNMP能监控到大部分你感兴趣的内容。大部分操作系统支持SNMP,开通管理非常方便,也非常安全。SNMP缺点是比较占用带宽,会消耗一定的CPU和内存,在CPU太高和网络流量大情况下,无法有效进行监控。

5、定义故障告警主次

对于监控同一台服务器的服务,需要定义一个主要监控对象,当主要监控对象出现故障,只发送主要监控对象的告警,其它次要的监控对象暂停监控和告警。例如用Ping来做主要监控对象,如果Ping不通出现Timeout,表示服务器已经当机或者断网,这时只发送服务器Ping告警持续监控Ping,因为再继续监控和告警其它服务已经没有必要。这样能大大减少告警消息数量,又让监控更加合理、更加有效率。

本地监控脚本的规范化部署

6、对在本地部署的监控脚本要进行统一规范的部署并记录到KM系统。

7、实现对常见性故障业务自我修复功能

实现对常见性故障业务自我修复功能脚本进行统一部署并对修复后故障进行检查告警检查频次不多于3次。

8、对监控的业务系统进行分级

一级系统实现7*24小时告警,二级系统实现7*12小时告警,三级系统实现5*8小时告警。

9、 监控范围及目标

实现对负载均衡设备、网络设备、服务器、存储设备、安全设备、数据库、中间件及应用软件等IT资源的全面监控管理;同时自动收集、过滤、关联和分析各种管理功能产生的故障事件,实现对故障的提前预警和快速定位;对网络和业务应用等IT资源的性能进行监控,定期提供性能报表和趋势报表,为性能优化及未来系统扩容提供科学依据。

通常情况下,我们可以将监控对象这么来分:

1.服务器监控,主要监控服务器如:CPU 负载、内存使用率、磁盘使用率、登陆用户数、进程状态、网卡状态等。

2.应用程序监控,主要监控该应用程序的服务状态,吞吐量和响应时间,因为不同应用需要监控的对象不同,这里不一一列举。

3.数据库监控,只所以把数据库监控单独列出来,足以说明它的重要性,一般监控数据库状态,数据库表或者表空间的使用情况,是否有死锁,错误日志,性能信息等等。

4.网络监控,主要监控当前的网络状况,网络流量等。

以上四条应该算是最基本的,也是保证网站正常运行必须要知道的几点内容,这样才能实现我们常说的“运筹帷幄之中,决胜千里之外”。

VIA http://blog.chinaunix.net/uid-25723371-id-3410014.html

Linux:解决MySQL中文乱码以及版本不一致问题

这几天基于Heritrix写了一个爬虫,用到MySQL,在导入导出数据时,遇到一些乱码问题,好不容易解决了,记录一下,以备查看。

 一、导出数据

先说明一下自己的环境:Mac OS X 10.8.3, MySQL Community Server 5.6.10, MySQL Workbench 5.2.47。

我想把本机数据库内的数据迁移到另一台机器上,于是使用Workbench中自带的import/export功能,其实就是调用mysqldump。不幸的是,出现了版本不一致的错误。

 

错误没治了,最终找到解决方案,可以指定mysql的mysqldump,路径为:/usr/local/mysql/bin/mysqldump,这样是把数据导出为sql语句的insert语句。

由于需要是把数据导出为excel,所以通过mysql控制台使用select语句把数据导出到excel文件中。

下面先介绍怎么导出为excel文件,然后介绍怎么导出为insert语句。

1、通过终端操作。

cd /usr/local/mysql/bin/

2、到达bin目录后,可以ls -l命令看看当前目录有哪些程序可以用,这里先用mysql,命令格式为:

mysql -h主机IP -u用户名 -p密码

如:

./mysql -hlocalhost -uroot -p123456

注意前面加的”./”。

这时就进入mysql命令控制台,终端上显示为:

3、然后通过show databases命令查看当前的所有数据库,使用use命令选择进入某个数据库,注意每个命令都要以英文分号“;”结束。

4、使用sql语句导出需要的数据,sql语句不限于单个表的查询。由于我的数据库编码是utf8格式,而office默认的编码则是gb2312,所以当某个字段中包含中文时,导出到excel后,中文内容是会乱码的,此时需要convert转换编码,具体使用方式:

我试着把文件保存到桌面,但始终提示没有权限,应该是和用户有关吧,无视了。当使用“./”这个路径保存时,实际是保存到了/usr/local/mysql/data下面。打开看看,哟西,不乱码了。

5、下面是把数据导出为sql的insert语句。

使用mysqldump命令,可以指定是单个表还是整个数据库导出。

打开终端,定位到/usr/local/mysql/bin,使用这个目录下的mysqldump。

导出单个表:

命令格式为:

mysqldump -u用户名 -p密码 -h主机地址 数据库名 表名 > 导出文件存储路径

例如:

/usr/local/mysql/bin/mysqldump -uroot -p123456 -hlocalhost -t --extended-insert=false --default-character-set=utf8 SpiderBBSDB Catalog > /Users/ethan/Desktop/Catalog.sql

其中用到了几个参数,简单说明一下:

-t:等同于–no-create-info,只导出数据,而不添加CREATE TABLE 语句。默认导出的文件中也有create table语句。

–extended-insert:使用具有多个VALUES列的INSERT语法,也就是传说中一次插入多条数据的INSERT句式。这样使导出文件更小,并加速导入时的速度,但是有可能sql语句会有长度限制,所以我并不推荐此种方式,比如我某个表中有500W条数据,难保能用一条insert语句可以执行完毕。此选项默认为打开状态,把他置为false,就是一条数据一个insert语句了。

–default-character-set:设置默认字符集,由于我的数据库和表均是设定为utf8编码格式,当不设置此选项时,导出的中文是乱码,奇怪的是官方说明中,说这个选项的默认值是utf8,表示不解。

导出整个数据库:

/usr/local/mysql/bin/mysqldump -uroot -p123456 -hlocalhost -t --extended-insert=false --default-character-set=utf8 SpiderBBSDB > /Users/ethan/Desktop/SpiderBBSDB.sql 

二、导入数据。

有导出就有导入。上面第5步导出的sql文件,可以直接在mysql workbench中执行,也可以使用mysqldump导入,这里说明一下如何使用mysqldump导入:

/usr/local/mysql/bin/mysqldump -uroot -p123456 -hlocalhost --default-character-set=utf8 SpiderBBSDB < /Users/ethan/Desktop/Catalog.sql

三、关于java连接mysql写入中文乱码。

关于这个中文乱码问题,着实折腾了我好久好久。一开始就百度谷歌bing,网上大多复制粘贴的答案,在这里记录一下自己的情况,希望同路人不再走弯路。

其实我的修改很简单,把数据库的编码改为utf-8,在新建表时,把表的默认编码也改为utf-8,就可以了。就这么个小小的改动,让我足足折腾了一个通宵,表示有解决问题强迫症,问题不解决真的睡不着,唉~~~

原文链接:http://www.cnblogs.com/zhaocq/archive/2013/03/23/2976610.html

 

Linux:为何编码规范每行代码不超过80个字符是合理的

也许在Python编码风格指导(PEP8)中最有争议的一部分要数每行代码不超过80个字符的限制。没错,实际上是79个字符,但我使用80个字符,这个大概数,它是给程序员的一个参考值。

编辑器

 

也许在Python编码风格指导(PEP8)中最有争议的一部分要数每行代码不超过80个字符的限制。没错,实际上是79个字符,但我使用80个字符,这个大概数,它是给程序员的一个参考值。

古老的VT100终端

古老的VT100终端

现在很多软件公司采用的编码规范基本是PEP8,但每行80个字符的限制除外。GitHub上的项目,大多数都遵循PEP8规范(这一点似乎达到了高度的统一),但遵守80个字符限制的很少。在一些有明确规定的规范标准中,这个限制可能会增加(100或120),甚至完全删除。这样做常长见的理由是:我们已经不是使用VT100终端编程的年代了,我们有了更大,更高分辨率的屏幕。这是事实,但我发现,在Python编码中采用这个80个字符的规范,配合空格的使用,这会让我们的代码更急凑,更可读。

有一点你可以看出,在自然情况下,Python语句的长度一般会占大概35-60个字符(不包括缩进)。更长的语句很少见。如果突然有一个句子比其它的要长很多,会显得很突兀,不好看。同样,使用强制性的空格来增加行宽能够从视觉上帮助你优化减少嵌套循环的层数,一般的建议是重构代码不要让缩进多于4层。

例如,把下面这个:

def search(directory, file_pattern, path_match,
           follow_symlinks=True, output=True, colored=True):
    ''' Search the files matching the pattern. The files will be returned, and can be optionally printed '''
    pattern = re.compile(file_pattern)
    results = []
    for root, sub_folders, files in os.walk(directory, followlinks=follow_symlinks):
        # Ignore hidden directories
        if '/.' in root:
            continue
        # Search in files and subfolders
        for filename in files + sub_folders:
            full_filename = os.path.join(root, filename)
            to_match = full_filename if path_match else filename
            match = re.search(pattern, to_match)
            if match:
                # Split the match to be able to colorize it
                # prefix, matched_pattern, sufix
                smatch = [to_match[:match.start()], to_match[match.start(): match.end()], to_match[match.end():]]
                if not path_match:
                    # Add the fullpath to the prefix
                    smatch[0] = os.path.join(root, smatch[0])
                if output:
                    print_match(smatch, colored)
                results.append(full_filename)
    return results

和这个比较:

def search(directory, file_pattern, path_match,
           follow_symlinks=True, output=True, colored=True):
    ''' Search the files matching the pattern.
        The files will be returned, and can be optionally printed '''
    pattern = re.compile(file_pattern)
    results = []
    for root, sub_folders, files in os.walk(directory,
                                            followlinks=follow_symlinks):
        # Ignore hidden directories
        if '/.' in root:
            continue
        # Search in files and subfolders
        for filename in files + sub_folders:
            full_filename = os.path.join(root, filename)
            to_match = full_filename if path_match else filename
            match = re.search(pattern, to_match)
            if match:
                # Split the match to be able to colorize it
                # prefix, matched_pattern, sufix
                smatch = [to_match[:match.start()],
                          to_match[match.start(): match.end()],
                          to_match[match.end():]]
                if not path_match:
                    # Add the fullpath to the prefix
                    smatch[0] = os.path.join(root, smatch[0])
                if output:
                    print_match(smatch, colored)
                results.append(full_filename)
    return results

在第一段代码里会出现滚动条,但即使是没有出现滚动条,这代码表现的也不美观,视觉上不平衡。第二段代码看起来更好,更容易阅读。

另外重要的一点是,我可以在屏幕上显示更多的东西。很多时候我们都需要屏幕上同时看一个文件的多个地方,或多个文件的内容。我喜欢的实现这个目的的方法是让它们按列排列。如果整个文件有80个宽度的限制,代码会有一个很好的呈现,我不用担心代码在编辑器里会否自动折行,不用去麻烦配置编辑器。如果我需要使用vim在命令行里快速编辑一个文件,就不用担心文件的宽度。能专注于代码。

竖行排列显示

竖行排列显示

唯一有问题的是使用Django的时候。当使用Django框架,你需要使用很多像这样的调用:

ThisIsMyModel.objects.find(field1=value1, field2=value2).count()

在有缩进的代码里,一个‘最小’的model函数调用都会让你没有多少剩余空间…但我仍然坚持相同的原则,尽量让代码表现的清晰可读,但这比起其它Python代码来要难的多。

所以,即使这个限制最初的愿望已经和现在完全不符合,我仍然觉得这个限制能帮助我写出更可读紧凑的代码。我是一个要求“可读性”的狂热分子,我甚至认为代码的可读性是一个最重要的需要考虑的方面,程序员应该在任何时候都铭记这一点。

 

[英文原文:80 chars per line is great ]
VIA http://www.aqee.net/80-chars-per-line-is-great/

 

 

 

Linux:牢记25个最佳的SSH命令

OpenSSH是SSH连接工具的免费版本。telnet,rlogin和ftp用户可能还没意识到他们在互联网上传输的密码是未加密的,但SSH是加密的,OpenSSH加密所有通信(包括密码),有效消除了窃听,连接劫持和其它攻击。此外,OpenSSH提供了安全隧道功能和多种身份验证方法,支持SSH协议的所有版本。

SSH是一个非常伟大的工具,如果你要在互联网上远程连接到服务器,那么SSH无疑是最佳的候选。下面是通过网络投票选出的25个最佳SSH命令,你必须牢记于心。

备注:本文最早出自  http://blog.urfix.com/25-ssh-commands-tricks/ ,国内有翻译,但是原文应该是多人拼凑而成,内容杂乱且有错误,国内转载翻译时也连错误一并搬了过来。由于其中一些技巧还是比较少见和有用,因此还是分享给大家参考,不过本站转载时,对其中部分内容进行了修订和删除,以期消除发现的错谬。

另外,本文的原始出处已经不可访问,不过可访问 http://www.pulog.org/Knows/1776/SSH-trick/ 保留的一份原文。

 

1、复制SSH密钥到目标主机,开启无密码SSH登录

ssh-copy-id user@host

如果还没有密钥,请使用ssh-keygen命令生成。

2、从某主机的80端口开启到本地主机2001端口的隧道

ssh -N -L2001:localhost:80 某主机

现在你可以直接在浏览器中输入http://localhost:2001访问这个网站。

3、将你的麦克风输出到远程计算机的扬声器

dd if=/dev/dsp | ssh -c arcfour -C 用户名@远程主机 dd of=/dev/dsp

这样来自你麦克风端口的声音将在SSH目标计算机的扬声器端口输出,但遗憾的是,声音质量很差,你会听到很多嘶嘶声。

4、比较远程和本地文件

ssh 用户名@远程主机 cat /path/to/remotefile | diff /path/to/localfile –

在比较本地文件和远程文件是否有差异时这个命令很管用。

5、通过SSH挂载目录/文件系统

sshfs 用户名@远程主机:/path/to/folder /path/to/mount/point

从http://fuse.sourceforge.net/sshfs.html下载sshfs,它允许你跨网络安全挂载一个目录。

6、通过中间主机建立SSH连接

ssh -t 中间主机 ssh 远程不可直接访问的主机

从本地网络无法直接访问的主机,但可以从中间主机所在网络访问时,这个命令通过到中间主机的“隐藏”连接,创建连接到远程不可直接访问的主机的连接。

7、原文此条和第一条重复

8、原文此条和第六条重复

9、创建到目标主机的持久化连接

ssh -MNf 用户名@主机

在后台创建到目标主机的持久化连接,将这个命令和你~/.ssh/config中的配置结合使用:

Host host
ControlPath ~/.ssh/master-%r@%h:%p
ControlMaster no

所有到目标主机的SSH连接都将使用持久化SSH套接字,如果你使用SSH定期同步文件(使用rsync/sftp/cvs/svn),这个命令将非常有用,因为每次打开一个SSH连接时不会创建新的套接字。

10、通过SSH连接屏幕

ssh -t remote_host screen –r

直接连接到远程屏幕会话(节省了无用的父bash进程)。

11、端口检测(敲门)

knock 主机 3000 4000 5000 && ssh -p 端口 用户名@主机 && knock 主机 5000 4000 3000

在一个端口上敲一下打开某个服务的端口(如SSH),再敲一下关闭该端口,需要先安装knockd,下面是一个配置文件示例。

[options]
logfile = /var/log/knockd.log
[openSSH]
sequence = 3000,4000,5000
seq_timeout = 5
command = /sbin/iptables -A INPUT -i eth0 -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 5000,4000,3000
seq_timeout = 5
command = /sbin/iptables -D INPUT -i eth0 -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn

12、从已知主机列表中删除一个主机

ssh-keygen -R 要删除的主机名

13、通过SSH运行复杂的远程shell命令(不用转义特殊字符)

ssh host -l user $(

更具移植性的版本:

ssh host -l user “`cat cmd.txt`”

14、通过SSH将MySQL数据库复制到新服务器

mysqldump –add-drop-table –extended-insert \
  –force –log-error=error.log \
  -uUSER -pPASS OLD_DB_NAME \
  | ssh -C user@newhost “mysql -uUSER -pPASS NEW_DB_NAME”

通过压缩的SSH隧道Dump一个MySQL数据库,将其作为输入传递给mysql命令,我认为这是迁移数据库到新服务器最快最好的方法。

15、原文该条目表述不清,删除

16、从一台没有ssh-copy-id命令的主机将你的SSH公钥复制到服务器

cat ~/.ssh/id_rsa.pub | ssh user@machine “mkdir ~/.ssh; cat >> ~/.ssh/authorized_keys”

如果你使用Mac OS X或其它没有ssh-copy-id命令的*nix变种,这个命令可以将你的公钥复制到远程主机,因此你照样可以实现无密码SSH登录。

17、实时SSH网络吞吐量测试

yes | pv | ssh 主机 "cat > /dev/null"

通过SSH连接到主机,显示实时的传输速度,将所有传输数据指向/dev/null,需要先安装pv。

18、如果建立一个可以重新连接的远程GNU screen

ssh -t 用户名@主机 /usr/bin/screen –xRR

人们总是喜欢在一个文本终端中打开许多shell,如果会话突然中断,或你按下了“Ctrl-a d”,远程主机上的shell不会受到丝毫影响,你可以重新连接,其它有用的screen命令有“Ctrl-a c”(打开新的shell)和“Ctrl-a a”(在shell之间来回切换),请访问http://aperiodic.net/screen/quick_reference阅读更多关于screen命令的快速参考。

19、继续scp大文件

rsync –partial –progress –rsh=ssh 源文件 用户名@主机:目标文件

它可以恢复失败的rsync命令,当你通过VPN传输大文件,如备份的数据库时这个命令非常有用,需要在两边的主机上安装rsync。

20、通过SSH w/wireshark分析流量

ssh 用户名@主机 ‘tshark -f “port !22″ -w -’ | wireshark -k -i -

使用tshark捕捉远程主机上的网络通信,通过SSH连接发送原始pcap数据,并在wireshark中显示,按下Ctrl+C将停止捕捉,但也会关闭wireshark窗口,可以传递一个“-c #”参数给tshark,让它只捕捉“#”指定的数据包类型,或通过命名管道重定向数据,而不是直接通过SSH传输给wireshark,我建议你过滤数据包,以节约带宽,tshark可以使用tcpdump替代:

ssh 用户名@主机 tcpdump -w – ‘port !22′ | wireshark -k -i -

21、原文此条和第九条重复

22、更稳定,更快,更强的SSH客户端

ssh -4 -C -c blowfish-cbc

强制使用IPv4,压缩数据流,使用Blowfish加密。

23、使用cstream控制带宽

tar -cj /backup | cstream -t 777k | ssh host ‘tar -xj -C /backup’

使用bzip压缩文件夹,然后以777k bit/s速率向远程主机传输。Cstream还有更多的功能,请访问http://www.cons.org/cracauer/cstream.html#usage了解详情,例如:

echo w00t, i’m 733+ | cstream -b1 -t2

24、原文此条和第一条重复

25、将标准输入(stdin)复制到你的X11缓冲区

ssh 用户名@主机 cat /path/to/some/file | xclip

你是否使用scp将文件复制到工作用电脑上,以便复制其内容到电子邮件中?xclip可以帮到你,它可以将标准输入复制到X11缓冲区,你需要做的就是点击鼠标中键粘贴缓冲区中的内容。 

VIA http://os.51cto.com/art/201304/390042.htm

Linux:利用ModSecurity防御暴力破解

在阅读本文前,先简单了解下什么是ModSecurity,ModSecurity是一个入侵探测与阻止的引擎.它主要是用于Web应用程序所以也可以叫做Web应用程序防火墙,相信不少商业WAF的签名开发同学也参考了ModSecurity的规则吧。

背景:

上周Wordpress网站遭受了大规模的暴力破解攻击,攻击者首先扫描互联网上的Wordpress网站,然后利用Web服务器组建的僵尸网络不断尝试用户名和密码试图登录管理界面。攻击者使用了超过9万台Web服务器来进行暴力破解。本文借用此例,来介绍下如何利用ModSecurity防御Wordpress的暴力破解。

常规的缓解暴力破解方法如下:

1:更改admin默认账户名称,或直接删除admin,添加一个新的管理员帐户。2:使用双因素认证 3:使用插件限制登录4:使用.htpasswd对访问特定页面实现用户名和密码验证。

这些都有现成的方法去实现了,这里就介绍一下用ModSecurity V2.7.3来保护Wordpress,防止暴力破解。

1:Wordpress的登录过程分析

下图为Wordpress的登录页面:

用户登录之后,发送请求到WP-loing.php页面,HTTP请求包内容如下:

POST /wordpress/wp-login.php HTTP/1.1
Host: mywordpress.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:12.0) Gecko/20100101 Firefox/12.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*; q=0.8
Accept-Language: en-us,en;q=0.5
DNT: 1
Referer: http://mywordpress.com/wordpress/wp-login.php
Content-Type: application/x-www-form-urlencoded
Via: 1.1 owaspbwa.localdomain
Connection: Keep-Alive
Content-Length: 73
log=administrator&pwd=pass123&submit=Login+%C2%BB&redirect_to=wp-admin%2F

payload部分包含了用户名和密码,以及登录成功后转向的页面。OK,了解数据包结构之后,我们可以创建规则,防止未经授权的访问。

2:检查Rerfer

正常的用户登录Wordpress,在数据包头部会包含一个Referer字段,但是通过人工编写的程序,很多不会包含Referer字段,直接发送登录请求到wp-login.php页面,所以,我们可以根据此创建一个ModSecurity规则来检查Rerfer字段信息:

SecRule REQUEST_METHOD "@streq POST" "chain,id:'1',phase:2,t:none,block,log,msg:'Warning: Direct Login Missing Referer.'"
  SecRule REQUEST_FILENAME "@pm /wp-login.php /wp-admin/" "chain"
    SecRule &REQUEST_HEADERS:Referer "@eq 0"

当然通过脚本,很容易实现Rerfer伪造,所以还需要接下来的规则一起配合。

3:限制访问的IP如果你不想修改默认管理员帐号,可以添加一个规则只允许特定的IP访问管理页面,如下:

SecRule REQUEST_METHOD "@streq POST" "chain,id:'1',phase:2,t:none,block,log,msg:'Warning: Direct Login Missing Referer.'"
  SecRule REQUEST_FILENAME "@pm /wp-login.php /wp-admin/" "chain"
    SecRule ARGS:log "@streq admin" "chain"
      SecRule REMOTE_ADDR "!@ipMatch 72.192.214.223"

在这个例子里,只允许名称为freebuf的管理员帐户通过72.192.214.223的IP地址来访问。

4:跟踪管理员帐户的登录尝试

我们可以通过ModSecurity的规则来block掉恶意IP,以下为登录失败的返回包:

HTTP/1.1 200 OK
Date: Fri, 11 May 2012 03:24:53 GMT
Server: Apache
Expires: Wed, 11 Jan 1984 05:00:00 GMT
Last-Modified: Fri, 11 May 2012 03:24:54 GMT
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 1697
Connection: close
Content-Type: text/html; charset=UTF-8WordPress › Login

WordPress

Error: Incorrect password.

可以看到状态码为200,而且返回的数据包中包含了Incorrect password,据此可以创建以下规则:

SecRule REQUEST_FILENAME "@streq /wordpress/wp-login.php" "chain, phase:4,id:999323,t:none,block,msg:'Authentication Failure Violation .',logdata:'Number of Authentication Failures: %{ip.failed_auth_ attempt}'"
  SecRule REQUEST_METHOD "@streq POST" "chain"
    SecRule ARGS:log "@streq admin" "chain"
      SecRule RESPONSE_STATUS "200" "chain"
        SecRule RESPONSE_BODY "@contains Error:Incorrect password." "chain,setvar:ip.failed_auth_attempt=+1,expirevar:ip.failed_auth_attempt=60"
          SecRule IP:FAILED_AUTH_ATTEMPT "@gt 5"

5:设置验证请求的次数

ModSecurity可以在指定的时间内跟踪请求的数量,设置阀值来进行阻断攻击,在它的规则集里已经个包含了该规则,modsecurity_crs_10_setup.conf

如下:

#
# -- [[ Brute Force Protection ]] ---------------------------------------------------------
#
# If you are using the Brute Force Protection rule set, then uncomment the following
# lines and set the following variables:
# - Protected URLs: resources to protect (e.g. login pages) - set to your login page
# - Burst Time Slice Interval: time interval window to monitor for bursts
# - Request Threshold: request # threshold to trigger a burst
# - Block Period: temporary block timeout
#
SecAction \
  "id:'900014', \
  phase:1, \
  t:none, \
  setvar:'tx.brute_force_protected_urls=/wp-login.php', \
  setvar:'tx.brute_force_burst_time_slice=60', \
  setvar:'tx.brute_force_counter_threshold=10', \
  setvar:'tx.brute_force_block_timeout=300', \
  nolog, \
  pass"

注意修改 setvar:’tx.brute_force_protected_urls=/wp-login.php‘,

设置完毕后,激活modsecurity_crs_11_brute_force.conf

 

#
# Anti-Automation Rule for specific Pages (Brute Force Protection)
# This is a rate-limiting rule set and does not directly correlate whether the
# authentication attempt was successful or not.
#
#
# Enforce an existing IP address block and log only 1-time/minute
# We don't want to get flooded by alerts during an attack or scan so
# we are only triggering an alert once/minute.  You can adjust how often
# you want to receive status alerts by changing the expirevar setting below.
#
SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "chain,phase:1,id:'981036',block,msg:'Brute Force Attack Identified from %{tx.real_ip} (%{tx.brute_force_block_counter} hits since last alert)',setvar:ip.brute_force_block_counter=+1"
	SecRule &IP:BRUTE_FORCE_BLOCK_FLAG "@eq 0" "setvar:ip.brute_force_block_flag=1,expirevar:ip.brute_force_block_flag=60,setvar:tx.brute_force_block_counter=%{ip.brute_force_block_counter},setvar:ip.brute_force_block_counter=0"
#
# Block and track # of requests but don't log
SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "phase:1,id:'981037',block,nolog,setvar:ip.brute_force_block_counter=+1"
#
# skipAfter Checks
# There are different scenarios where we don't want to do checks -
# 1. If the user has not defined any URLs for Brute Force Protection in the 10 config file
# 2. If the current URL is not listed as a protected URL
# 3. If the current IP address has already been blocked due to high requests
# In these cases, we skip doing the request counts.
#
SecRule &TX:BRUTE_FORCE_PROTECTED_URLS "@eq 0" "phase:5,id:'981038',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"
SecRule REQUEST_FILENAME "!@within %{tx.brute_force_protected_urls}" "phase:5,id:'981039',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"
SecRule IP:BRUTE_FORCE_BLOCK "@eq 1" "phase:5,id:'981040',t:none,nolog,pass,skipAfter:END_BRUTE_FORCE_PROTECTION_CHECKS"
#
# Brute Force Counter
# Count the number of requests to these resoures
#
SecAction "phase:5,id:'981041',t:none,nolog,pass,setvar:ip.brute_force_counter=+1"
#
# Check Brute Force Counter
# If the request count is greater than or equal to 50 within 5 mins,
# we then set the burst counter
#
SecRule IP:BRUTE_FORCE_COUNTER "@gt %{tx.brute_force_counter_threshold}" "phase:5,id:'981042',t:none,nolog,pass,t:none,setvar:ip.brute_force_burst_counter=+1,expirevar:ip.brute_force_burst_counter=%{tx.brute_force_burst_time_slice},setvar:!ip.brute_force_counter"
#
# Check Brute Force Burst Counter and set Block
# Check the burst counter - if greater than or equal to 2, then we set the IP
# block variable for 5 mins and issue an alert.
#
SecRule IP:BRUTE_FORCE_BURST_COUNTER "@ge 2" "phase:5,id:'981043',t:none,log,pass,msg:'Potential Brute Force Attack from %{tx.real_ip} - # of Request Bursts: %{ip.brute_force_burst_counter}',setvar:ip.brute_force_block=1,expirevar:ip.brute_force_block=%{tx.brute_force_block_timeout}"
SecMarker END_BRUTE_FORCE_PROTECTION_CHECKS

6:使用SecGuardianLog

从 1.9版本后,ModSecurity 支持一个新的指令,SecGuardianLog,设计此指令用于把所有允许数据通过管理日志功能发送到另一个程序。自从 apache部署成典型的多进程方式,信息共享变得困难了,这一想法就是部署一个独立的外部进程使用状态机的方式去观察所有的请求,提供额外的保护。使用方法如下:

语法: SecGuardianLog |/path/to/httpd-guardian
示例: SecGuardianLog |/usr/local/apache/bin/httpd-guardian
范围: Main
版本: 2.0.0

而且SecGuardianLog也可以和 SnortSam协同工作(http://www.snortsam.net)。如果已经配置过 httpd-guardian(具体介绍请查看源代码)你只需要在 apache配置中添加一行就可以部署它:

SecGuardianLog |/path/to/httpd-guardian

规则如下:

# If defined, execute this command when a threshold is reached
# block the IP address for one hour.
# $PROTECT_EXEC = "/sbin/blacklist block %s 3600";
# $PROTECT_EXEC = "/sbin/samtool -block -ip %s -dur 3600 snortsam.example.com";
my $PROTECT_EXEC;
# For testing only:
# $PROTECT_EXEC = "/sbin/blacklist-webclient %s 3600";
# Max. speed allowed, in requests per
# second, measured over an 1-minute period
my $THRESHOLD_1MIN = 2; # 120 requests in a minute

跟踪httpd守护进程数量,如果超过了限制,可以执行一些操作,如封锁IP一小时。

了解了一些ModSecurity的防止暴力破解规则之后,同志们可不要对freebuf进行破解,freebuf服务器小心脏经不起折腾,而且到时候IP被封可别找小编解封哦!:)

原文:http://blog.spiderlabs.com/2013/04/defending-wordpress-logins-from-brute-force-attacks.html 

VIA:http://www.freebuf.com/articles/web/8749.html 

 

 

Linux:解决linux中tracker大量占用CPU的问题

  在使用fedora的过程中, 有时会发现CPU的温度会突然升高, 本来正常情况下, CPU的温度也就在39~45度左右, 然后在gnome-terminal下, 运行top命令一看, 有几个以tracker开头的进程居然占用了将近100%的CPU, 难怪CPU的温度会突然上升到60多度。

  于是, 就自然想到了把这个软件卸载掉, 然而, 事实却没有这么简单。 如果卸载tracker软件, 会由于依赖关系卸载掉很多重要的软件, 比如nautilus, totem等等。

  后来, 自己google一下, 原来很多人也都遇到了这个问题, 最简单直接的方法就是把tracker禁用掉。 具体方法如下:

  1.在gnome-terminal中, 输入’gnome-session-properties'(不包括单引号), 回车。 然后弹出下图中所示窗口。

  2.找到Tracker存储和Tracker文件系统挖掘器。 把左边的勾勾取消掉。

  3.运行命令’tracker-control -S’, 会显示其没有运行, 就算成功了。

转自:http://blog.csdn.net/byguess/article/details/8818328

Linux:Linux命令行之逗趣无极限

  你有没有在Linux命令行中见过一辆火车呢?“猫跟老鼠”呢?编辑Linux命令行其实并不总是件严肃古板的事情。你完全可以用它自娱自乐。下面我们就跟大家一起讨论一下Linux命令行的特质。

  假设:本文所有示例都使用Ubuntu Linux。文中描述命令行功能或许在你的Linux系统中是默认的。

  有趣的Linux命令行功效

1. Linux“sl”命令行

  尽管“sl”代表了“蒸汽机机头”,但它是用来提醒那些命令行控们别把“ls”打成了“sl”。让我们看看在系统中运行这个命令的时候会怎样。

  首先,我们安装的时候,要将其设置为不与标准Linux一起出现。用“apt-get”可以很方便地完成安装。

sudo apt-get install sl

  大部分的安装需要sudo特权。完成安装后,在命令提示行中输入”sl”。

$sl

  我们看到了动画蒸汽机机头从屏幕右边开往左边。这个火车头是用ASCLL字符绘制。

  面是我机器上的效果图:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/211758k4kau9t3kh3gwwzk.png

  这难道比我们平时操作Linux 命令行要难吗?我认为沉浸在工作中的Linux用户看到这幅意料之外的动画时,肯定会心一笑,并意识到自己的输入有误。

  即便是这种简单的命令行也可以提供特定选项。详细命令参考:http://man.cx/sl%286%29

SYNOPSIS       sl [ -alFe ]DESCRIPTION       sl Displays animations aimed to correct users who accidentally enter sl instead of ls.  SL stands for Steam Locomotive.OPTIONS       -a     An accident seems to happen. You’ll feel pity for people who cry for help.       -l     shows little one.       -F     It flies.       -e     Allow interrupt by Ctrl+C.

  还可以用  $alia ls=sl  给人弄个恶作剧。

2. Linux “yes” 命令

  这里是一个在进程结束前一直打印输入字符串的命令。万一,用户不指定任何输入字符串,默认命令是”y”。

  命令会这样运行:

$yes mylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbookmylinuxbook^C$

  用”ctrl+c”结束前台运行进程。

  很奇怪,是吗?为什么我们希望命令在进程中一直打印字符串呢?尽管这样运行的方式很傻,但却不一定没用。我们可以用特定脚本中的”yes”命令,在 这些脚本中,我们可以用重复操作作答。例如,我们可以在一组文件上进行操作,而Linux会要求我们对文件进行确认。我们可以用”yes”命令自动回复。

3. Linux”rev”命令

  尽管非常简单,但我发现这行命令其实非常有意思。它会一行接一行地颠倒所输入的字符串。”rev”命令的名称来源于英文reverse。可以在命令指示符中输入”rev”然后按回车

$rev

  终端会提示我们通过标准输入提供一个字符串。那么在每行后面我们就可以同时看到输出。

  比如,我们输入”mylinuxbook”然后按回车。

mylinuxbookkoobxunilym

  为了回到命令提示符,可以使用”ctrl+c”。

  我们看到颠倒的字符串直接出现在了下一行。然后,我们可以输入下一个希望出现颠倒效果的字符串,接着按回车,就可以得到标准输出了。

$ revgoogleelgooglinux is funnuf si xunil^C$

  这行命令也可以以文件的形式输入,它会颠倒文件中的所有字符串,然后把输出结果打成标准输出。

$ cat strings.txtMyLinuxBookLinux is so much fun!Happy Birthday$ rev strings.txtkooBxuniLyM!nuf hcum os si xuniLyadhtriB yppaH

4. Linux”fortune” 命令

  Fortune命令是在相同命令行中作为fortune cookies。我们运行这个命令的时候随机找了一条谚语或信息。

  首先要对其进行安装,

$sudo apt-get install fortune

  安装完成后,我们运行这个命令的方式就是:

$ fortuneYou have the power to influence all with whom you come in contact.

  所以,依靠这个命令,Linux可以像个算命师一样。

5. Linux”figlet”命令

  这个命令会用大写方式把我们输入的字符串显示在标题栏,显示效果由ASCII字符组成。

  由于它不是标准设置,所以要先安装这一功能。

$sudo apt-get install figlet

  看到字符串在终端上变成这样确实很有意思。

$ figlet mylinuxbook

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/211800qv4qty3610ttsy3v.png

  你可以试着用”figlet”在脚本标头或源代码中添加标题栏。

6. Linux “toilet”命令

  我不知道这个命令的名字源自哪里。但是它确实个五颜六色的命令。与figlet一样,它会把文本显示称标题栏,但是效果更好。

  首先,安装:

$sudo apt-get install toilet

  然后试一试这个简单的命令:

$toilet mylinuxbook

  输入效果如下图所示:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/211801zqqcjb89b8lfuqn0.png

  它比figlet命令的效果更有艺术感。

  不过,它还可以添加颜色。我们可以运行下列命令看到颜色:

$toilet -f mono12 -F metal mylinuxbook

  效果如下图:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/2118020v70v4esf747v6eb.png

7. Linux “cowsay”命令

  Cowsay命令是一个有趣的命令。它会用ASCII字符描绘牛,羊和许多其他动物。但是不是每个Linux发行版都带有这个命令。

  使用下面的命令安装此命令:

$sudo apt-get install cowsay

  现在,运行命令,并在命令中给出一个信息字符串。

$cowsay “Linux is fun”

  我们看到了一个有趣的图像:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/211802inz5bn9iwi6ixxvb.png

  基本上,我们会看到一头牛告诉我们所输入的信息。尽管这个命令中只出现了cow,但其实它还可以有羊的效果。

$cowsay -f sheep “I too love linux”

  效果如图:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/21180364cyyur0by44ep46.png

  只需用 ‘-l 就能看到它能提供的所有动物。输入:

$cowsay -l

  系统会弹出下列信息:

Cow files in /usr/share/cowsay/cows:apt beavis.zen bong bud-frogs bunny calvin cheese cock cower daemon defaultdragon dragon-and-cow duck elephant elephant-in-snake eyes flaming-sheepghostbusters gnu head-in hellokitty kiss kitty koala kosh luke-koalamech-and-cow meow milk moofasa moose mutilated pony pony-smaller ren sheepskeleton snowman sodomized-sheep stegosaurus stimpy suse three-eyes turkeyturtle tux unipony unipony-smaller vader vader-koala www

  因此,我们可以用 ‘-f’ 输入以上信息中的任何动物。

  为了使之更有趣,你可以让cowsay说出fortune信息,如输入:

$fortune | cowsay

  则出现下面的效果:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/211804wo022oea7dwa9wpg.png

8. Linux “cmatrix”命令

  这个命令会在终端生成ASCII字符组成的矩阵风格的动画效果。

  先安装:

$sudo apt-get install cmatrix

  现在运行:

cmatrix

  出来的效果很酷:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/211806e1egbgrs0iip0og8.png

  用”ctrl+c” 结束,生成动画。

9. Linux “oneko” 命令

  这个命令是最好玩的。我们都知道”猫和老鼠”的动画,这个命令会让我们想起他们的追逐游戏。有了这行命令,我们可以看到一只猫在追老鼠(鼠标指示器)的效果。

  先安装:

$sudo apt-get install oneko

  运行这个命令,我们输入:

oneko

  然后你就可以看到不管鼠标指示器放到哪里,Tom猫都会追着跑。下面是截图,不过不足以显示动态的效果:

https://dn-linuxcn.qbox.me/data/attachment/album/201304/18/2118088ti8ai1b08sb4i5u.png

  即便我们切换应用,猫也不会离开老鼠。它甚至没有局限于终端。

  想关掉这个的时候,只需在终端里用ctrl+c 结束进程即可。

结语

  希望读者可以了解以上有趣的Linux命令行功能。如果你还知道更多诸如此类的有趣命令,不妨留言跟大家一起分享吧!

原文链接:http://mylinuxbook.com/funny-side-of-linux-command-line/

译文连接:http://os.51cto.com/art/201304/390059.htm

Linux:LINUX修改文件权限

  用户权限在Windows操作系统里也不陌生,但是Linux操作系统的用户权限和文件权限要比Windows操作系统里严格有效。比较明显的一个案例就是,即便是你在Windows操作系统里设置了多用户,但是不同的用户之间通过一定的方式,还是能够互访文件的,这就失去了权限的意义。

  LINUX文件权限针对的对象分三类(互斥的关系):

  • user(文件的拥有者)
  • group(文件拥有者所在的组,但不包括user)
  • other(其它用户,即user和group以外的)

  LINUX用一个3位二进制数对应着文件的3种权限(1表示有该权限,0表示无):

  • 第1位 读 r 100 4
  • 第2位 写 w 010 2
  • 第3位 执行 x 001 1

  查看权限

  #ls -l

  第一列,一共10位(drwxrwxrwx),就代表了文件的权限:

  • 第一个d代表是一个目录,如果显示“-”,则说明不是一个目录
  • 2-4代表user的权限
  • 5-7代表group的权限
  • 8-10代表other的权限

  对于后9位:

  • r 代表可读(read),其值是4
  • w 代表可写(write),其值是2
  • x 代表可执行(execute),其值是1
  • – 代表没有相应权限,其值是0

  修改文件权限

  # chmod [ugoa][+-=][rwx] 文件名

  1)用户

  • u 代表user
  • g 代表group
  • o 代表other
  • a 代表全部的人,也就是包括u,g和o

  2)行动

  • + 表示添加权限
  • – 表示删除权限
  • = 表示使之成为唯一的权限

  3)权限

  rwx也可以用数字表示法,不过很麻烦要自己算,比如 rw=6

  常见权限

  • -rw—— (600) 只有所有者才有读和写的权限
  • -rw-r——r—— (644) 只有所有者才有读和写的权限,组群和其他人只有读的权限
  • -rwx—— (700) 只有所有者才有读,写,执行的权限
  • -rwxr-xr-x (755) 只有所有者才有读,写,执行的权限,组群和其他人只有读和执行的权限
  • -rwx——x——x (711) 只有所有者才有读,写,执行的权限,组群和其他人只有执行的权限
  • -rw-rw-rw- (666) 每个人都有读写的权限
  • -rwxrwxrwx (777) 每个人都有读写和执行的权限,最大权限

Linux:安装漂亮的Faenza1.3与Faience0.5图标主题

相信你不会认识这两款图标主题,非常漂亮的图标主题, Faenza 1.3 与 Faience 0.5 也一直在更新,而且也支持更多的应用图标。图标设计类似苹果的方块圆角,直观漂亮。两款主题的版本现在为 Faenza 1.3 与 Faience 0.5 。

FaenzaIconsv1.3

faience_icon_theme_by_tiheum-d47vo5d

Ubuntu用户安装Faenza:

sudo add-apt-repository ppa:tiheum/equinox

sudo apt-get update

sudo apt-get install faenza-icon-theme

安装Faience:

sudo add-apt-repository ppa:tiheum/equinox

sudo apt-get update

sudo apt-get install faenza-icon-theme faience-icon-theme 

http://www.linuxeden.com/html/softuse/20130421/138444.html 

via http://imcn.me/

Linux:Linux系统硬盘读写测试

Linux服务器想要知道硬盘的读写是否能满足服务的需要,我们可以使用Linux自带的dd命令测试硬盘的读写速度,方法如下:

登录SSH,输入以下命令即可,根据测试数据的大小等待返回的时间不同。

Linux硬盘写入速度:

# time dd if=/dev/zero of=/var/test bs=2k count=1000000

Linux硬盘读取速度:

# time dd if=/var/test of=/dev/null bs=2k

命令详解:

  • time用于计时
  • dd用于复制,从if读出,写到of。
  • if=/dev/zero不产生IO,因此可以用来测试纯写速度;同理of=/dev/null不产生IO,可以用来测试纯读速度。
  • bs是每次读或写的大小,即一个块的大小,count是读写块的数量,相乘就是读写数据量大小。

数据量越大越准确,多次测试取平均值。

以阿里云服务器为例测试硬盘写入速度,2G的数据量,88秒,23.2MB/s,速度虽比不上自己电脑的硬盘,但作为WEB服务器,够用了。

读写 硬盘 测试 linux dd aliyun
via http://www.linuxde.net/2013/01/11863.html

Linux:Ubuntu各大分支版本功能介绍及下载地址

Ubuntu目标:(摘自官网)快速,免费,易用。特色:带有上千种免费的开源应用软件,支持各种电脑文件设备、打印机、数码相机、音乐播放器和智能手机。每年的4月和10月都会发布一个新版本。官方网站: http://www.ubuntu.com/下载地址: http://releases.ubuntu.com/下载地址: http://cdimage.ubuntu.com/网易镜像下载: http://mirrors.163.com/ubuntu-releases/搜狐镜像下载: http://mirrors.sohu.com/ubuntu-releases/下载地址:在线云系统 http://cdimage.ubuntu.com/ubuntu-cloud-live/下载地址:核心系统  http://cdimage.ubuntu.com/ubuntu-core/下载地址:Gnome桌面版系统 http://cdimage.ubuntu.com/ubuntu-gnome/下载地址:服务器版系统   http://cdimage.ubuntu.com/ubuntu-server/下载地址:手机及触摸式平板电脑系统(开发预览版) http://cdimage.ubuntu.com/ubuntu-touch-preview/


UbuntuKylin目标:构架真正的Ubuntu中文定制版。特色:与中国麒麟操作系统合作开发,加入多款中国本土软件,更多地支持中国地域网络服务。中文网站: http://www.ubuntukylin.com下载地址: http://cdimage.ubuntu.com/ubuntukylin/

 


 

Kubuntu目标:(摘自官网)这是一个可以替代微软Windows系统和Office办公套件的开源软件。特色:由全球专家团队开发的操作系统,包含了所有您需要的应用程序:Web浏览器,办公套件,媒体应用,即时消息客户端及其它更多软件。使用KDE桌面窗口管理器。官方网站: http://www.kubuntu.org/下载地址: http://www.kubuntu.org/getkubuntu下载地址: http://cdimage.ubuntu.com/kubuntu/下载地址:用于KDE4桌面 http://cdimage.ubuntu.com/kubuntu-kde4/下载地址:用于平板电脑 http://cdimage.ubuntu.com/kubuntu-active/下载地址:用于上网本电脑 http://cdimage.ubuntu.com/kubuntu-netbook/

 


 

Xubuntu 目标:(摘自官网)优雅,易用的系统,稳定、轻便、可配置桌面环境。特色:使用Xfce桌面窗口管理器,能完美高效地应用于台式机、笔记本、上网本电脑,极具现代感的外观和足够多的常用软件,也能运行在较旧的硬件上。官方网站: http://xubuntu.org/下载地址: http://xubuntu.org/getxubuntu/下载地址: http://cdimage.ubuntu.com/xubuntu/

 


 

Edubuntu 目标:(摘自官网)把所有最好的且免费的教育软件集成在一个易于安装和维护的系统内。特色:与教育有关的软件包均经过精心挑选,适合3至18岁的儿童与青少年学习,并能帮助教师备课、制作课件、进行教学管理等。不需要掌握复杂电脑技术,也能让资金有限的学校充分利用老旧电脑,简单快速地搭建起“服务器——客户端”教学系统。官方网站: http://www.edubuntu.org下载地址: http://www.edubuntu.org/download下载地址: http://cdimage.ubuntu.com/edubuntu/其它Linux发行版的Educational Systems教育系统分支版本:Debian-EduFedora Education SpinGuadalinux-EduOpenSuse-EduQimo for KidsUberstudent请参考: http://edubuntu.org/other-educational-systems

 


 

UbuntuStudio目标:(摘自官网)专为那些有创意的人们提供免费开放的系统。特色:提供全方位的多媒体内容创作的工作流程,包括图形、音频、视频、摄影和出版软件。官方网站: http://ubuntustudio.org/下载地址: http://ubuntustudio.org/download/下载地址: http://cdimage.ubuntu.com/ubuntustudio/

 


 

Lubuntu目标:(摘自官网)专注于速度和能源效率。因此,硬件要求非常低。特色:这是一个运行速度快,轻量级的操作系统,甚至可以安装运行在1999年出产的586老旧电脑上。使用最小型的桌面窗口管理器LXDE,把软件包的相互依赖性降到最低点。官方网站: http://lubuntu.net/下载地址: https://help.ubuntu.com/community/Lubuntu/GetLubuntu下载地址: http://cdimage.ubuntu.com/lubuntu/

 


 

Mythbuntu目标:(摘自官网)建立一个基于MythTV的电视录像及点播系统(PVR)。特色:带 有图形界面的MythTV控制中心可将电脑配置为PVR的主后端或前端,或前后端一并运行。能很方便地安装各种专用的驱动程序和解码器,也可以安装其它桌 面和软件。CD光盘本身就是一个可直接运行的前端,可选择主后端的网络位置、配置遥控器等,并且可以把相关设置保存在U盘上随身携带。官方网站: http://www.mythbuntu.org/下载地址: http://www.mythbuntu.org/downloads下载地址: http://cdimage.ubuntu.com/mythbuntu/


Gobuntu目标:全部100%纯开源自由软件系统。————至8.04版已经停止发布。特色:只包括开源无限制的软件,不会包含任何不开放源代码、不基于相关开源协议、不能自由使用、学习、开发、修改及再分发的固件、驱动、应用程序和内容。官网介绍: https://wiki.ubuntu.com/Gobuntu下载地址: http://cdimage.ubuntu.com/gobuntu/

 


 

Ubuntu-Women目标:(摘自官网)通过指导和启发,促进妇女在Ubuntu社区的参与和贡献。官方网站: http://wiki.ubuntu-women.org/

 


 

附:中国内地开源软件镜像下载网站汇总网易开源镜像站:

搜狐开源镜像站:

北京理工大学:

北京交通大学:

兰州大学:

厦门大学:

上海交通大学:

清华大学:

天津大学:

中国科学技术大学:

西南大学:

东北大学:

电子科技大学:

青岛大学:


摘自:http://forum.ubuntu.org.cn

Linux:Pinterest架构:两年内月PV从零到百亿

Pinterest正经历了指数级曲线般的增长,每隔一个半月翻翻。在这两年里,Pinterest,从 每月PV量0增长到10亿,从两名成立者和一个工程师成长为四十个工程师,从一台MySQL 服务器增长到180台Web 服务器(Web Engine),240台接口服务器(API Engine), 88台MySQL 数据库 (cc2.8xlarge) ,并且每台DB有一个备份服务器,110台Redis 实例服务(Redis Instance),200台 Memcache 实例服务(Memcache  Instance)。

令人叹为观止的增长。想一探Pinterest的传奇吗?我们请来了Pinterest的两位创立者Yashwanth Nelapati 和 Marty Weiner,他们将以 Scaling Pinterest为题讲述关于Pinterest架构的充满戏剧化的传奇故事。他们说如果能在一年半前飞速发展时能看到有人做类似题材的演讲的话,他们就会有更多的选择,以避免自己在这一年半里做出的很多错误的决定。

这是一个很不错的演讲,充满了令人惊讶的细节。同时这个演讲也是很务实的,归根结底,它带来了可让大家选择的策略。极度推荐

这篇演讲中有两个我最为看重的经验:

1.强大的架构在处理增长时通过简单增加相同的东西(服务器)来应对,同时还能保证系统的正确性。当遇到某种(性能)问题时,你想通过砸钱来扩容指的是你可以简单增加服务器(boxes)。如果你的架构能够做到这一点,那它就如金子一般强大而珍贵!

2. 当某些(性能问题)快到极限时大多数技术都会以他们自己的方式失败。这导致他们在审核工具时要考虑以下一些特性:成熟,好且简单,有名气且用的人多,良好的支持,持续的优异性能,很少失败,开源。按照这样的标准,他们选择了:MySQL, Solr, Memcache, and Redis,放弃了Cassandra ,Mongo。

这两点经验是相互联系的。遵循(2)中提到的标准的工具可以在扩容时简单增加服务器(boxes).当负载增加了,成熟的产品更少会有问题。当你遇到问题时,你至少希望它的社区团队能够帮助解决。当你使用的工具过于技巧化和过于讲究时,你会发现你遇到一堵无法逾越的墙。

在这段演讲里,碎片化(sharding)优于集群(clusterting)的观点是我认为最好的一部分。为了应对增长,通过增加资源,更少失败的模式,成熟,简单,良好的支持,最终圆满完成。请注意他们选择的工具以sharding的方式增长,而不是clustering。关于他们为什么选择sharding和他们如何做sharding是很有趣的事,这很可能触及到你以前未考虑过的场景。

现在,让我们看看Pinterest如何扩容:

(本段有些术语黑话不是很明白,望纠错)

基本概念

  • Pins是一幅关于其他信息的集合的图片,描述了为什么它对于用户来说很重要,可以链回到他们发现它的地方。
  • Pinterest是一个社交网络。你可以追踪人或者板报(boards).
  • Database:它包含了拥有pins的板报(boards)和拥有板报(boards)的人 ,可以追踪或重新建立(repin)联系,还包含认证信息。

启动于2010年三月–自我发现时期

此时此刻,你甚至不知道你在做的这个产品将要做什么。你有想法,迭代开发更新产品的频率很高。最终因遇到一些在现实生活中永远不会遇到的奇怪的简短的MySQL查询而结束。

早期的一些数字:

  • 两个创始人
  • 一个工程师
  • Rackspace托管服务器
  • 一个小型web引擎
  • 一个小型MySQL数据库


发表评论













最新评论

我也要发表评论

Linux:码农如何快速打造一个有设计感的网站

注:拥有属于自己的网站是很多人的梦想,但大多数人只能借助像 WordPress 这样的 CMS 实现,甚至很多公司网站也是这样。但这些网站大多数看起来都比较缺乏设计感,通俗来讲就是有点“土”。那么对于像程序员以及其他对设计比较小白们来说,如何能让你的网站看起来更加前卫,有范,有设计感呢?极客公园编译了 24WAYS 的文章 How to Make Your Site Look Half-Decent in Half an Hour 为您提供解决方法。

像我这样的程序员来说经常被“设计”这个词吓到,因为我是一名程序员而不是设计师,我拥有的是计算机学位证,另外我对 Comic Sans 字体并不介意。(注:Comic Sans 字体是 Win95 附带的一种漫画字体,设计行业极为排斥,设计师或那些拥有美学情结的人不屑与之为伍。更多查看这篇为什么不要使用 Comic sans 字体

虽然只是一名程序员,但我还是想让自己的网站看起来更加吸引人,一方面出于虚荣,因为这样可以显得我更加“专业”,而另一方面是出于现实,因为研究机构调查发现用户会更加信任那些网站“看起来”很好的网站。但是因为很长时间一直从事的是编程工作,对设计并不是熟悉,甚至害怕,因为在我这个外行看来设计是由很多只能感受不能言传身教的规则以及所谓的设计感悟组成的,知识壁垒比较高。

但是不久之前我决定要尽我最大努力让我网站看起来显得更加专业一点,即使比不上真正由设计师操刀做出来的效果,但对像我这种没有设计能力的人来说还是很有帮助的。

1. 使用 Bootstrap

如果你还没有使用 Bootstrap 的话那么赶紧开始吧,这个来自 Twitter 的开源项目使得网站设计真正进入大众化时代。

本质上 Bootstrap 是一种隔栅系统,由两名 twitter 员工 Mark Otto 和 Jacob Thornton 开发的开源前端框架[注:想了解更多请查看什么是 Twitter Bootstrap?],它集成了很多 CSS 样式的合集,可以帮助那些不懂或者不擅长 CSS 的开发人员快速的建立一个外观看起来很不错的网站。

使用 Bootstrap 的另一个好处就是网站本身就是自适应的(Responsive),可以省去各种为移动设备等的适配工作。此外,Bootstrap 还是可定制的,可以根据你的需求自己配置。(注:英文不好的可以查看中文版的 Bootstrap 文档或 Bootstrap中文网)

2. Bootstrap 定制指南

决定使用 Bootstrap 是迈出的重要一步,相比其他可以在前端开发上节省很多精力,但有利有弊,如果你决定使用 Bootstrap 的话就意味着很有可能会和其他人“撞框架”,就像默认的 WordPress 皮肤一样,如果大家都完全用 Bootstrap 的样式的话,会让不少见得多的人心生厌烦。

所以,如果实在抽不出时间的话可以去Wrap Bootstrap购买一份主题皮肤,这些主题皮肤都是由专业的设计师设计的,虽然不会成为唯一定制的,但已经看起来相当不错了,而且这种方法是最快速的。接下来就是以 Narrow marketing 这个模板(下图)为例教你如何自己定制一份完全属于你自己的 Bootstrap 。

一. 字体

修改网页字体是让网站看起来更有特色、有现代感的捷径,我们可以去谷歌的字体服务(免费正版)中随意挑选自己喜欢的字体,但是要注意字体间的搭配,在这里我们选择由 DesignShack 推荐的谷歌字体搭配中的一种:Cardo(用于标题) 和 Nobile(用于主体内文)。

  1. 在网页头部中加入此代码:

  2. 在 CSS 样式表 custom.css 中加入以下代码:h1, h2, h3, h4, h5, h6 {font-family: ‘Corben’, Georgia, Times, serif;} p, div {font-family: ‘Nobile’, Helvetica, Arial, sans-serif;}

添加完后刷新即可查看效果了,现在我们的网站样式已经变成下面这样了,看起来比默认好多了。

此外,除了谷歌的字体服务外还可以使用像 Fontdeck或 Typekit 字体服务,它们的字体更多,更多的字体搭配方案可以参考Type Connection

二. 纹理

知道如何让一个网站看起来更加高雅优雅一些吗?是的,纹理。就像 24WAY 的背景纹理一样。

但是这些纹理效果应该去哪里寻找呢?设计师 Atle Mo 的 Subtle Patterns 网站是个不错的去处,我们接下来就使用这个网站上的 Cream Dust 纹理。点击下载,将纹理图片保存到本地,然后放到根目录下的 /img/ 目录文件夹中,最后到 CSS 样式表中加入代码 body { background: url(/img/cream_dust.png) repeat 0 0;} 即可。(如果需要更多样式的纹理或纹理的其他用法的话可以看看 Smashing 的这篇文章)

添加纹理前后对比(大图)

三. 图标

这里的图标并不是指那些透明的 PNG 图片图标,而是图标字体,其加载方式和字体一样,由 CSS 样式控制,比起图片图标来说这种图标字体加载速度更加,对资源的消耗也更低。在去年 24WAY 曾经有一篇如何在网站中使用图标字体的文章。

对于 Bootstrap 框架来说,整合的图标字体是Font Awesome(Shifticons也是一个不错的选择),和谷歌的字体服务一样也是免费开源的。要使用它只需将其下载下来,然后在根目录下创建 /fonts/ 文件夹,将其放进去。然后再将 font-awesome.css 文件放到 /css/ 目录文件夹。

接着将引用写入网页头部中,代码为 ,这时候我们可以随时在网站上任意地方自由使用这些图标字体了,如要想将一个卡车图标添加到注册按钮的话只需声明一下就可以,Sign up today。同时为了防止加入图标字体后引起按钮拉伸变形,还需要一点点额外的工作,将按钮宽度加大一点(.jumbotron .btn i { margin-right: 8px; })。最后效果如下:

四. CSS3

将上面都搞定后接下来要做的就是再加点 CSS3 特效了,如果时间不够的话简单的添加上盒阴影box-shadow和字体阴影text-shadow就可以让网站增色不少,CSS 代码如下。

h1 { text-shadow: 1px 1px 1px #ccc; } .div-that-you want-to-stand-out { box-shadow: 0 0 1em 1em #ccc; }

如果时间足够的话还可以添加一个放射渐变填充效果,可以让标题的显示效果更重一些,如下面对比图所示。(如果想要更多 CSS 效果的话可以去学习一下 CodeSchool 的在线教程)

五. jQuery

其实到这里了话网站看起来已经很不错了,但为了让它更加个性化,还需要再添加上一张背景图片。对很多程序员来说这一步是比较难以进行的,那么应该如何选择一张设计师可能会使用的图片呢?答案就是去iStockPhoto或类似的付费图库中去寻找。

这里我们将使用 Winter Sun 这张照片,为了让网站保持自适应布局,还需要使用 Backstretch 这个 jQuery 插件让背景图可以随时自动调整大小。

  1. 首先需要付费下载背景图片,然后放到 /img/ 文件目录中去。
  2. 将此图片设置为的背景图(background-image): $.backstretch(“/img/winter.jpg”);
  3. 加入背景图后网页主题部分会产生遮挡,所以可以让其透明,这样网站效果看起来会更加现代、有设计感。这里可以使用这个技巧将网站变得透明,代码见右边,.container-narrow {background: url(/img/cream_dust_transparent.png) repeat 0 0;}

 效果

六. 色调

到这几乎差不多已经完成调整了,但如果你够细心的话会发现按钮以及导航菜单的颜色还是 Bootstrap 默认的蓝色系。在有着设计师存在网站,设计师都会负责进行网站色调的调整,为了保证网站的一致性,所有按钮和导航一般是三到四种颜色(更多可以查看极客公园之间的文章小按钮大学问)。

在这里,虽然不可能像大公司网站那样取色严谨,但还是有一些快速的方法使网站看起来很搭配的。

  1. 使用 GIMP 的取色器读取背景图片的主题颜色,确认其 GBR 十六进制值;
  2. 使用 Color Scheme Designer确认与差异大但同时又互补的颜色;
  3. 最后根据确定的颜色来制定按钮,可以用[Bootstrap Buttons][]等在线直接生成。

这样首页上那个大大的注册按钮就搞定了,接下来是修改导航菜单的颜色,这个比较简单,写入代码 .nav-pills > .active > a, .nav-pills > .active > a:hover {background-color: #FF9473;} 即可。看看咋样。

结语

如果经历过了上面所说的流程的话,相信你已经可以在比较短的时间内制作出了一个还能拿得出手的网站了。

原文地址:http://www.geekpark.net/read/view/176891

Linux:使用top命令查看CPU负载

在系统维护的过程中,随时可能有需要查看 CPU 使用率,并根据相应信息分析系统状况的需要。在 CentOS 中,可以通过 top 命令来查看 CPU 使用状况。运行 top 命令后,CPU 使用状态会以全屏的方式显示,并且会处在对话的模式 — 用基于 top 的命令,可以控制显示方式等等。退出 top 的命令为 q (在 top 运行中敲 q 键一次)。 

在命令行中输入 “top” 即可启动 top ,运行后如下图所示:

 top运行中的截图

如上图所示,top 的全屏对话模式可分为3部分:系统信息栏、命令输入栏、进程列表栏。

第一部分 — 最上部的系统信息栏   

第一行(top):

“00:11:04”为系统当前时刻;

“3:35”为系统启动后到现在的运作时间;

“2 users”为当前登录到系统的用户,更确切的说是登录到用户的终端数 — 同一个用户同一时间对系统多个终端的连接将被视为多个用户连接到系统,这里的用户数也将表现为终端的数目;

“load average”为当前系统负载的平均值,后面的三个值分别为1分钟前、5分钟前、15分钟前进程的平均数,一般的可以认为这个数值超过 CPU 数目时,CPU 将比较吃力的负载当前系统所包含的进程;

第二行(Tasks):

“59 total”为当前系统进程总数;

“1 running”为当前运行中的进程数;

“58 sleeping”为当前处于等待状态中的进程数;

“0 stoped”为被停止的系统进程数;

“0 zombie”为被复原的进程数; 

第三行(Cpus):

分别表示了 CPU 当前的使用率; 

第四行(Mem):

分别表示了内存总量、当前使用量、空闲内存量、以及缓冲使用中的内存量;

第五行(Swap):

表示类别同第四行(Mem),但此处反映着交换分区(Swap)的使用情况。通常,交换分区(Swap)被频繁使用的情况,将被视作物理内存不足而造成的。

第二部分 — 中间部分的内部命令提示栏 

top 运行中可以通过 top 的内部命令对进程的显示方式进行控制。内部命令如下表:

s – 改变画面更新频率

l – 关闭或开启第一部分第一行 top 信息的表示

t – 关闭或开启第一部分第二行 Tasks 和第三行 Cpus 信息的表示

m – 关闭或开启第一部分第四行 Mem 和 第五行 Swap 信息的表示

N – 以 PID 的大小的顺序排列表示进程列表

P – 以 CPU 占用率大小的顺序排列进程列表

M – 以内存占用率大小的顺序排列进程列表

h – 显示帮助

n – 设置在进程列表所显示进程的数量

q – 退出 top

s – 改变画面更新周期

第三部分 — 最下部分的进程列表栏

以 PID 区分的进程列表将根据所设定的画面更新时间定期的更新。通过 top 内部命令可以控制此处的显示方式。 

一般的,我们通过远程监控的方式对服务器进行维护,让服务器本地的终端实时的运行 top ,是在服务器本地监视服务器状态的快捷便利之一。

via http://os.51cto.com/art/201304/391420.htm 

该贴已经同步到 linux的微博

Linux:Linux压缩那些事儿

Linux的压缩命令的源文件只能有一个,这意味在压缩之前不得不先将要压缩的所有文件打包成一个包,然后再压缩包,这样来完成对多个文件的压缩。所以在了解解压缩之前就必须先了解打包命令。

Linux的打包一般都是通过tar命令来完成的,通过man tar,可以得到一些信息,tar来完成不同的动作是通过指定不同的参数来完成的,通常使用的也就是——x/c,这两个参数,它们的字面含义是c——create,x——extract,创建和分包提取,另外还有一些不常用的参数,比如a,将tar添加到另外一个tar包的末尾,t,列出包中的文件,-C,将工作目录切换到指定的目录下,指定这个参数就可以将解压后的文件放到指定的目录当中去了,等。另外有一个重要的参数f,这个参数可以打包的结果放在一个文件当中。

下面举两个简单的例子说明打包和分包提取:

1.打包文件,现在有3个文件,文件名分别是fiel1,file2,file3,把这三个文件打包成file.tar.

tar -cf file.tar file1 file2 file3

-c,打包模式,-f指定将要创建的打包结果存放文件。

2.解包文件,现在有一个包file.tar,将它解包。

tar -xf file.tar

-x,解包模式,-f指定tar包文件。

讲完打包,接着将压缩,压缩的作用毋庸置疑,一旦一件事物变的更为简单之后,各方面的操作就更为简单,Linux的压缩一般有几种方式,它们是gzip压缩,bzip2压缩,xz压缩。它们的输入都只有一个,下面讲一个实例,分别用这三种压缩方式来压缩file.tar,然后压缩好的压缩文件再分别用这三种方式解压,生成xfile.tar,由于分别对单纯的解压和压缩并不是本文的重点,所以有些参数就不着重介绍,但需要的时候会简单的介绍下。

1.用gzip操作

压缩:gzip file.tar (如想将文件压缩到指定的文件当中去,可用”gzip -c file.tar > xxx”,来完成,以下相同)

解压:gunzip -c file.tar.gz > xfile.tar

2.用bzip2操作

压缩:bzip2 -c file.tar > xifle.tar.bz2

解压:bunzip2 -cv xfile.tar.bz2 > xfile.tar

3.用xz操作

压缩:xz -c file.tar > xfile.tar.xz

解压:unxz -c xfile.tar.xz > xfile.tar

对于压缩来讲,压缩率显然是首要关注点,就压缩率而言,xz>bzip2>gzip,一般情况下xz能比bzip2高出15%的压缩率,比gzip高出30%的压缩率,但是另外的有一些东西在具体的场合下还是需要关心的,比如CPU占有率,xz虽然压缩比高,但是它的耗时却是最多的,这意味着占用了更多的CPU时间片,所以在选择压缩算法的时候还应该考虑到现在的首要关注点是什么,以此来选择压缩算法。

上面分别讲解了打包和解压缩这两个过程,但这两个过程是分开的,在通常情况下,这两个过程不会分开,而是用tar包一步将多个文件打包压缩成一个压缩包,下面将分别使用tar命令调用这三种压缩方式来完成一步将多个文件打包压缩成一个压缩包。

1.用tar调用gzip将file1,file2,file3生成压缩包

tar -czvf file.tar.gz file{1,2,3}

2.用tar调用bzip2将file1,file2,file3生成压缩包

tar -cjvf file.tar.bz2 file{1,2,3}

3.用tar调用xz将file1,file2,file3生成压缩包

tar -cJvf file.tar.xz file{1,2,3}

对于上面的文字,有点需要注意,那就是后缀名并不是必须的,Linux当中后缀名都不是必须的,这应该是一个基础点,之所以指定后缀名是为了便于区别,也方便一些粗糙的识别程序。

阅读完上面的文字,我相信对Linux的压缩应该有一定程度的掌握,其实最重要的还是要学会阅读man page,里面应有尽有,只是过全就会过于复杂,不太适合初学者

via 51CTO

该贴已经同步到 linux的微博

Linux:如何将 Ubuntu 13.04 升级到 GNOME 3.8

Ubuntu 13.04 在它的存档中装载了 GNOME桌面的一个老版本。这对需要稳定性的GNOME-fans来说真的太棒了,但是对那些想尝试最新发布版的人来说就不那么棒了。

感谢GNOME团队使在Ubuntu 13.04上安装/升级到GNOME 3.8 变得容易——而且有充足的理由你会想要那么做!

有大量的警告——大部分是说一些软件会有一些不稳定——但是很可能的是,你既然有足够的能力升级你的桌面,你也会很好处理任何可能出现的问题。

如何在Ubuntu 13.04中升级到 GNOME 3.8  

添加 GNOME 3 PPA(Personal Package Archives)

在你进一步浏览之前,确认你正在运行的是Ubuntu 13.04。你一定知道 最新发布版 。但更好的是, 运行 Ubuntu GNOME 13.04.

对这个少见的版本, 我们先给Ubuntu的Software Sources增加GNOME 3 PPA这可以不用命令行就做到,但出于简单化的目的,这么做要容易的多。

打开一个新的Terminal 窗口,仔细输入下面的命令。

sudo add-apt-repository ppa:gnome3-team/gnome3

 

升级或安装 GNOME Shell

在PPA添加以后,现在你需要根据你安装的东西做两个步骤中的一个。

如果你没有安装GNOME Shell,那么在一个新的终端程序中执行下面的命令,在提示的地方输入你的密码:

sudo apt-get update && sudo apt-get install gnome-shell ubuntu-gnome-desktop

根据安装的各种包,将显示下面的界面,询问你选择哪一个显示管理器——“登录画面”——Ubuntu应该用:

gnome

决定,决定…

这两个选项都会让你在登录之前选择一个会话(所以如果你希望的话你可以登录Unity环境)。‘lightdm’是Ubuntu默认选项,但为了一个真实的GNOME体验,例如获得锁定屏幕通知,你要选择GNOME显示管理器(GNOME Display Manager也称作GDM )

login screen display managers

LightDM和 GDM 并排展示

如果你确实安装了GNOME Shell,或正在使用Ubuntu GNOME, 运行这个命令:

sudo apt-get update && sudo apt-get dist-upgrade

 

用于额外的比特的可选的Staging PPA

如果你非常谨慎,也可以增加 GNOME 3 Staging PPA 。但是它之中的很多组件是不稳定的 – 这是一个大问题你必须关注 。

sudo add-apt-repository ppa:gnome3-team/gnome3-staging

sudo apt-get update && sudo apt-get dist-upgrade

重启并登录

就这么多——你已经全做完了。确保所有都尽可能非常的顺利,你就可以重启了。

如果你使用了默认的Unity登录界面,在用户区点击Ubuntu,选择 ‘GNOME’会话,然后继续并像正常情况登录。

sessions

Unity Greeter’s Session Selector

如果你要选择GNOME显示管理器,那么就在登录之前从会话下拉菜单选择‘GNOME’。

如果一切都正常,你将会看到类似这样的界面…

gnome

Ubuntu 13.04中的GNOME 3.8 桌面

一些不同

当随着Unity使用GNOME Shell时,一些需要注意到的不同。

首先,你会在System Settings看到两个“在线账户”入口。左边的是Ubuntu的。右边的是GNOME的版本。

为了与特定的GNOME应用集成,包括文档,联系人与Evolution邮件,还有日历,你会想将你的账户加到右边的版本。为了Shotwell相片管理, Empathy即时聊天和 Gwibber微博写作器支持,你需要使用左边的版本。

online-accounts

系统设置

同样System Settings中 ‘新鲜’的是 ‘Notifications’ 和‘Search’入口。二者都不言自明;前者使你选择可以发送通知的应用,而后者关心在叠加活动(Activities Overlay)中,哪个应用/资源显示结果。

卸载GNOME 3.8

要卸载 GNOME Shell桌面,我们需要做一些事情。

首先从Ubuntu Software Center安装PPA Purge

安装 PPA Purge

下一步打开一个新的终端窗口,运行下面的命令:

sudo ppa-purge ppa:gnome3-team/gnome3

注意在降级过程中终端里出现的任何提示。如果你也安装了GNOME 3 Staging PPA (见上文),你还需要运行:

sudo ppa-purge ppa:gnome3-team/gnome3-staging

下一步通过运行下面命令卸载GNOME Shell:

sudo apt-get remove gnome-shell ubuntu-gnome-desktop

清除任何没有被降级与卸载移除的残留的应用,然后重启。

英文原文:How To Upgrade to GNOME 3.8 in Ubuntu 13.04

来源:开源中国社区

Linux:大型发布会现场的 Wi-Fi 应该如何搭建?

老罗的锤子rom发布会才开始几分钟,就爆出现场网络瘫痪,@互联网的那点事在微博说新浪微博登录百人以上的发布会现场热点怎么也得有几十个才够用。一个发布会的wifi应该如何搭建,真的是几十个的话现场如何组织呢?

WiFi网络的部署要远远比一般人想象的复杂,不是说放上几十个AP带宽就自动增加几十倍,恰恰相反,简单放几十个AP带宽会由于AP之间的竞争而迅速使带宽下降为几乎不可用。实际上这个问题完全可以写一本书了,此处只有挂一漏万,简明扼要地讲个大概。对于大型活动做WiFi的规划,要按照这几步来做:

  • 情况调查:首先从主办方取得场地大小和人数、分布,包括场地地图。对于网络的规模和部署有个大概的估计。一般来讲要为每个人规划至少1个客户端设备,以往经验值可以按0.5个客户端来规划,由于智能手机和平板的普及,未来估计要往1.5~2个客户端靠拢了。手机和笔记本或者平板电脑有可能同时在上网。
  • 带宽估计:发布会要保证参与者能正常使用比较轻量级的互联网应用,最基本每个设备要分配500kbps的可用带宽。在这个基础上要考虑大型活动的特点。如果是新闻发布会,那么会有很多人上传视频,带宽分配需要重新考虑,每个人至少有一个设备应保证1Mbps带宽。如果是小组讨论会,那么带宽需求就会小得多。下图是一些典型应用通常需要的带宽。
  • 根据如上两点可以算出每个区域的带宽需求,下一步就是AP规划。虽然11g号称54Mbps带宽,实际可用的最多只有25Mbps,也就是说最多能保证50个设备同时浏览网页(在这个情况下由于客户端相互竞争,用户体验已经非常糟糕了,一般打个对折)。11n对于大部分手机只能保证35Mbps,对于笔记本电脑等支持MIMO的可以保证到70Mbps甚至更高。按照这个原则相应地在图上标出每个AP应该覆盖的区域。为了保证通信质量,为了保证比较好的体验,实际上应该控制每个AP接入的设备不超过刚才计算出的数目的一半。
  • 下一步就是分配信道。由于国内只能用2.4GHz的频段,这个频段虽然号称有11个信道(有的国家有13个),实际上只有1,6,11三个互相不重叠的信道可以用。把这三个信道尽可能互不重叠地在上图中覆盖起来(见上图)。有时候如果无法做到不重叠地覆盖,那么还要考虑用扇区天线把覆盖区域细分成几个扇区。
  • 信道分配完成后就要实地部署无线网络了(实际上在上述理论工作之前就应该做实地勘探,考虑墙壁和各种反射物的影响,此处为了简化略去)。部署时应该考虑用高增益天线,但是降低每个AP的发射功率,让其覆盖区域基本与规划的区域吻合。注意这里功率不是越大越好,应该让每个AP只覆盖规划好的区域,别越俎代庖。部署时可能需要用一些现场测量工具对于部署的效果进行评价,防止由于多径干扰出现死角。下图就是用11g部署和11n网络部署后整片区域的差异。红色区域表示覆盖不理想的情况,可以看出11n网络对于多径干扰抑制非常好。再过几年尽量就不要考虑兼容问题,部署时不要开启11g模式了。目前看起来还是需要通过11g接入点自身功率和天线调整,甚至增加额外接入点来弥补。
  • 有线网络规划部署:每个11g的AP应该接入至少百兆上行口,11n的AP应该接入千兆上行口。最后出口也要保证足够上下行带宽,上行传现场资料,下行供大家无聊或者需要查相关资料用,也要按上面第二步计算的总结果的按一定比例保留(取决于活动性质)。若是国内还要考虑多个运营商的出口。
  • SSID的分配:实际上除了少数情况用户实现已经分配好座位,大部分情况没有办法把用户固定在某个AP上,所以更常见的做法是所有AP设置同一个SSID。这里实际上涉及到瘦AP和AP控制器的管理问题,由于各家方案都不相同,就不细数了。
  • 用户认证和带宽控制:为了防止恶意蹭网,最好能对用户做基本的认证,比如凭入场券领取账号名和密码。同时对于每个账号要限制带宽使用,这也会涉及到用户认证和带宽管理,通常需要额外的服务器来处理。

至此一个较简单的WiFi网络才部署完毕。你给的链接找不到原文,我只能根据新闻说有3000人到场,猜测主办方低估了参会者带宽需求,原因无非是

  • AP数目不足(应该100个左右,至少50个)
  • AP规划不合理(太多包碰撞)
  • 或者AP崩溃(每个AP接入用户太多)
  • 或者AP控制器崩溃(无法同时响应这么多AP接入/断开请求)
  • 或者认证服务器崩溃(无法同时认证这么多用户)
  • 或者出口带宽太窄(按我的估计需要至少300MB上行,300MB下行)
  • 管理混乱(没有控制每个客户端设备流量)。

实际上这个发布会远不是最有挑战的无线接入,真正有挑战的是这个:Super Bowl plans to handle 30,000 Wi-Fi users at once超级碗的主办方需要对付73208个用户,安排了700多个个接入点,能够同时支持30000个连接(比例低一点儿,这么热烈的比赛,用户花在看手机上的时间应该比新闻发布会少得多)。美国人的课堂也很可怕,清一水的苹果笔记本,还不包括他们包包里的平板和手机!!!!!有兴趣的可以看看CIsco的这个报告(PDF格式),http://files.meetup.com/1698110/Cisco%2520presentation.pdf 

via http://www.zhihu.com/question/20890194 

Linux:视觉直观感受7种常用的排序算法

 

1 快速排序

介绍:

快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来,且在大部分真实世界的数据,可以决定设计的选择,减少所需时间的二次方项之可能性。

步骤:

▲从数列中挑出一个元素,称为 “基准”(Pivot),

▲重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。

递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

排序效果:

视觉直观感受7种常用排序算法

 

2 归并排序

介绍:

归并排序(Merge sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用

步骤:

▲申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列

▲设定两个指针,最初位置分别为两个已经排序序列的起始位置

▲比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置

▲重复步骤3直到某一指针达到序列尾

▲将另一序列剩下的所有元素直接复制到合并序列尾

排序效果:

视觉直观感受7种常用排序算法

 

3 堆排序

介绍:

堆积排序(Heapsort)是指利用这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

步骤:

(比较复杂,自己上网查吧)

排序效果:

视觉直观感受7种常用排序算法

###NextPage### 

4 选择排序

介绍:

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。

排序效果:

视觉直观感受7种常用排序算法

 

5 冒泡排序

介绍:

冒泡排序(Bubble Sort,台湾译为:泡沫排序或气泡排序)是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

步骤:

1、比较相邻的元素。如果第一个比第二个大,就交换他们两个。

2、对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。

3、针对所有的元素重复以上的步骤,除了最后一个。

4、持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

排序效果:

视觉直观感受7种常用排序算法 

6 插入排序

介绍:

插入排序(Insertion Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

步骤:

1、从第一个元素开始,该元素可以认为已经被排序

2、取出下一个元素,在已经排序的元素序列中从后向前扫描

3、如果该元素(已排序)大于新元素,将该元素移到下一位置

4、重复步骤3,直到找到已排序的元素小于或者等于新元素的位置

5、将新元素插入到该位置中

6、重复步骤2

排序效果:

(暂无)

 

7 希尔排序

介绍:

希尔排序,也称递减增量排序算法,是插入排序的一种高速而稳定的改进版本。

希尔排序是基于插入排序的以下两点性质而提出改进方法的:

1、插入排序在对几乎已经排好序的数据操作时, 效率高, 即可以达到线性排序的效率

2、但插入排序一般来说是低效的, 因为插入排序每次只能将数据移动一位>

排序效果:

视觉直观感受7种常用排序算法 

via http://www.blogjava.net/todayx-org/archive/2012/01/08/368091.html

Linux:Ubuntu 系统中通过火狐OS模拟器轻松体验 Firefox OS

西班牙已经发布了基于Firefox OS的手机,但是不是任何人能体验到,很都人都在苦苦等待,现在我们有另一种方法,不需要任何命令,没有纷繁复杂的安装步骤,在该文中,会教大家在ubuntu系统中一种轻松体验 Firefox OS。

 

只需在火狐浏览器中就可是实现:

firefoxosvs4

火狐OS模拟器是为开发者使用的,用来测试他们的程序的的火狐浏览器插件,下面是该模拟器的功能:

  • Push to Device
  • Rotation simulation
  • Basic geolocation API simulation
  • Manifest validation
  • Stability fixes for installation and updates to apps
  • Newer versions of the Firefox rendering engine and Gaia (the UI for Firefox OS)

安装火狐os模拟器复制下面的地址在firefox浏览器中打开:

https://ftp.mozilla.org/pub/mozilla.org/labs/r2d2b2g/r2d2b2g-linux.xpi

如下图程序开始下载:firefoxosvs

下载完成后点击安装按钮:firefoxosvs1

安装完成后如下图打开:firefoxosvs3

然后点击“stoped”启动:firefosvs2

然后享受firefoxOS吧,截图几张,供大家欣赏:

拨号:

firefoxosvs5

 

浏览器网站

firefoxosvs6

 

发短信

firefoxosvs7

Linux:安装 Ubuntu 13.04 后要做的六件事

  最新版本的Ubuntu已经新鲜出炉:Ubuntu 13.04,代号为Raring Ringtail。作为幕后开发Ubuntu Linux的公司,Canonical在为全新安装的系统设置一系列默认值方面已经做得很到位,但你可能还是想在几个方面对这款刚安装的这款操作系统进行增添或更改。

1. 调整隐私方面的设置。

  你在安装了Ubuntu后可能想调整隐私方面的设置。默认情况下,当你在Dash(托盘)里面输入搜索时,Ubuntu会提供在线搜索结果。这每一次搜索最后都通过Canonical的服务器来进行处理。禁用这项功能是个好主意。

  点击Launcher(启动器)上面的Settings(设置)图标(即上面带有齿轮和扳手的那个图标)。然后点击弹出来的System Settings(系统设置)窗口里面的Privacy(隐私)。关闭这个菜单里面的”Include online search results”(包含在线搜索结果)和”Record Activity”(记录活动)。

点击查看原始大图

2. 移除亚马逊购物滤镜。

  这项特性就上面这一项而言似乎是多余的,但在我看来仍似乎是个好主意。一旦你禁用了在线搜索结果,应该会在你的托盘里面看到亚马逊网站上销售的任何商品。我仍倾向于移除这项功能。

  打开终端窗口,输入下面这个命令,即可将亚马逊购物滤镜(Amazon Shopping Lens)从Unity Dash移除。

sudo apt-get remove unity-lens-shopping

  注销,重新登录,当你搜索Dash(托盘)时,应该不会看到来自亚马逊网站的结果。不过,除非你禁用了在线搜索结果,否则仍会在Video Search(视频搜索)部分看到亚马逊网站的促销内容。

3. 选择你所在地的速度最快的更新服务器。

  这个巧妙的小技巧将帮助你从速度最快的那台服务器获得系统更新程序。服务器速度会不一样,取决于你所在位置以及数据沿哪条路线发送到你处。Ubuntu里面有个实用工具,会检测所有可用的更新服务器,并为你找到速度最快的那台服务器。

  想使用该工具,从Launcher(启动器)再次打开System Settings(系统设置),鼠标双击Software & Updates(软件与更新)。然后点击其中的”Download from:”(下载来源:)下拉框,之后选择”Other…”(其他…)。在弹出来的下一个菜单中,点击”Select Best Server”(选择最佳服务器),该实用工具会开始为你搜寻速度最快的更新服务器。一旦搜索完毕,它会高亮显示速度最快的那台服务器,你只要点 击”Choose Server”(选择服务器),就可以完成任务。最后,点击Software & Updates(软件与更新)菜单里面的”Close”(关闭)。

https://dn-linuxcn.qbox.me/data/attachment/album/201305/08/190010hnhoatt1ihnxhg8a.png

4. 安装Unity Tweak工具。

  我之前曾撰文介绍过Unity Tweak工具。让人高兴的是,它已被添加到了Ubuntu 13.04的Ubuntu软件库当中。由于它已在主要的软件库中,所以你再也不需要为了安装它而添加个人软件包档案(PPA)。你可以从Ubuntu软件 中心搜索并安装它,也可以从命令行安装它,只要使用这个命令:

sudo apt-get install unity-tweak-tool

  一旦该工具安装完毕,你就可以从Dash(托盘)启动它。

https://dn-linuxcn.qbox.me/data/attachment/album/201305/08/1900121d82in2ldi2d2lvx.png

5. 安装多媒体编解码器。

  你可能需要的编解码器大多数位于ubuntu-restricted-extras软件包中,但是如果你想播放经过加密的DVD内容,就需要从Medibuntu软件库安装一些软件包。想启用Medibuntu软件库,你就需要往终端窗口里面输入这个长长的命令:

sudo -E wget –output-document=/etc/apt/sources.list.d/medibuntu.list http://www.medibuntu.org/sources.list.d/$(lsb_release -cs).list && sudo apt-get –quiet update && sudo apt-get –yes –quiet –allow-unauthenticated install medibuntu-keyring && sudo apt-get –quiet update

  一旦Medibuntu设置完毕,就用下面这个命令安装多媒体编解码器:

sudo apt-get install non-free-codecs libdvdcss

6. 安装新立得软件包管理器。

  Ubuntu软件中心是个相当棒的软件管理器,但是如果你之前使用Ubuntu或另一个Debian衍生版本已有一段时日,可能想要一款功能更齐全 的软件包管理器。新立得软件包管理器(Synaptic)过去包含在默认安装的Ubuntu系统中,但现在不再是这样。你可以从软件中心找到并安装它,或 者用这个命令来安装它:

sudo apt-get install synaptic

点击查看原始大图

  这就是我认为安装Ubuntu后要做的若干件事。如果你在全新安装了Ubuntu后还想做别的什么事,欢迎留言交流。

原文:http://tuxtweaks.com/2013/04/6-things-to-do-after-installing-ubuntu-13-04/

译文:http://os.51cto.com/art/201305/392646.htm

 已同步至 linux的微博

Linux:MongoDB的真正性能

最近开始研究MySQL和MongoDB,发现这方面资料不多。尤其是真正的说到点子上的文章,太少了。

有一些对比测试的文章基本上都是瞎测,测试方法都测到了马腿上,得出的结论基本上都是NoSQL毫无价值

容我借用Russell Smith 的那句话:不是MongoDB不行,是你不懂。

让我来分析一下MongoDB的真正性能吧。

有说MongoDB慢

  反对:不设其他唯一索引的情况下,只用_id 在普通办公电脑上每秒插入几万,在普通x86服务器上每秒插入十几万,你好意思说这个性能低?比mysql强出一个数量级。

      赞同:检索是真的慢,和sql数据库不同,越复杂的条件搜索MangoDB越吃亏,CPU和IO的双重压力。面对那些直接把SQL查询改写成MangoDB的用法,别转了,你不会收获任何性能提升。

      你不行:说你不行还是真的不行,MongoDB领导了NoSQL运动,NoSQL请注意,我们最主要反对的就是SQL的方法论,按SQL方法使用MangoDB你只能收获失望。再想想MongoDB的设计思想:文档化。_id 就是文件名,MongoDB是个文件系统。全文检索?别闹了,用文件名找文件,一个文件名对应一个文件,你绝对不会失望。

那么MongoDB究竟应该怎么用呢?

首先,忘记SQL

你应该忘记你学过的那些优雅无敌的SQL,不是说为了提升检索性能,扔索引就有好处。

有一个简单的事实如下:只有一个默认的_id 索引,此时插入性能为1,你再加一个索引,插入性能约1/2,再加一个约1/3 ,以此类推……

如果这个事实对你是很震撼的,那说明你还没有忘记SQL,接着忘。

MongoDB的索引对插入性能有着不可忽略的拖后腿效应,所以,我们应该使用且仅使用 _id 作为插入key,作为查询key,作为所有的那个key。

其次,直接忘记搜索这件事。

把MongoDB当做你的硬盘,给他文件名去操作文件.这就是Key-Value数据库的做法,你稍加设计就能这么用。

那么其实你所有的操作可以简化为两个指令,逻辑上 就是一个字典

你给他_id,往字典里插一个数据,或者拿一个数据。

Save({_id:xxx,…..})

FindOne({_id:xxx})

要想高性能,善用那个_id,把你原来准备当主键的那个玩意,hash成_id.

把你原来准备的查询条件,什么?查询,拿_id来,别的全砍掉。

第三、这不是数据表

记住,这不是数据表,一个_id对应的东西不是一行数据,而是一个文件。

文件存储和表存储有什么不同呢?

我举个例子,比如我们要存储用户列表和每个用户的道具列表。

数据表的做法是建一张用户表,一张道具表,道具表里有个字段表示他属于哪个用户。

然后,你就离不开万恶的查询了。

然后如果一个用户有100条道具,100万用户意味着道具表有一亿条记录。

这时候就开始考验你的小数据库了,但这都是过去式了,这一亿的道具,用MongoDB,根本不是个事儿

因为MongoDB的方法是当做文件存,只设计一个用户集合,每个用户的信息是一个文件,然后这100个道具就分开存在每个用户的文件里。

然后来比较一下,我们取得用户的记录,然后从中拿出100个道具,NoSQL方法。

查一亿的表,找出属于某个用户的记录。

熟快熟慢?

然后你可能回想,SQL方法,我也可以搞个道具字段,把用户的100个道具用某种协议打包,然后操作啊,一样可以取得巨大的优化呀。

没错,你的想法很好,你正在用NOSQL的方式用SQL。

第四、文件存储的精华之处

如果问题止于此处,MongoDB就毫无优势可言了,如果这个方法在SQL数据库上也是如此容易使用,那还费劲搞MongoDB干什么?

我们再折腾一点,如果每个道具还要存100条转手记录,你还是可以打包,但你这个打包字段已经1M了。

于是每次存取这个打包字段都是一个系统工程了,还要负担1M的流量。

MongoDB这边呢?我们可以直接对文件的一部分进行读写,比如我只返回一个用户的第二个道具的信息,和返回第二个道具的第1~30条转手记录。

这,是一种怎样的差距啊。

你想要一张美女的照片,你朋友有,但是他只有一个压缩包,他那里没有解包工具,于是他把整个包传给了你。他想问你要一张照片,但是他没有压缩工具,为了存档需要,他让你再压进包里传给他。

这个朋友就是你的用户表的一行,如果换成真实世界的事件是多么的不可思议,这就是在一个字段里打包数据的问题。

MongoDB的一条记录就是一个脑筋更正常的朋友,你要他一张照片,他从包里找出来给你。你给他一张照片,他分门别类的放置到他的包里去。

用文件的思维去访问,MongoDB是一个更好的朋友。

审视一下你项目中的大部分的数据需求,是不是都可以用这种方式去组织呢?

如果是,加入NOSQL吧,我们的口号是:很暴力不SQL

还有什么好处 

1.不用逻辑关心的水平切分

  无需多言,对MongoDB而言,这是运维人员的工作了

2.不用对齐的数据结构

  不用对齐意味着你不用为以前表结构变化的迁移烦恼,有些文件里有一个部分,有些没有,这对MongoDB而言,很正常。

via http://www.cnblogs.com/crazylights/archive/2013/05/08/3066056.html 

Linux:Ubuntu 13.04 系统管理初探

   Ubuntu 13.04 (代号 Raring Ringtail)正式版于上个月底发布,很多对 Ubuntu 情有独钟的网友已经迫不及待尝鲜了,51CTO系统频道也体验了一下,大家可以通过《Ubuntu 13.04 来袭:铆劲浣熊酷炫体验》查看。本篇文章将从系统管理方面入手,继续探究Ubuntu 13.04 的奥秘。

1 设置shell版本

  /bin/sh 是 /bin/dash,的符号链接。Ubuntu为了加速开机的速度使用了dash来取代传统的bash,/bin/sh -> /bin/bash改成了/bin/sh -> /bin/dash。虽然说dash体积有比较小开机时速度也比较快,但是在开机之后使用某些原本在bash环境可以正常使用的脚本,换到了dash之后 反而会出现一些莫名其妙的问题,这里笔者要改回去。

#dpkg-reconfigure dash(选择否即可)

点击查看原始大图

图 1 dpkg-reconfigure 工作界面

  再次检查一下, ls /bin/sh -al 发现软链接指向/bin/bash就可以了。

  说明:dpkg-reconfigure用来重新配制一个已经安装的软件包,通常把什么软件“弄坏了”,都可以通国dpkg- reconfigure来重新配置。例如dpkg-reconfigure xserver-xfree86 配置显卡,显示器鼠标,键盘.,dpkg-reconfigure locales 产生locale及default locale,dpkg-reconfigure etherconf 配置以太网参数。

  Debian Almquist shell,缩写为dash,一种 Unix shell,相容于POSIX标准。它比 Bash 小,只需要较少的磁盘空间,但是它的对话性功能也较少。它由 NetBSD版本的Almquist shell (ash)发展而来,于1997年,由赫伯特·许(Herbert Xu)移植到Linux上,于2002年改名为 dash。

2 介绍一下查看Ubuntu版本的几个方法

  对于桌面系统查看系统设置中详细信息中的即可如图1

https://dn-linuxcn.qbox.me/data/attachment/album/201305/09/165614f87oc677ak5k8lka.jpg

  对于服务器版本,如果没有安装X Window可以使用如下几个命令:

方法一:#lsb_release -a

方法二:#uname -a

方法三:#cat /etc/issue

方法四:#cat /etc/lsb-release

  以上几个命令的输出略有不同如图3。

https://dn-linuxcn.qbox.me/data/attachment/album/201305/09/165615hqdbb33j34zl4dbf.jpg

图3 查看Ubuntu版本

3 服务器版本语言设置

#apt-get -y install language-pack-cn-base language-pack-cn

  更新中文UTF的本地环境:

sudo locale-gen zh_CN.UTF-8sudo update-locale LANG=zh_CN.UTF-8

  服务器版本时选择语言为English的原因。如果设置了中文,可以通过下面的方法修改系统语言为英文:

sudo nano /var/lib/locales/supported.d/local 改成 en_US.UTF-8 UTF-8sudo vim /etc/default/locale 将 LANG=”zh_CN.UTF-8″ LANGUAGE=”zh_CN:zh”

  修改为:LANG=”en_US.UTF-8″ LANGUAGE=”en_US:en”

sudo locale-gen

  reboot 重启系统之后,ubuntu server  系统语言显示英文,也就不再出现乱码中文了。

  如果出现warning: setlocale: LC_CTYPE: cannot change locale (en_US)

  执行下列指令:

sudo locale-gen en_US.UTF-8sudo update-locale LANG=en_US.UTF-8

4 使用tasksel架建LAMP

  本来Ubuntu下架建LAMP,需要apt安装很多包,记住那些包的名字比较麻烦,可以使用tasksel安装LAMP套件。先说说什么是 Tasksel,它是一个Debian下的安装任务套件,如果你为了使你的系统完成某一种常规功能,而需要安装多个软件包时,我们就可以使用它了。这句话 是什么意思呢?比如说,我们需要安装LAMP架设一个web服务器,为了完成这个功能,我们一般需要安装很多个软件包,用apt的话,我们就需要分别安装 这些包(包含apache2、php5等等),以便构成一个完整的(符合我们要求的)LAMP系统。而如果使用tasksel的话,就可以用它方便的给我 们安装一个完整的LAMP套件,而无须我们去关心具体需要由哪些包来构成这个统一的套件。需要指出的是,通过tasksel软件包不仅可以安装LAMP组 件,还可以安装其他服务器组件,比如DNS服务器,Mail服务器,打印服务器等。其实使用tasksel安装LAMP套件的方法很简单:

sudo tasksel install lamp-server

  然后:

sudo tasksel

  然后在tasksel界面中选LAMP-Server就OK了如图4。

https://dn-linuxcn.qbox.me/data/attachment/album/201305/09/165615yioo1o8kipuxa1a1.jpg

图4 工作界面

  安装过程中会提示你输入mysql的root密码。

$sudo vi /var/www/info.php

 

phpinfo();?>

 

$sudo /etc/init.d/apache2 restart

  安装完成了,现在你可以运行apache2来启动apache了,然后在浏览器里输入127.0.0.1/info.php,看看是不是已经显示测试页面了如图5:

点击查看原始大图

图5

  下面通过命令:sudo apt-get install phpmyadmin,安装MySQL管理工具phpmyadmin。

  下面使用浏览器访问http://ip/phpmyadmin或者http://localhost/phpmyadmin,如图6:

点击查看原始大图

图6

Linux:MongoDB的真正性能-实战百万用户一:一亿的道具

上一篇为求振聋发聩的效果,有些口号主义,现在开始实战,归于实用主义。

使用情景

开始之前,我们先设定这样一个情景:

1.一百万注册用户的页游或者手游,这是不温不火的一个状态,刚好是数据量不上不下的一个情况。也刚好是传统MySql数据库性能开始吃紧的时候。

2.数据库就用一台很普通的服务器,只有一台。读写分离、水平扩展、内存缓存都不谈。一百万注册用户如果贡献度和活跃度都不高,恐怕公司的日子还不是那么宽裕,能够在数据库上的投资也有限。

以此情景为例,设每个用户都拥有100个道具,用户随时会获得或失去道具。

我们就来看看这一亿的道具怎么搞。

道具一般要使用原型、实例的设计方法,这个不属于数据库的范畴。

道具类型001 是屠龙刀,屠龙刀价格1500,基础攻击150,这些,我们把它们称为道具原型,保存在原型数据文件中。

这个原型数据文件,无论是存在何种数据库或者本地文件中,对服务器来说都不是问题,也不干扰数据库设计,所以我们不去讨论他。

关系数据库设计方法

典型的关系数据库设计方法:

用户表:字段 xxx userid xxx   ,记录数量100万

xxx是其他字段,userid标示用户

用户道具表:字段 xxx userid itemtype xxx ,记录数量一亿

xxx是其他字段,userid 标示

一个亿的记录数是不是看起来有点头疼,mysql这个时候就要想各种办法了。

MongoDB设计方法

但我们用mongoDB来实现这个需求,直接就没有问题

首先第一个集合:users集合,用UserName 作为_id ,记录数100万

然后道具的组织,我们有两种选择

1.在users集合的值中建立Items对象,用Bson数组保存道具(Mongo官方称为Bson,和Json一模一样的存储方法)

方法一,没有额外的记录数

2.新建userItems集合,同样用UserName作为_id 每个UserItems集合的值中建立一个Item对象,使用一个Bson数组来保存道具

方法二,多了一个集合和100万记录数

 

我们的道具数据看起来像下面这样:

{_id:xxx,Items:[

{Itemtype:xxx,ItemPower:xxx},

 

]}

测试方法

测试方法如下:测试客户端随机检查一个用户的道具数量,小于100加一个道具,大于100 删除一个道具。

连续100万次,采用10个线程并发。

如果用关系数据库设计方法+mysql来实现,这是一个很压力很大的数据处理需求。

可是用文档数据库设计方法+MongoDB来实现,这个测试根本算不上有压力。

注意事项

即使我们用了一个如此胜之不武的设计方式,你依然有可能还是能把他写的很慢。

因为MongoDB在接口设计上并没有很好的引导和约束,如果你不注意,你还是能把他用的非常慢。

第一个问题:Key-Value数据库可以有好多的Key,没错,但对MongoDB来说,大错特错

MongoDB的索引代价很大,大到什么程度:

1.巨大的内存占用,100万条索引约占50M内存,如果这个设计中,你一个道具一条记录,5G内存将用于索引。

我们的屌丝情景不可能给你这样的服务器,

2.巨大的性能损失,作为一个数据库,所有的东西终将被写入硬盘,没有关系数据库那样的表结构,MongoDB的索引写入性能看起来很差,如果记录数据较小的时候,你可以观测到这样震撼的景象,加一个索引,性能变成了1/2,加两个索引,性能变成了1/3。

只有当第二个索引的查询不可避免,才值得增加额外索引。因为没索引的数据,查询性能是加几个零的慢,比加索引更惨。

我们既然选择了Key-Value数据库,应尽量避免需要多个索引的情况。

所有的索引只能存在于内存中,而读取记录时,也需要将Bson在内存中处理,内存还承担着更重要的作用:读取缓存。

本来就不充裕的内存,应该严格控制我们的记录条数,能够用Bson存储的,尽量用之。

那么我们之前在MongoDB的设计中怎么还考虑第二种设计方法呢?独立一个userItems 集合,不是又多出100万条记录了吗?

这基于另两个考虑:a.Bson的处理是要反复硬盘和内存交换的,如果每条记录更小,则IO压力更小。内存和硬盘对服务器来说都是稀缺资源,至于多大的数据拆分到另一个集合中更划算,这需要根据业务情况,服务器内存、硬盘情况来测试出一个合适大小,我们暂时使用1024这个数值,单用户的道具表肯定是会突破1024字节的,所以我们要考虑将他独立到一个集合中

b.可以不部署分片集群,将另一个集合挪到另一个服务器上去。只要服务器可以轻松承载100万用户,200万还会远么?在有钱部署分片集群以前,考虑第二组服务器更现实一些。

第二个问题:FindOne({_id:xxx})就快么?

毋庸置疑,FindOne({_id:xxx})就是最直接的用Key取Value。

也的确,用Key取Value 就是我们能用的唯一访问Value的方式,其他就不叫Key-Value数据库了。

但是,由于我们要控制Key的数量,单个Value就会比较大。

不要被FindOne({_id:xxx}).Items[3].ItemType这优雅的代码欺骗,这是非常慢的,他几乎谋杀你所有的流量。

无论后面是什么 FindOne({_id:xxx})总是返回给你完整的Value,我们的100条道具,少说也有6~8K.

这样的查询流量已经很大了,如果你采用MongoDB方案一设计,你的单个Value是包含一个用户的所有数据的,他会更大。

如果查询客户端和数据库服务器不在同一个机房,流量将成为一个很大的瓶颈。

我们应该使用的查询函数是FindOne({_id:xxx},filter),filter里面就是设置返回的过滤条件,这会在发送给你以前就过滤掉

比如FindOne({_id:xxx},{Items:{“$slice”:[3,1]}}),这和上面那条优雅的代码是完成同样功能,但是他消耗很少的流量

第三个问题:精细的使用Update

这和问题二相对的,不要暴力的FindOne,也尽量不要暴力的Update一整个节点。虽然MangoDB的性能挺暴力的,IO性能极限约等于MongoDB性能,暴力的Update就会在占用流量的同时迎接IO的性能极限。

除了创建节点时的Insert或者Save之外,所有的Update都应该使用修改器精细修改.

比如Update({_id:xxx},{$set:{“Items.3.Item.Health”:38}});//修改第三把武器的健康值

至于一次修改和批量修改,MongoDB默认100ms flush一次(2.x),只要两次修改比较贴近,被一起保存的可能性很高。

但是合并了肯定比不合并强,合并的修改肯定是一起保存,这个也要依赖于是用的开发方式,如果使用php做数据客户端,缓存起来多次操作合并了一起提交,实现起来就比较复杂。

 

注意以上三点,一百万注册用户并不算很多,4G内存,200G硬盘空间的MongoDB服务器即可轻松应对。性能瓶颈是硬盘IO,可以很容易的使用Raid和固态硬盘提升几倍的吞吐量。不使用大量的Js计算,CPU不会成为问题,不要让索引膨胀,内存不会成为问题。你根本用不着志强的一堆核心和海量的内存,更多的内存可以让缓存的效果更好一些,可是比读写分离还是差远了。如果是高并发时查询性能不足,就要采用读写分离的部署方式。当IO再次成为瓶颈时,就只能采用集群部署MongoDB启用分片功能,或者自行进行分集合与key散列的工作。

 via http://www.cnblogs.com/crazylights/archive/2013/05/08/3068098.html 

Linux:详解JavaScript中的this

JavaScript中的this总是让人迷惑,应该是js众所周知的坑之一。 个人也觉得js中的this不是一个好的设计,由于this晚绑定的特性,它可以是全局对象,当前对象,或者…有人甚至因为坑大而不用this。

其实如果完全掌握了this的工作原理,自然就不会走进这些坑。来看下以下这些情况中的this分别会指向什么:

1.全局代码中的this

alert(this)//window

全局范围内的this将会指向全局对象,在浏览器中即使window。

2.作为单纯的函数调用

 
function fooCoder(x) {
	this.x = x;
}
fooCoder(2);
alert(x);// 全局变量x值为2

这里this指向了全局对象,即window。在严格模式中,则是undefined。

3.作为对象的方法调用

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		console.log(this.name + " says " + sth);
	}
}
person.hello("hello world");

输出 foocoder says hello world。this指向person对象,即当前对象。

4.作为构造函数

new FooCoder();

函数内部的this指向新创建的对象。

5.内部函数

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		var sayhello = function(sth) {
			console.log(this.name + " says " + sth);
		};
		sayhello(sth);
	}
}
person.hello("hello world");//clever coder says hello world

在内部函数中,this没有按预想的绑定到外层函数对象上,而是绑定到了全局对象。这里普遍被认为是JavaScript语言的设计错误,因为没有人想让内部函数中的this指向全局对象。一般的处理方式是将this作为变量保存下来,一般约定为that或者self:

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		var that = this;
		var sayhello = function(sth) {
			console.log(that.name + " says " + sth);
		};
		sayhello(sth);
	}
}
person.hello("hello world");//foocoder says hello world

6.使用call和apply设置this

person.hello.call(person, "world");

apply和call类似,只是后面的参数是通过一个数组传入,而不是分开传入。两者的方法定义:

call( thisArg [,arg1,arg2,… ] );  // 参数列表,arg1,arg2,...
apply(thisArg [,argArray] );     // 参数数组,argArray

两者都是将某个函数绑定到某个具体对象上使用,自然此时的this会被显式的设置为第一个参数。

简单地总结

简单地总结以上几点,可以发现,其实只有第六点是让人疑惑的。

其实就可以总结为以下几点:

1.当函数作为对象的方法调用时,this指向该对象。

2.当函数作为淡出函数调用时,this指向全局对象(严格模式时,为undefined)

3.构造函数中的this指向新创建的对象

4.嵌套函数中的this不会继承上层函数的this,如果需要,可以用一个变量保存上层函数的this。

再总结的简单点,如果在函数中使用了this,只有在该函数直接被某对象调用时,该this才指向该对象。

obj.foocoder();
foocoder.call(obj, ...);
foocoder.apply(obj, …);

更进一步

我们可能经常会写这样的代码:

$("#some-ele").click = obj.handler;

如果在handler中用了this,this会绑定在obj上么?显然不是,赋值以后,函数是在回调中执行的,this会绑定到$(“#some-div”)元素上。这就需要理解函数的执行环境。本文不打算长篇赘述函数的执行环境,可以参考《javascript高级程序设计》中对执行环境和作用域链的相关介绍。这里要指出的时,理解js函数的执行环境,会更好地理解this。

那我们如何能解决回调函数绑定的问题?ES5中引入了一个新的方法,bind():

fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg
当绑定函数被调用时,该参数会作为原函数运行时的this指向.当使用new 操作符调用绑定函数时,该参数无效.
arg1, arg2, ...
当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数.

该方法创建一个新函数,称为绑定函数,绑定函数会以创建它时传入bind方法的第一个参数作为this,传入bind方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数.

显然bind方法可以很好地解决上述问题。

$("#some-ele").click(person.hello.bind(person));
//相应元素被点击时,输出foocoder says hello world
其实该方法也很容易模拟,我们看下Prototype.js中bind方法的源码:
Function.prototype.bind = function(){
  var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift();
  return function(){
    return fn.apply(object,
      args.concat(Array.prototype.slice.call(arguments)));
  };
};

明白了么?

相信看完全文以后,this不再是坑~

via http://foocoder.com/blog/xiang-jie-javascriptzhong-de-this.html/ 

Linux:成人网站性能提升20倍之经验谈

色情业是个大行业。互联网上没有多少网站的流量能和最大的色情网站相匹敌。

要搞定这巨大的流量很难。更困难的是,在色情网站上提供的很多内容都是低延迟的实时流媒体而不是简单的静态视频。但是对于所有碰到过的挑战,我很少看到有搞定过它们的开发人员写的东西。所以我决定把自己在这方面的经验写出来。

问题是什么?

几年前,我正在为当时全世界访问量排名26的网站工作 — 这里不是说的色情网站排名,而是全世界排名。

当时,该网站通过RTMP(Real Time Messaging protocol)协议响应对色情流媒体的请求。更具体地说,它使用了Adobe的FMS(Flash Media Server)技术为用户提供实时流媒体。基本过程是这样的:

  1. 用户请求访问某个实时流媒体
  2. 服务器通过一个RTMP session响应,播放请求的视频片段

因为某些原因,FMS对我们并不是一个好的选择,首先是它的成本,包括了购买以下两者:

  1. 为每一台运行FMS的服务器购买Windows的版权
  2. 大约4000美元一个的FMS特定版权,由于我们的规模,我们必须购买的版权量数以百计,而且每天都在增加。

所有这些费用开始不断累积。撇开成本不提,FMS也是一个比较挫的产品,特别是在它的功能方面(我过一会再详细说这个问题)。所以我决定抛弃FMS,自己从头开始写一个自己的RTMP解析器。

最后,我终于把我们的服务效率提升了大约20倍。

开始

这里涉及到两个核心问题:首先,RTMP和其他的Adobe协议及格式都不是开放的,这就很难使用它们。要是对文件格式都一无所知,你如何能对它进行反向工程或者解析它呢?幸运的是,有一些反向工程的尝试已经在公开领域出现了(并不是Adobe出品的,而是osflash.org,它破解了一些协议),我们的工作就是基于这些成果。

注:Adobe后来发布了所谓的“规格说明书”,比起在非Adobe提供的反向工程wiki和文档中披露的内容,这个说明书里也没有啥新东西。他们给的规格说明书的质量之低劣达到了荒谬的境地,近乎不可能通过该说明书来使用它们的库。而且,协议本身看起来常常也是有意做成具有误导性的。例如:

  1. 他们使用29字节的整形数。
  2. 他们在协议头上所有地方都采用低地址存放最高有效字节(big endian)的格式,除了在某一个字段(而且未标明)上采用低地址存放最低有效字节(little endian)的格式。
  3. 他们在传输9K的视频时,不惜耗费计算能力去压缩数据减少空间,这基本上是没意义的,因为他们这么折腾一次也就是减少几位或几个字节,对这样的一个文件大小可以忽略不计了。

还有,RTMP是高度以session为导向的,这使得它基本上不可能对流进行组播。理想状态下,如果多个用户要求观看同一个实时视频流,我们可以直接向他们传回指向单个session的指针,在该session里传输这个视频流(这就是组播的概念)。但是用RTMP的话,我们必须为每一个要求访问特定流的用户创建全新的一个实例。这是完全的浪费。

 

我的解决办法

想到了这些,我决定把典型的响应流重新打包和解析为FLV“标签”(这里的“标签”指某个视频、音频或者元数据)。这些FLV标签可以在RTMP下顺利地传输。

这样一个方法的好处是:

  • 我们只需要给流重新打包一次(重新打包是一个噩梦,因为缺少规格说明,还有前面说到的恶心协议)。
  • 通过套用一个FLV头,我们可以在客户端之间顺畅地重用任何流,而用内部的FLV标签指针(配以某种声明其在流内部确切位置的位移值)就可以访问到真正的内容。

我一开始用我当时最熟悉的C语言进行开发。一段时间后,这个选择变得麻烦了,所以我开始学习Python并移植我的C代码。开发过程加快了,但在做了一些演示版本后,我很快遇到了资源枯竭的问题。Python的socket处理并不适合处理这些类型的情况,具体说,我们发现在自己的Python代码里,每个action都进行了多次系统调用和context切换,这增加了巨大的系统开销。

改进性能:混合使用Python和C

在对代码进行梳理之后,我选择将性能最关键的函数移植到内部完全用C语言编写的一个Python模块中。这基本是底层的东西,具体地说,它利用了内核的epoll机制提供了一个O(log n)的算法复杂度。

在异步socket编程方面,有一些机制可以提供有关特定socket是否可读/可写/出错之类的信息。过去,开发人员们可以用select()系统调用获取这些信息,但很难大规模使用。Poll()是更好的选择,但它仍然不够好,因为你每次调用的时候都要传递一大堆socket描述符。

Epoll的神奇之处在于你只需要登记一个socket,系统会记住这个特定的socket并处理所有内部的杂乱的细节。这样在每次调用的时候就没有传递参数的开销了。而且它适用的规模也大有可观,它只返回你关心的那些socket,相比用其他技术时必须从10万个socket描述符列表里挨个检查是否有带字节掩码的事件,其优越性真是非同小可啊。

不过,为了性能的提高,我们也付出了代价:这个方法采用了完全和以前不同的设计模式。该网站以前的方法是(如果我没记错的话)单个原始进程,在接收和发送时会阻塞。我开发的是一套事件驱动方案,所以为了适应这个新模型,我必须重构其他的代码。

具体地说,在新方法中,我们有一个主循环,它按如下方式处理接收和发送:

  1. 接收到的数据(作为消息)被传递到RTMP层
  2. RTMP包被解析,从中提取出FLV标签
  3. FLV数据被传输到缓存和组播层,在该层对流进行组织并填充到底层传输缓存中
  4. 发送程序为每个客户端保存一个结构,包含了最后一次发送的索引,并尽可能多地向客户端传送数据

这是一个滚动的数据窗口,并包含了某些试探性算法,当客户端速度太慢无法接收时会丢弃一些帧。总体来说运行的很好。

 

系统层级,架构和硬件问题

但是我们又遇到另外一个问题:内核的context切换成为了一个负担。结果,我们选择每100毫秒发送一次而不是实时发送。这样可以把小的数据包汇总起来,也避免了context切换的爆炸式出现。

也许更大的一个问题在于服务器架构方面:我们需要一个具备负载均衡和容错能力的服务器集群,毕竟因为服务器功能异常而失去用户不是件好玩的事情。一开始,我们采用了专职总管服务器的方法,它指定一个”总管“负责通过预测需求来产生和消除播放流。这个方法华丽丽地失败了。实际上,我们尝试过的每个方法都相当明显地失败了。最后,我们采用了一个相对暴力的方法,在集群的各个节点之间随机地共享播放的流,使流量基本平衡了。

这个方法是有效的,但是也有一些不足:虽然一般情况下它处理的很好,我们也碰到了当所有网站用户(或者相当大比例的用户)观看单个广播流的时候,性能会变得非常糟糕。好消息是,除了一次市场宣传活动(marketing campaign)之外,这种情况再也没出现过。我们部署了另外一套单独的集群来处理这种情况,但真实的情况是我们先分析了一番,觉得为了一次市场活动而牺牲付费用户的体验是说不过去的,实际上,这个案例也不是一个真实的事件(虽然说能处理所有想象得到的情况也是很好的)。

 

结论

这里有最后结果的一些统计数字:每天在集群里的流量在峰值时是大约10万用户(60%负载),平均是5万。我管理了2个集群(匈牙利和美国),每个里有大约40台服务器共同承担这个负载。这些集群的总带宽大约是50 Gbps,在负载达到峰值时大约使用了10 Gbps。最后,我努力做到了让每台服务器轻松地能提供10 Gbps带宽,也就等于一台服务器可以承受30万用户同时观看视频流。

已有的FMS集群包含了超过200台服务器,我只需要15台就可以取代他们,而且其中只有10台在真正提供服务。这就等于200除以10,等于20倍的性能提高。大概我在这个项目里最大的收获就是我不应让自己受阻于学习新技能的困难。具体说来,Python、转码、面向对象编程,这些都是我在做这个项目之前缺少专业经验的概念。

这个信念,以及实现你自己的方案的信心,会给你带来很大的回报。

【1】后来,当我们把新代码投入生产,我们又遇到了硬件问题,因为我们使用老的sr2500 Intel架构服务器,由于它们的PCI总线带宽太低,不能支持10 Gbit的以太网卡。没辙,我们只好把它们用在1-4×1 Gbit的以太网池中(把多个网卡的性能汇总为一个虚拟网卡)。最终,我们获得了一些更新的sr2600 i7 Intel架构服务器,它们通过光纤达到了无性能损耗的10 Gbps带宽。所有上述汇总的结果都是基于这样的硬件条件来计算的。

 

英文原文:GERGELY KALMAN,编译:@老码农的自留地

译文链接:http://blog.jobbole.com/39323/

Linux:优秀的开源系统恢复软件

  Linux等操作系统都有不错的工具可帮助恢复有价值的数据,但如果系统都无法启动,很多数据恢复工具可能就没有用武之地了。

  系统无法启动的原因可能是启动引导程序损坏,分区损坏,或者说重要的系统文件丢失,甚至可能是登录密码忘记了。在这种情况下,开源软件提供了大量解决方案,有专门的Linux发行版提供了许多有用的系统管理软件和数据恢复工具,如:

来自:http://www.solidot.org/story?sid=34389

Linux:使用 Zsh 的九个理由

像大部分 *nix 用户,我之前用 bash 很多年,期间也有过小的不爽,但一直都忍过来,或者是说没想过这些不爽的地方能解决,比如 cd 到一个深目录时得哐哐猛敲 。这么多年里我也尝试过其他 shell。比如 ksh/tcsh 以及今天要说的 zsh,但最终都没坚持下去,因为心中始终还是认为 bash 是最正统的 shell,不愿意去主动深入学习其他 shell。直到前几天逛 GitHub,发现 排名第 6 的开源项目 oh-my-zsh,下来试用了一把,顿时觉得 bash 各种操作不爽到无法忍受。

放弃 bash 的各种内牛满面的理由

这里有个 youtube 上的视频,短短 4 分钟就已经抛出了几十个让 bash 用户切换到 zsh 中的理由。视频链接

 

理由 0:zsh 兼容 bash

兼容 bash 意味着我不需要太多学习成本就可以切换过来,意味着我以前在 bash 下积累的 shell 语法、基本操作都不会荒废。在我心里 bash 还是最通用和标准的 shell 环境,因此兼容 bash 让我切换到 zsh 时没有太多后顾之忧。

 

理由 1:zsh 的补全模式更方便

zsh 中按两下 tab 键可以触发 zsh 的补全,所有待补全项都可以通过键盘方向键或者  来选择。

nine reasons to use zsh

 

理由 2:zsh 支持命令选项补全

zsh 除了支持目录的补全,还支持命令选项的补全,例如 ls – 会直接列出所有 ls 的参数,再也不会出现一个命令打到一半,忘记参数导致重开一个 terminal man 一把。

nine reasons to use zsh

 

 

理由 3:zsh 支持命令参数补全

以前想 kill 掉一个进程,我的做法是 ps aux | grep “进程名” 然后记下 id,再 kill id。在 zsh 下,只需要 kill 进程名,zsh 就会自动补全进程的 pid。

nine reasons to use zsh

其余我常用的补全还有:

·ssh  时 zsh 会自动列出你访问过的主机和用户名来补全 ssh 的参数。·brew install  来补全软件包名,除了 homebrew 以外,同样支持 port/apt-get 等其他包管理器。

 

理由 4:zsh 支持更加聪明的目录补全

以前比如想进入一个比较深的目录,比如 /Users/pw/workspace/project/src/main/webapps/static/js,就得在 bash 下面打半天,不停的 tab 去补全一个正确的路径出来。在 zsh 下,只需要输入每个路径的头字母然后 tab 一下: cd /u/p/w/p/s/m/w/s/j

 

理由 5:zsh 强大的快速目录切换

以前最苦逼的事情莫过于频繁在两个工作目录下切换,总要打一长串 cd 路径。也尝试过 popd 和 pushd 来解决这个问题,但往往是目录已经切换了才想起来没用 pushd。而 zsh 会记住你每一次切换的路径,然后通过 1 来切换到你上一次访问的路径,2 切换到上上次……一直到 9,还可以通过 d 查看目录访问历史。

zsh 还可以配合 autojump 一起使用,autojump 会记录下每一个你访问过的目录,然后通过 j 来快速跳转。

 

理由 6:zsh 支持全局 alias 和后缀名 alias

bash 的 alias 只能做命令的缩写,而 zsh 更进一步,使 alias 可以缩写命令的一部分,例如参数或环境变量设置。

$ alias -s log=less
$ ~/package/tomcat/log/catalina.log # 相当于 less ~/package/tomcat/log/catalina.log
$ alias -g PR=http_proxy=127.0.0.1:8087
$ PR curl https://twitter.com # 相当于 http_proxy=127.0.0.1:8087 curl https://twitter.com

 

理由 7:zsh 有着丰富多彩的命令行提示符

bash 下通过设置 $PS1 已经可以实现很丰富的提示符了,而 zsh 更进一步,可以实现诸如多行提示符、提示符右对齐等功能。oh-my-zsh 配置文件中提供了非常丰富的提示符 theme 供选择,我使用的是 gentoo 主题,比较简洁,还可以显示当前 git 仓库的状态。

 

理由 8:zsh 有更多优雅的语法

例如修改 PATH,bash 下设置 $PATH 要求所有路径都要写在一行里,目录多了以后看起来就很难看。zsh 支持更加符合程序员审美观的设置方式。

path=(
    ~/bin
    $path
    ~/package/smartsprites/bin
)

 

安装 zsh

Linux 用户通过各自发行版的包管理器直接安装即可。

Mac 自带一个 4.x.x 版本的 zsh,可以直接使用,也可以通过 homebrew 安装最近刚刚发布的 5.0.0 版本。推荐使用最新的 5.0 版本,对多字节字符提供了完整的支持,这一点对于国内用户来说很重要。详细的 release note

 

设置为默认 shell

通过命令 chsh 修改默认登录 shell,需要注意的是,如果通过 homebrew 安装了最新版本的 zsh,则需要 sudo 编辑 /etc/shells 加入一行 /usr/local/bin/zsh。然后再通过 chsh 来修改默认 shell,否则会提示 /usr/local/bin/zsh 不是合法的 shell。

 

安装 oh-my-zsh 配置

对于每一个像我这样的 zsh 初级用户来说,oh-my-zsh 就是救人于水火中的大杀器,强烈建议使用此配置上手 zsh。

作者提供了傻瓜安装命令:

curl -L https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh | sh 

也可以手工安装,具体步骤

 

几个必备的插件

autojump

帮助快速目录跳转的小工具。首先要安装 autojump,然后在 .zshrc 中开启 autojump 插件。它会记录下来每个你进入过的目录,随后通过 j 目录名称的一部分就可快速跳转到该目录。 Youtube 视频介绍

git

Git 命令补全,除了可以补全 git 的子命令、命令开关等常规补全项以外,还可以补全分支名等内容,用 git 必开的插件。

osx

提供一些与 Mac OSX 系统交互的命令,比如:

● man-preview 通过 preview 程序查看一个命令的手册,例如 man-preview git

● quick-look 快速预览文件

● pfd 返回当前 finder 打开的文件夹的路径

● cdf 切换到当前 finder 所在的目录

原文:perfectworks 

via http://blog.jobbole.com/28829/

Linux:为重负网络优化 Nginx 和 Node.js

在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对。他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器的C10K瓶颈。预设的配置已经可以获得很高的并发,不过,要是大家想在廉价硬件上做到每秒数千以上的请求,还是有一些工作要做的。

这篇文章假定读者们使用NginX的HttpProxyModule来为上游的node.js服务器充当反向代理。我们将介绍Ubuntu 10.04以上系统sysctl的调优,以及node.js应用与NginX的调优。当然,如果大家用的是Debian系统,也能达到同样的目标,只不过调优的方法有所不同而已。

网络调优

如果不先对Nginx和Node.js的底层传输机制有所了解,并进行针对性优化,可能对两者再细致的调优也会徒劳无功。一般情况下,Nginx通过TCP socket来连接客户端与上游应用。

我们的系统对TCP有许多门限值与限制,通过内核参数来设定。这些参数的默认值往往是为一般的用途而定的,并不能满足web服务器所需的高流量、短生命的要求。

这里列出了调优TCP可供候选的一些参数。为使它们生效,可以将它们放在/etc/sysctl.conf文件里,或者放入一个新配置文件,比如/etc/sysctl.d/99-tuning.conf,然后运行sysctl -p,让内核装载它们。我们是用sysctl-cookbook来干这个体力活。

需要注意的是,这里列出来的值是可以安全使用的,但还是建议大家研究一下每个参数的含义,以便根据自己的负荷、硬件和使用情况选择一个更加合适的值。

net.ipv4.ip_local_port_range='1024 65000'
net.ipv4.tcp_tw_reuse='1'
net.ipv4.tcp_fin_timeout='15'
net.core.netdev_max_backlog='4096'
net.core.rmem_max='16777216'
net.core.somaxconn='4096'
net.core.wmem_max='16777216'
net.ipv4.tcp_max_syn_backlog='20480'
net.ipv4.tcp_max_tw_buckets='400000'
net.ipv4.tcp_no_metrics_save='1'
net.ipv4.tcp_rmem='4096 87380 16777216'
net.ipv4.tcp_syn_retries='2'
net.ipv4.tcp_synack_retries='2'
net.ipv4.tcp_wmem='4096 65536 16777216'
vm.min_free_kbytes='65536'

重点说明其中几个重要的。

net.ipv4.ip_local_port_range

为了替上游的应用服务下游的客户端,NginX必须打开两条TCP连接,一条连接客户端,一条连接应用。在服务器收到很多连接时,系统的可用端口将很快被耗尽。通过修改net.ipv4.ip_local_port_range参数,可以将可用端口的范围改大。如果在/var/log/syslog中发现有这样的错误: “possible SYN flooding on port 80. Sending cookies”,即表明系统找不到可用端口。增大net.ipv4.ip_local_port_range参数可以减少这个错误。

net.ipv4.tcp_tw_reuse

当服务器需要在大量TCP连接之间切换时,会产生大量处于TIME_WAIT状态的连接。TIME_WAIT意味着连接本身是关闭的,但资源还没有释放。将net_ipv4_tcp_tw_reuse设置为1是让内核在安全时尽量回收连接,这比重新建立新连接要便宜得多。

net.ipv4.tcp_fin_timeout

这是处于TIME_WAIT状态的连接在回收前必须等待的最小时间。改小它可以加快回收。

如何检查连接状态

使用netstat:

netstat -tan | awk ‘{print $6}’ | sort | uniq -c

或使用ss:

ss -s

NginX

随着web服务器的负载逐渐升高,我们就会开始遭遇NginX的某些奇怪限制。连接被丢弃,内核不停报SYN flood。而这时,平均负荷和CPU使用率都很小,服务器明明是可以处理更多连接的状态,真令人沮丧。

经过调查,发现有非常多处于TIME_WAIT状态的连接。这是其中一个服务器的输出:

ss -s
Total: 388 (kernel 541)
TCP:   47461 (estab 311, closed 47135, orphaned 4, synrecv 0, timewait 47135/0), ports 33938
Transport Total     IP        IPv6
*          541       -         -
RAW        0         0         0
UDP        13        10        3
TCP        326       325       1
INET       339       335       4
FRAG       0         0         0

有47135个TIME_WAIT连接!而且,从ss可以看出,它们都是已经关闭的连接。这说明,服务器已经消耗了绝大部分可用端口,同时也暗示我们,服务器是为每个连接都分配了新端口。调优网络对这个问题有一点帮助,但是端口仍然不够用。

经过继续研究,我找到了一个关于上行连接keepalive指令的文档,它写道:

设置通往上游服务器的最大空闲保活连接数,这些连接会被保留在工作进程的缓存中。

有趣。理论上,这个设置是通过在缓存的连接上传递请求来尽可能减少连接的浪费。文档中还提到,我们应该把proxy_http_version设为”1.1″,并清除”Connection”头部。经过进一步的研究,我发现这是一种很好的想法,因为HTTP/1.1相比HTTP1.0,大大优化了TCP连接的使用率,而Nginx默认用的是HTTP/1.0。

按文档的建议修改后,我们的上行配置文件变成这样:

upstream backend_nodejs {
  server nodejs-3:5016 max_fails=0 fail_timeout=10s;
  server nodejs-4:5016 max_fails=0 fail_timeout=10s;
  server nodejs-5:5016 max_fails=0 fail_timeout=10s;
  server nodejs-6:5016 max_fails=0 fail_timeout=10s;
  keepalive 512;
}

我还按它的建议修改了server一节的proxy设置。同时,加了一个 p roxy_next_upstream来跳过故障的服务器,调整了客户端的 keepalive_timeout,并关闭访问日志。配置变成这样:

server {
  listen 80;
  server_name fast.gosquared.com;
  client_max_body_size 16M;
  keepalive_timeout 10;
  location / {
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
    proxy_set_header   Connection "";
    proxy_http_version 1.1;
    proxy_pass http://backend_nodejs;
  }
  access_log off;
  error_log /dev/null crit;
}

采用新的配置后,我发现服务器们占用的socket 降低了90%。现在可以用少得多的连接来传输请求了。新的输出如下:

ss -s
Total: 558 (kernel 604)
TCP:   4675 (estab 485, closed 4183, orphaned 0, synrecv 0, timewait 4183/0), ports 2768
Transport Total     IP        IPv6
*          604       -         -
RAW        0         0         0
UDP        13        10        3
TCP        492       491       1
INET       505       501       4

Node.js

得益于事件驱动式设计可以异步处理I/O,Node.js开箱即可处理大量的连接和请求。虽然有其它一些调优手段,但这篇文章将主要关注node.js的进程方面。

Node是单线程的,不会自动使用多核。也就是说,应用不能自动获得服务器的全部能力。

实现Node进程的集群化

我们可以修改应用,让它fork多个线程,在同一个端口上接收数据,从而实现负载的跨越多核。Node有一个cluster模块,提供了实现这个目标所必需的所有工具,但要将它们加入应用中还需要很多体力活。如果你用的是express,eBay有一个叫cluster2的模块可以用。

防止上下文切换

当运行多个进程时,应该确保每个CPU核同一时间只忙于一个进程。一般来说,如果CPU有N个核,我们应该生成N-1个应用进程。这样可以确保每个进程都能得到合理的时间片,而剩下的一个核留给内核调度程序运行其它任务。我们还要确保服务器上基本不执行除Node.js外的其它任务,防止出现CPU的争用。

我们曾经犯过一个错误,在服务器上部署了两个node.js应用,然后每个应用都开了N-1个进程。结果,它们互相之间抢夺CPU,导致系统的负荷急升。虽然我们的服务器都是8核的机器,但仍然可以明显地感觉到由上下文切换引起的性能开销。上下文切换是指CPU为了执行其它任务而挂起当前任务的现象。在切换时,内核必须挂起当前进程的所有状态,然后装载和执行另一个进程。为了解决这个问题,我们减少了每个应用开启的进程数,让它们公平地分享CPU,结果系统负荷就降了下来:

为重负网络优化 Nginx 和 Node.js

请注意上图,看系统负荷(蓝线)是如何降到CPU核数(红线)以下的。在其它服务器上,我们也看到了同样的情况。既然总的工作量保持不变,那么上图中的性能改善只能归功于上下文切换的减少。

链接和参考

● 10 Vital Aspects of building a Node.JS application

● Using NginX to avoid node.js load

● Commands to analyse system socket usage

● TCP/IP setting reference

● Linux kernel tuning 

英文原文:Optimising NginX, Node.JS and networking for heavy workloads,编译:AlfredCheung