Jsoup获取全国地区数据(省市县镇村)

最近手头在做一些东西,需要一个全国各地的地域数据,从省市区到县镇乡街道的。各种度娘,各种谷歌,都没找到一个完整的数据。最后功夫不负有心人,总算找到一份相对来说比较完整的数据,但是这里的数据也只是精确到镇级别,没有村一级的数据(后来通过分析数据源我知道了为什么,呵呵),在加上博主提供的有些数据存在冗余,对于有强迫症和追求完美的我,心想着我一定要自己动手去把这部分数据给爬取出来。

上述博文中的内容还算丰富,博主是用的是php来实现的,作为2015年度编程语言排行榜的第一位,我们也不能示弱啊,下面我就带着大家一起来看看用java怎么从网页当中爬取我们想要的数据…

第一步、准备工作(数据源+工具):

数据源(截止目前最全面权威的官方数据):http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/

爬取数据的工具(爬虫工具):http://jsoup.org/

第二、数据源分析:

首先jsoup工具的使用我在这里就不做讲解了,感兴趣的可以自己动手去查阅。

做开发就应该多去了解一些软件工具的使用,在平常开发过程中遇到了才知道从何下手,鼓励大家多平时留意一些身边的软件工具,以备不时之需。在做这个东西以前,我也不知道jsoup要怎么用,但我知道jsoup可以用来干嘛,在我需要的用到的时候,再去查阅资料,自己学习。

 

上述的数据源是2013年中华人民共和国国家统计局发布的,其准确性和权威性不言而喻。

接下来我们分析一下数据源的结构,先从首页说起:   

通过分析首页源码我们可以得到如下3点:

  1. 页面的整个布局是用的table标签来控制的,也就是说我们如果要通过jsoup来选择超链接,那么一定要注意,上图中不是只要标注了省市地区的地方采用的才是表格,整个页面中存在多个表格,因此是不可以直接通过表格
    Document connect = connect("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/");
    Elements rowProvince = connect.select("table");

    来解析数据的。

  2. 页面中有超链接的部分有多少地方。可能是官方考虑到了你们这种程序员需要获取这样的数据的原因吧,页面很干净,除开下方的备案号是多余的超链接,其他的链接可以直接爬取。
  3. 省份城市的数据规律。包含有效信息的表格的每一行都有一个class属性provincetr,这个属性很重要,至于为什么重要,请接着往下看;每一行数据中存在多个td标签,每一个td标签中包含一个a超链接,而这个超链接正是我们想要的超链接,超链接的文本即使省份(直辖市等)的名称。

 

再次我们再看一下一般的数据页面(一般的数据页面包括市级、县级、镇级这三级数据展示页面):

之所以要把上述三个页面放在一起,是因为通过分析我们可以发现,这三级数据的数据页面完全一致,唯一不同的就是在html源码数据表格中的数据行tr的class属性不一致,分别对应为:citytr,countrytrhe towntr。其他均一致。这样我们就可以用一个通用的方法解决这三个页面的数据爬取。  

 

最后看看村一级的数据页面:   

在村一级的数据中,和上述市县镇的数据格式不一致,这一级所表示的数据是最低一级的,所以不存在a链接,因此不能采用上面市县镇数据的爬取方式去爬取;这里展示数据的表格行的class为villagetr,除开这两点以外,在每一行数据中包含三列数据,第一列是citycode,第二列是城乡分类(市县镇的数据格式不存在这一项),第三列是城市名称。

把握了以上各个要点之外,我们就可以开始编码了。

第三步、编码实现:

复制代码
  1 import java.io.BufferedWriter;
  2 import java.io.File;
  3 import java.io.FileWriter;
  4 import java.io.IOException;
  5 import java.util.HashMap;
  6 import java.util.Map;
  7 
  8 import org.jsoup.Jsoup;
  9 import org.jsoup.nodes.Document;
 10 import org.jsoup.nodes.Element;
 11 import org.jsoup.select.Elements;
 12 
 13 /**
 14  * 全国省市县镇村数据爬取
 15  * @author liushaofeng
 16  * @date 2015-10-11 上午12:19:39
 17  * @version 1.0.0
 18  */
 19 public class JsoupTest
 20 {
 21     private static Map<Integer, String> cssMap = new HashMap<Integer, String>();
 22     private static BufferedWriter bufferedWriter = null;
 23 
 24     static
 25     {
 26         cssMap.put(1, "provincetr");// 省
 27         cssMap.put(2, "citytr");// 市
 28         cssMap.put(3, "countytr");// 县
 29         cssMap.put(4, "towntr");// 镇
 30         cssMap.put(5, "villagetr");// 村
 31     }
 32 
 33     public static void main(String[] args) throws IOException
 34     {
 35         int level = 1;
 36 
 37         initFile();
 38 
 39         // 获取全国各个省级信息
 40         Document connect = connect("http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2013/");
 41         Elements rowProvince = connect.select("tr." + cssMap.get(level));
 42         for (Element provinceElement : rowProvince)// 遍历每一行的省份城市
 43         {
 44             Elements select = provinceElement.select("a");
 45             for (Element province : select)// 每一个省份(四川省)
 46             {
 47                 parseNextLevel(province, level + 1);
 48             }
 49         }
 50 
 51         closeStream();
 52     }
 53 
 54     private static void initFile()
 55     {
 56         try
 57         {
 58             bufferedWriter = new BufferedWriter(new FileWriter(new File("d:\\CityInfo.txt"), true));
 59         } catch (IOException e)
 60         {
 61             e.printStackTrace();
 62         }
 63     }
 64 
 65     private static void closeStream()
 66     {
 67         if (bufferedWriter != null)
 68         {
 69             try
 70             {
 71                 bufferedWriter.close();
 72             } catch (IOException e)
 73             {
 74                 e.printStackTrace();
 75             }
 76             bufferedWriter = null;
 77         }
 78     }
 79 
 80     private static void parseNextLevel(Element parentElement, int level) throws IOException
 81     {
 82         try
 83         {
 84             Thread.sleep(500);//睡眠一下,否则可能出现各种错误状态码
 85         } catch (InterruptedException e)
 86         {
 87             e.printStackTrace();
 88         }
 89 
 90         Document doc = connect(parentElement.attr("abs:href"));
 91         if (doc != null)
 92         {
 93             Elements newsHeadlines = doc.select("tr." + cssMap.get(level));//
 94             // 获取表格的一行数据
 95             for (Element element : newsHeadlines)
 96             {
 97                 printInfo(element, level + 1);
 98                 Elements select = element.select("a");// 在递归调用的时候,这里是判断是否是村一级的数据,村一级的数据没有a标签
 99                 if (select.size() != 0)
100                 {
101                     parseNextLevel(select.last(), level + 1);
102                 }
103             }
104         }
105     }
106 
107     /**
108      * 写一行数据到数据文件中去
109      * @param element 爬取到的数据元素
110      * @param level 城市级别
111      */
112     private static void printInfo(Element element, int level)
113     {
114         try
115         {
116             bufferedWriter.write(element.select("td").last().text() + "{" + level + "}["
117                 + element.select("td").first().text() + "]");
118             bufferedWriter.newLine();
119             bufferedWriter.flush();
120         } catch (IOException e)
121         {
122             e.printStackTrace();
123         }
124     }
125 
126     private static Document connect(String url)
127     {
128         if (url == null || url.isEmpty())
129         {
130             throw new IllegalArgumentException("The input url('" + url + "') is invalid!");
131         }
132         try
133         {
134             return Jsoup.connect(url).timeout(100 * 1000).get();
135         } catch (IOException e)
136         {
137             e.printStackTrace();
138             return null;
139         }
140     }
141 }
复制代码
数据爬取过程便是一个漫长的过程,只需要慢慢等待吧,呵呵,由于程序运行时间较长,请不要在控制台打印输出,否则可能会影响程序运行....

最终获取到数据的格式如下(”{}”中表示城市级别,”[]”中内容表示城市编码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
市辖区{3}[110100000000]
东城区{4}[110101000000]
东华门街道办事处{5}[110101001000]
多福巷社区居委会{6}[110101001001]
银闸社区居委会{6}[110101001002]
东厂社区居委会{6}[110101001005]
智德社区居委会{6}[110101001006]
南池子社区居委会{6}[110101001007]
黄图岗社区居委会{6}[110101001008]
灯市口社区居委会{6}[110101001009]
正义路社区居委会{6}[110101001010]
甘雨社区居委会{6}[110101001011]
台基厂社区居委会{6}[110101001013]
韶九社区居委会{6}[110101001014]
王府井社区居委会{6}[110101001015]
景山街道办事处{5}[110101002000]
隆福寺社区居委会{6}[110101002001]
吉祥社区居委会{6}[110101002002]
黄化门社区居委会{6}[110101002003]
钟鼓社区居委会{6}[110101002004]
魏家社区居委会{6}[110101002005]
汪芝麻社区居委会{6}[110101002006]
景山东街社区居委会{6}[110101002008]
皇城根北街社区居委会{6}[110101002009]
交道口街道办事处{5}[110101003000]
交东社区居委会{6}[110101003001]
福祥社区居委会{6}[110101003002]
大兴社区居委会{6}[110101003003]
府学社区居委会{6}[110101003005]
鼓楼苑社区居委会{6}[110101003007]
菊儿社区居委会{6}[110101003008]
南锣鼓巷社区居委会{6}[110101003009]
安定门街道办事处{5}[110101004000]
交北头条社区居委会{6}[110101004001]
北锣鼓巷社区居委会{6}[110101004002]
国子监社区居委会{6}[110101004003]
......

拿到以上数据以后,自己想干什么都可以自我去实现了,以上的代码可以直接运行,从数据源爬取后,可以直接转换成自己所要的格式。

后续处理的最终结果,请参见博文:http://www.cnblogs.com/liushaofeng89/p/4937714.html

 

如果你觉得本博文对你有所帮助,请记得点击右下方的”推荐”哦,么么哒…

转载请注明出处:http://www.cnblogs.com/liushaofeng89/p/4873086.html

Redis系列-存储篇set主要操作函数小结

最近,总是以“太忙“为借口,很久没有blog了,凡事贵在恒,希望我能够坚持不懈,毕竟在blog的时候,也能提升自己。废话不说了,直奔主题”set“

redis set 是string类型对象的无序集合,set不管存储多少对象,对存储对象的add,remove和test操作的时间复杂度是O(1)。set最多能包含 232 – 1 个member。

1、增加

语法:sadd key member[member…]

解释:对特定key的set增加一个或多个值,返回是增加元素的个数。注意:对同一个member多次add,set中只会保留一份。

  1. [root@xsf001 ~]# redis-cli
  2. redis 127.0.0.1:6379> sadd stu zhangsan lisi wangwu #新增
  3. (integer) 3
  4. redis 127.0.0.1:6379> smembers stu    #得到set的所有member
  5. 1) “wangwu”
  6. 2) “lisi”
  7. 3) “zhangsan”
  8. redis 127.0.0.1:6379> sadd stu zhangsan #增加存在的member
  9. (integer) 0
  10. redis 127.0.0.1:6379> smembers stu
  11. 1) “wangwu”
  12. 2) “lisi”
  13. 3) “zhangsan”
  14. redis 127.0.0.1:6379> sadd tech wangwu liming joe
  15. (integer) 3
  16. redis 127.0.0.1:6379> sadd tech jim
  17. (integer) 1
  18. redis 127.0.0.1:6379> smembers tech
  19. 1) “jim”
  20. 2) “liming”
  21. 3) “wangwu”
  22. 4) “joe”

2、查询

a)smembers

语法:smembers key

解释:获取set中的所有member

  1. redis 127.0.0.1:6379> smembers stu
  2. 1) “wangwu”
  3. 2) “lisi”
  4. 3) “zhangsan”
  5. redis 127.0.0.1:6379> smembers tech
  6. 1) “jim”
  7. 2) “liming”
  8. 3) “wangwu”
  9. 4) “joe”

b)sismember

语法:sismember key member

解释:判断值是否是set的member。如果值是set的member返回1,否则,返回0

  1. redis 127.0.0.1:6379> sismember tech jim #jim 是set的member
  2. (integer) 1
  3. redis 127.0.0.1:6379> sismember tech jim001 #jim001 不是set的member
  4. (integer) 0

c)scard

语法:scard key

解释:返回set的member个数,如果set不存在,返回0

  1. redis 127.0.0.1:6379> scard tech  # tech 存在
  2. (integer) 4
  3. redis 127.0.0.1:6379> scard stud #stud 不存在
  4. (integer) 0
  5. redis 127.0.0.1:6379> scard stu
  6. (integer) 4

d)srandmember

语法:srandmember key

解释:从set中返回一个随机member

  1. redis 127.0.0.1:6379> srandmember stu
  2. “zhangsan”
  3. redis 127.0.0.1:6379> srandmember stu
  4. “zhangsan”
  5. redis 127.0.0.1:6379> srandmember stu
  6. “wangwu”
  7. redis 127.0.0.1:6379> srandmember stu
  8. “zhangsan01”

3、删除

a)spop

语法:spop key

解释:移除并返回一个随机member

  1. redis 127.0.0.1:6379> smembers stu #pop前
  2. 1) “zhangsan01”
  3. 2) “wangwu”
  4. 3) “lisi”
  5. 4) “zhangsan”
  6. redis 127.0.0.1:6379> spop stu  #移除一个随机member
  7. “lisi”
  8. redis 127.0.0.1:6379> smembers stu #pop后
  9. 1) “zhangsan01″<span style=”white-space:pre”>   </span>
  10. 2) “wangwu”
  11. 3) “zhangsan”

b)srem

语法:srem key member [member …]

解释:移除一个或多个member

  1. redis 127.0.0.1:6379> smembers tech
  2. 1) “jim”
  3. 2) “liming”
  4. 3) “wangwu”
  5. 4) “joe”
  6. redis 127.0.0.1:6379> srem tech jim   #移除jim
  7. (integer) 1
  8. redis 127.0.0.1:6379> smembers tech
  9. 1) “liming”
  10. 2) “wangwu”
  11. 3) “joe”
  12. redis 127.0.0.1:6379> srem tech liming joe #移除多个member
  13. (integer) 2
  14. redis 127.0.0.1:6379> smembers tech
  15. 1) “wangwu”

c)smove

语法:smove source destination member

解释:将source中的member移动到destination

  1. redis 127.0.0.1:6379> smembers tech   #smove前
  2. 1) “wangwu”
  3. redis 127.0.0.1:6379> smembers stu
  4. 1) “zhangsan01”
  5. 2) “wangwu”
  6. 3) “zhangsan”
  7. redis 127.0.0.1:6379> smove stu tech zhangsan  #将zhangsan 从stu移动到tech
  8. (integer) 1
  9. redis 127.0.0.1:6379> smembers stu #smove后
  10. 1) “zhangsan01”
  11. 2) “wangwu”
  12. redis 127.0.0.1:6379> smembers tech
  13. 1) “wangwu”
  14. 2) “zhangsan”

4、其他

a)并集

语法:sunion key[key…]

解释:多个set的并集

  1. redis 127.0.0.1:6379> smembers stu
  2. 1) “zhangsan01”
  3. 2) “wangwu”
  4. redis 127.0.0.1:6379> sunion stu
  5. 1) “zhangsan01”
  6. 2) “wangwu”
  7. redis 127.0.0.1:6379> smembers tech
  8. 1) “wangwu”
  9. 2) “zhangsan”
  10. redis 127.0.0.1:6379> sunion stu tech
  11. 1) “zhangsan01”
  12. 2) “wangwu”
  13. 3) “zhangsan”

b)把并集结果存储到set

语法:sunionstore destination key [key …]

解释:求多个set并集,并把结果存储到destination

  1. redis 127.0.0.1:6379> sunionstore same stu tech #把stu tech并集结果存储在union
  2. (integer) 3
  3. redis 127.0.0.1:6379> smembers union
  4. 1) “zhangsan01”
  5. 2) “wangwu”
  6. 3) “zhangsan”

c)交集

语法:sinter key[key…]

解释:多个set的交集

  1. redis 127.0.0.1:6379> smembers stu
  2. 1) “zhangsan01”
  3. 2) “wangwu”
  4. redis 127.0.0.1:6379> smembers tech
  5. 1) “wangwu”
  6. 2) “zhangsan”
  7. redis 127.0.0.1:6379> sinter stu tech
  8. 1) “wangwu”

d)把交集结果存储到指定set

语法:sinterstore destination key [key …]

解释:把多个set的交集结果存储到destination

  1. redis 127.0.0.1:6379> sinterstore inter stu tech
  2. (integer) 1
  3. redis 127.0.0.1:6379> smembers inter
  4. 1) “wangwu”

e) set中在其他set中不存在member

语法:sdiff key[key …]

  1. redis 127.0.0.1:6379>
  2. redis 127.0.0.1:6379> smembers stu
  3. 1) “zhangsan01”
  4. 2) “wangwu”
  5. redis 127.0.0.1:6379> smembers tech
  6. 1) “wangwu”
  7. 2) “zhangsan”
  8. redis 127.0.0.1:6379> sdiff stu tech
  9. 1) “zhangsan01”
  10. redis 127.0.0.1:6379> sdiff tech stu
  11. 1) “zhangsan”

f)把set中在其他set中不存在的member存储到新的set

语法:sdiffstore key[key…]

  1. redis 127.0.0.1:6379> sdiffstore diff stu tech
  2. (integer) 1
  3. redis 127.0.0.1:6379> smembers diff
  4. 1) “zhangsan01”

主要参考:

http://redis.io/commands#set

http://redis.io/topics/data-types

工欲善其事,必先利其器

本文版权归翟士丹(Stan Zhai)博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

原文地址:http://www.cnblogs.com/jasondan/p/it-memo.html

技术站点

Hacker News:非常棒的针对编程的链接聚合网站

Programming reddit:同上

MSDN:微软相关的官方技术集中地,主要是文档类

infoq:企业级应用,关注软件开发领域

OSChina:开源技术社区,开源方面做的不错哦

cnblogs,51cto,csdn:常见的技术社区,各有专长

stackoverflow:IT技术问答网站

GitHub:全球最大的源代码管理平台,很多知名开源项目都在上面,如Linux内核,

OpenStack等免费的it电子书:http://it-ebooks.info/

DevStore:开发者服务商店

不错的书籍

人件

人月神话

代码大全2

计算机程序设计艺术

程序员的自我修养

程序员修炼之道

高效能程序员的修炼(成为一名杰出的程序员其实跟写代码没有太大关系)

深入理解计算机系统

软件随想录

算法导论(麻省理工学院出版社)

离线数学及其应用

设计模式

编程之美

黑客与画家

编程珠玑

C++ Prime

Effective C++

TCP/IP详解

Unix 编程艺术

《精神分析引论》弗洛伊德

搞定:无压力工作的艺术

平台工具(都是开源的好东东哦)

Redmine/Trac:项目管理平台

Jenkins/Jira(非开源):持续集成系统(Apache Continuum,这个是Apache下的CI系统,还没来得及研究)

Sonar:代码质量管理平台

git,svn:源代码版本控制系统

GitLib/Gitorious:构建自己的GitHub服务器

gitbook:https://www.gitbook.io/写书的好东西,当然用来写文档也很不错的

Travis-ci:开源项目持续集成必备,和GitHub相结合,https://travis-ci.org/

开源测试工具、社区(Selenium、OpenQA.org)

Puppet:一个自动管理引擎,可以适用于Linux、Unix以及Windows平台。所谓配置管理系统,就是管理机器里面诸如文件、用户、进程、软件包这些资源。无论是管理1台,还是上万台机器Puppet都能轻松搞定。

Nagios:系统状态监控报警,还有个Icinga(完全兼容nagios所有的插件,工作原理,配置文件以及方法,几乎一模一样。配置简单,功能强大)

Ganglia:分布式监控系统

fleet:分布式init系统

爬虫相关(好玩的工具)

Phantomjs

berserkJS(基于Phantomjs的改进版本)

SlimerJS

CasperJS

selenium

Web服务器性能/压力测试工具/负载均衡器

http_load: 程序非常小,解压后也不到100K

webbench: 是Linux下的一个网站压力测试工具,最多可以模拟3万个并发连接去测试网站的负载能力

ab: ab是apache自带的一款功能强大的测试工具

Siege: 一款开源的压力测试工具,可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进行。

squid(前端缓存),nginx(负载),nodejs(没错它也可以,自己写点代码就能实现高性能的负载均衡器):常用的负载均衡器

Piwik:开源网站访问量统计系统

ClickHeat:开源的网站点击情况热力图

HAProxy:高性能TCP /HTTP负载均衡器

ElasticSearch:搜索引擎基于Lucene

Page Speed SDK和YSLOW

HAR Viewer: HAR分析工具

protractor:E2E(end to end)自动化测试工具

Web前端相关

GRUNT: js task runner

Sea.js: js模块化

knockout.js:MVVM开发前台,绑定技术

Angular.js: 使用超动感HTML & JS开发WEB应用!

Highcharts.js,Flot:常用的Web图表插件

Raw:非常不错的一款高级数据可视化工具

Rickshaw:时序图标库,可用于构建实时图表

JavaScript InfoVis Toolkit:另一款Web数据可视化插件

Pdf.js,在html中展现pdf

ACE,CodeMirror:Html代码编辑器(ACE甚好啊)

NProcess:绚丽的加载进度条

impress.js:让你制作出令人眩目的内容展示效果(类似的还有reveal)

Threejs:3DWeb库

Hightopo:基于Html5的2D、3D可视化UI库

jQuery.dataTables.js:高度灵活的表格插件

Raphaël:js,canvas绘图库,后来发现百度指数的图形就是用它绘出来的

director.js:js路由模块,前端路由,Nodejs后端路由等,适合构造单页应用

pace.js:页面加载进度条

bower:Web包管理器

jsnice:有趣的js反编译工具,猜压缩后的变量名 http://www.jsnice.org/

D3.js: 是一个基于JavaScript数据展示库(类似的还有P5.js)

Zepto.js:移动端替代jQuery的东东,当然也可以使用jquery-mobile.

UI框架:Foundation,Boostrap,Pure,EasyUI,Polymer

前端UI设计师必去的几个网站:DribbbleawwwardsunmatchedstyleUIMaker

Mozilla 开发者中心:https://developer.mozilla.org/en-US/

图标资源:IcoMoon(我的最爱),Themify IconsFreePikGlyphiconsart

Dialog:非常漂亮的对话框

AdminLTE:github上的一个开源项目,基于Boostrap3的后台管理页面框架

Respond.js:让不懂爱的IE6-8支持响应式设计

require.js: js模块加载库

select2:比chosen具有更多特性的选择框替代库

AngularUI:集成angular.js的UI库

normalize.css: 采用了现代化标准让各浏览器渲染出的html保持一致的库

CreateJS:Html5游戏引擎Less,Compass:简化CSS开发

emojify.js:用于自动识别网页上的Emoji文字并将其显示为图像

simditor:一个不错的开源的html编辑器,简洁高效

Sencha:  基于html5的移动端开发框架

SuperScrollorama+TweenMax+skrollr:打造超酷的视差滚动效果网页动画

jquery-smooth-scroll:同上,平滑滚动插件

Animate.css:实现了各种动画效果的css库

Emmet:前端工程师必备,ZenCode的前身

MagicDraw:Uml图工具

大数据处理/数据分析/分布式工具

Hadoop:分布式的文件系统,结合其MapReduce编程模型可以用来做海量数据的批处理(Hive,Pig,HBase啥的就不说了),值得介绍的是Cloudera的Hadoop分支CDH5,基于YARN MRv2集成了Spark可直接用于生产环境的Hadoop,对于企业快速构建数据仓库非常有用。

Ceph:Linux分布式文件系统(特点:无中心)

Storm:实时流数据处理,可以看下IBM的一篇介绍 (还有个Yahoo的S4,也是做流数据处理的)

Spark:大规模流式数据处理(可以应付企业中常见的三种数据处理场景:复杂的批量数据处理(batch data processing);基于历史数据的交互式查询(interactive query);基于实时数据流的数据处理(streaming data processing)),CSND有篇文章介绍的不错

Spark Streaming:基于Spark的实时计算框架

Tachyon:分布式内存文件系统

Mesos:计算框架一个集群管理器,提供了有效的、跨分布式应用或框架的资源隔离和共享Impala:新一代开源大数据分析引擎,提供Sql语义,比Hive强在速度上

SNAPPY:快速的数据压缩系统,适用于Hadoop生态系统中

Kafka:高吞吐量的分布式消息队列系统

ActiveMQ:是Apache出品,最流行的,能力强劲的开源消息总线

MQTT:Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分

RabbitMQ:记得OpenStack就是用的这个东西吧

ZeroMQ:宣称是将分布式计算变得更简单,是个分布式消息队列,可以看下云风的一篇文章的介绍开源的日志收集系统:scribe、chukwa、kafka、flume。这有一篇对比文章

Zookeeper:可靠的分布式协调的开源项目

Databus:LinkedIn 实时低延迟数据抓取系统

数据源获取:Flume、Google Refine、Needlebase、ScraperWiki、BloomReach

序列化技术:JSON、BSON、Thrift、Avro、Google Protocol Buffers

NoSql:Apache Hadoop、Apache Casandra、MongoDB、Apache CouchDB、Redis、BigTable、HBase、Hypertable、Voldemort、Neo4j

MapReduce相关:Hive、Pig、Cascading、Cascalog、mrjob、Caffeine、S4、MapR、Acunu、Flume、Kafka、Azkaban、Oozie、Greenplum

数据处理:R、Yahoo! Pipes、Mechanical Turk、Solr/ Lucene、ElasticSearch、Datameer、Bigsheets、TinkerpopNLP自然语言处理:Natural Language Toolkit、Apache OpenNLP、Boilerpipe、OpenCalais

机器学习:WEKA、Mahout、scikits.learn、SkyTree

可视化技术:GraphViz、Processing、Protovis、Google Fusion Tables、Tableau、Highcharts、EChats(百度的还不错)、Raphaël.js

Kettle:开源的ETL工具

Pentaho:以工作流为核心的开源BI系统

Mondrian:开源的Rolap服务器

Oozie:开源hadoop的工作流调度引擎

开源的数据分析可视化工具:Weka、Orange、KNIME

Cobar:阿里巴巴的MySql分布式中间件

C & C++

Thrift:用来进行可扩展且跨语言的服务的开发(类似的还有个Avro,Google protobuf)。

libevent:是一个事件触发的网络库,适用于windows、linux、bsd等多种平台,内部使用select、epoll、kqueue等系统调用管理事件机制。(对了还有个libev呢)

Boost:不多说了,准C++标准库

Ptmalloc\Valgrind\Purify

NetworkServer架构:acceptor->dispatcher->worker(这个不算工具哦)

breakpad:崩溃转储和分析模块,很多crashreport会用到

UI界面相关:MFC、BCG和QT这类的就不说了,高端一点的还有Html和DirectUI技术:libcef(基于chrome内核的,想想使用html5开发页面,还真有点小激动呢)、HtmlLayout、Duilib、Bolt,非C++的,还有node-webkit也不错,集成了node和webkit内核。

游戏开发相关

MINA:使用Java开发手游和页游服务器(对了还有Netty,也很猛的,都是基于NIO的)

HP-Socket:见有有些页游服务器使用这个构建的

云风的技术博客:http://blog.codingnow.com/

OGRE:大名鼎鼎的3D图形渲染引擎

OpenVDB:梦工厂C++的特效库,开源的

cocos2d:跨平台2D游戏引擎

unity3d:跨平台3D游戏引擎,很火的哦

Nodejs:也有不少使用它来开发手游和也有服务器(网易的Pomelo就是哦)

日志聚合,分布式日志收集

Scribe:Facebook的(nodejs + scribe + inotify 同步日志)

logstash:强大的日志收集系统,可以基于logstash+kibana+elasticsearch+redis开发强大的日志分析平台

log.io: nodejs开发的实时日志收集系统

RTP,实时传输协议与音视频

RTP,RTCP,RTSP-> librtp,JRTPLIB(遵循了RFC1889标准)

环形缓冲区,实时数据传输用

SDL,ffmpeg,live555,Speex

Red5:用Java开发开源的Flash流媒体服务器。它支持:把音频(MP3)和视频(FLV)转换成播放流; 录制客户端播放流(只支持FLV);共享对象;现场直播流发布;远程调用。

Python

Eric,Eclipse+pydev,比较不错的Python IDE

PyWin:Win32 api编程包

numpy:科学计算包,主要用来处理大型矩阵计算等,此外还有SciPy,Matplotlib

GUI相关:PyQt,PyQwt

supervisor:进程监控工具

Java相关

常用的IDE:IntelliJ IDEA,Eclipse,Netbeans

Web开发相关:Tomcat、Resin、Jetty、WebLogic等,常用的组件Struts,Spring

HibernateNetty: 异步事件驱动网络应用编程框架,用于高并发网络编程比较好(NIO框架)

MINA:简单地开发高性能和高可靠性的网络应用程序(也是个NIO框架),不少手游服务端是用它开发的

jOOQ:java Orm框架Activiti:工作流引擎,类似的还有jBPM、Snaker

Perfuse:是一个用户界面包用来把有结构与无结构数据以具有交互性的可视化图形展示出来.

Gephi:复杂网络分析软件, 其主要用于各种网络和复杂系统,动态和分层图的交互可视化与探测开源工具

Nutch:知名的爬虫项目,hadoop就是从这个项目中发展出来的

web-harvest:Web数据提取工具

POM工具:Maven+ArtifactoryNetflix

Curator:Netflix公司开源的一个Zookeeper client library,用于简化Zookeeper客户端编程

Akka:一款基于actor模型实现的 并发处理框架

EclEmma:覆盖测试工具

.net相关

Xilium.CefGlue:基于CEF框架的.NET封装,基于.NET开发Chrome内核浏览器

CefSharp:同上,有一款WebKit的封装,C#和Js交互会更简单

netz:免费的 .NET 可执行文件压缩工具

SmartAssembly:变态的.net代码优化混淆工具

NETDeob0:.net反混淆工具,真是魔高一尺道高一丈啊(还有个de4dot,在GitHub上,都是开源的)

ILMerge:将所有引用的DLL和exe文件打成一个exe文件

ILSpy:开源.net程序反编译工具

Javascript.NET:很不错的js执行引擎,对v8做了封装

NPOI: Excel操作

DotRAS:远程访问服务的模块

WinHtmlEditor: Winform下的html编辑器

SmartThreadPool:使用C#实现的,带高级特性的线程池

Snoop: WPF Spy Utility

Autofac: 轻量级IoC框架

HtmlAgilityPack:Html解析利器

Quartz.NET:Job调度

HttpLib:@CodePlex,简化http请求

SuperSocket:简化Socket操作,基于他的还有个SuperWebSocket,可以开发独立的WebSocket服务器了

DocX:未安装Office的情况下操作Word文件

Dapper:轻量级的ORM类,性能不错

HubbleDotNet:支持接入数据库的全文搜索系统

fastJSON:@CodeProject,高性能的json序列化类

ZXing.NET:@CodePlex,QR,条形码相关

Nancy:轻量级Http服务器,做个小型的Web应用可以摆脱IIS喽(Nancy.Viewengines.Razor,可以加入Razor引擎)

AntiXSS:微软的XSS防御库Microsoft Web Protection

LibraryJint:JavaScript解释器

CS-Script:将C#代码文件作为脚本执行

Jexus:Linux下 高性能、易用、免费的ASP.NET服务器

Clay:将dynamic发挥的更加灵活,像写js一样写C#

DynamicJSON:不必定义数据模型获取json数据

Antlr:开源的语法分析器(归到C#不太合适,其他语言也可以去用)

SharpPcap:C#版的WinPcap调用端,牛逼的网络包分析库(自带PacketNotNet用于包协议分析)

Roslyn:C#,VB编译器

ImageResizer: 服务端自由控制图片大小,真乃神器也,对手机端传小图,PC端传大图,CMS用它很方便

UI相关:DevExpress, Fluent(Office 07风格), mui(Modern UI for WPF)

NetSparkle:应用自动更新组件

ConfuserEx: 开源.net混淆工具

ServiceStack: 开源高性能Web服务框架,可用于构建高性能的REST服务Expression

Evaluator:Eval for C#,处理字符串表达式

http://nugetmusthaves.com/

常用工具

Fiddler:非常好用的Web前端调试工具,当然是针对底层http协议的,一般情况使用Chrome等自带的调试工具也足够了,特殊情况还得用它去处理

wireshark:知名的网络数据包分析工具

PowerCmd:替代Windows Cmd的利器

RegexBuddy:强大的正则表达式测试工具

Soure Insight:源代码阅读神器

SublimeText:程序员最爱的编辑器

Database.NET:一个通用的关系型数据库客户端,基于.NET 4.0开发的,做简单的处理还是蛮方便的

Navicat Premium:支持MySql、PostgreSQL、Oracle、Sqlite和SQL Server的客户端,通用性上不如Database.NET,但性能方面比Database.NET好很多,自带备份功能也用于数据库定时备份。

Synergy : 局域网内一套键盘鼠标控制多台电脑

DameWare:远程协助工具集(我在公司主要控制大屏幕用)

Radmin: 远程控制工具,用了一段时间的

DameWare,还要破解,对Win7支持的不好,还是发现这个好用

Listary:能极大幅度提高你 Windows 文件浏览与搜索速度效率的「超级神器」

Clover:给资源管理器加上多标签

WinLaunch:模拟Mac OS的Launch工具

Fritzing:绘制电路图

LICEcap:gif教程制作git,

svn:版本控制系统Enigma Virtual Box(将exe,dll等封装成一个可执行程序)

Open DBDiff(针对SqlServer)数据库同步

SymmetricDS:数据库同步

BIEE,Infomatica,SPSS,weka,R语言:数据分析

CodeSmith,LightSwitch:代码生成

Pandoc:Markdown转换工具,出书用的。以前玩过docbook,不过现在还是Markdown盛行啊。

Window Magnet[Mac]:增强Mac窗口管理功能,想Win7一样具有窗口拖放到屏幕边缘自动调整的功能

log explorer:查看SqlServer日志dependency

walker:查询Windows应用程序dll依赖项

Shairport4w:将iPhone,iPad,iPod上的音频通过AirPlay协议传输到PC上

ngrok:内网穿透工具Axure:快速原型制作工具,还有个在线作图的工具国内的一个创业团队做的,用着很不错 http://www.processon.com

tinyproxy:(Linux)小型的代理服务器支持http和https协议EaseUS Partition

Master:超级简单的分区调整工具,速度还是蛮快的,C盘不够用了就用它从D盘划点空间吧,不用重装系统这么折腾哦。

CheatEngine:玩游戏修改内存值必备神器(记得我在玩轩辕剑6的时候就用的它,超级方便呢)

ApkIDE:Android反编译神器翻、墙工具(自|由|门、天行浏览器)

设计工具:Sketch、OmniGraffle

MindManger:思维导图

未完待续……

[译]拳头公司聊天服务架构:服务器篇

原文:Chat Service Architecture Servers

译者:杰微刊-张帆

服务器,架构,开发

英雄联盟玩家每天总计发送数百万的信息。他们邀请朋友双排,在英雄选择界面和队伍沟通英雄选择,在战局结束时向所有人敲出”GG”(Good Game)以表感谢。今年的7月21号(我随机挑选了一天),玩家在游戏中建立了170万新的好友关系——满满都是爱!每次玩家发送消息,都会触发一系列后台的操作,而正是这些后台技术驱动了Riot的聊天系统。

在之前的文章《聊天服务架构:协议篇》中,我论述了我们所选用的客户端服务器间通信协议:XMPP(Extensible Messaging and Presence Protocol, 可扩展通讯和表示协议)。今天我会适当地就服务端和基础设施架构的相关机制进行深入探讨,同时,我也会论述到目前为了保证服务器的可扩展性和健壮性,我们所做的努力和已经完成的工作。像上一篇文章一样,我希望任何需要为分布式客户端库添加聊天特性的开发者会对本篇文章感兴趣。

服务器硬件

聊天系统的物理服务器应当具备这样的能力——确保服务对玩家来讲持续可用。这些服务器管理每个用户的聊天会话,同时能够保证必要的稳定性和应用安全验证隐私设置,如访问量流量限制、指标收集和日志记录等。
我们的聊天服务是按区域部署的(我们称每个区域为一个“分片”),这意味着每个英雄联盟区服拥有其自己的聊天集群,用于提供并且仅为该分片的玩家提供聊天功能。结果导致跨区服的玩家不能进行沟通交流,同时聊天服务器不能使用其他区域的数据。比如,北美服务器(NA)不能直接与西欧服务器(EU West)进行交流。
每个分片维护了一个由大量各种各样的物理服务器组成的聊天集群,这些服务器上运行着相同的服务器软件。每个区域的硬件规格参数都不尽相同,因为要考虑一系列的原因,如承载量需求、设备年限和硬件可用性——我们最新的服务器具备现代24核CPU、196GB的内存和固态硬盘(SSD),而较陈旧的服务器则使用24G内存和传统磁碟硬盘。
在聊天集群内,每个节点是完全独立和可替换的,这使得系统可以轻松的进行维护,从而提高了系统整体的容错性。一个集群中的节点数约为6~12台机器。尽管我们可以在每个区域运行更少的机器数量,但是为了给容错提供足够的空间和适应将来的增长需求,还是保证了足够的数量。如果月到升级需要关闭服务器,举例来讲,我们可以关闭单个集群中一半的节点数来确保不会中断为玩家提供的服务。
下面是一个简单的图表,展示了我们聊天服务的集群架构

服务器,架构,开发

在过去一段时间,我们遇到过大量由于硬件或者网络故障引起的意外事件,为了解决这类问题,我们不得不将个人服务器关闭几天,然而正是因为系统具备较好的容错机制,对玩家来讲,服务持续进行并没有中断。此外,我们还在客户端实现了这样一个逻辑——帮助已连接到关闭服务器的玩家自动重新获取他们的链接。
具体实现
拳头的聊天服务器主要是用Erlang(如果你对该语言感兴趣,可以点击查看这个视频https://www.youtube.com/watch?v=xrIjfIjssLE)写的,此外我们还用C来实现一些下层操作,如XML解析、SSL握手、字符串操作等。我们聊天服务的代码库,大约10%是C语言实现,90%是纯Erlang(忽略外部库和Erlang VM本身)。
在用C语言开发服务器组件之前,我们花了大量的时间分析和优化现有的Erlang代码库。我们尝试在使用全部现有工具的前提下,找出不同抽象等级下潜在的并发和效率瓶颈:
① 对于简单的调用计数,我们使用cprof,cprof框架极其简单,却能够具有验证我们是否在正确的时间进行了正确调用的能力。
② 为了进行更详细的分析,我们运行了fprof。不幸的是,fprof对测试服务器会产生较大的影响,所以不能在一个完整的负载测试期间使用——然而,它却能够使我们更详细的了解到如何和何时进行调用。其中包括单个函数在它执行期间花费的时间(own time,独占时间),包含调用函数所花费时间在内的全部时间(accumulated time,累计时间)和过程结果的分组。所以这些帮助我们找出系统执行过程中的CPU密集区域。
③ 当检测并发瓶颈时,perceptlcnt十分友好。这些工具帮我们尽可能的识别所有并行化数据处理的时机,以便是我们可以利用所有的可用核心。
④ 在操作系统层面,我们采用了传统分析工具,比如mpstat,vmstat,iostat,perf,还有一些/proc的文件系统文件。
我们发现,大部分珍贵的CPU执行周期和内存分配发生在处理文本和数据流时。由于Erlang的terms被定义为不可修改,不管我们如何优化代码,执行任何字符串密集的排序操作将十分“昂贵”。所以,我们使用C来重写最笨重的字符串操作的系统部件,同时,使用HiPE来编译部分标准库——这使得CPU占有率性能提高了60%以上。此外,我们发现,对每个玩家的会话处理,内存分配由150kb降低至25kb。
我们尝试遵从“Erlang/OTP设计原则和最佳实践”(best practices and Erlang/OTP design principles),所以拳头的聊天服务器形成了一个全关联的集群,即集群中的每两个聊天服务器之间由Erlang VM维护单独的一个持久TCP连接。服务器使用这些连接来传达Erlang分布式协议,进行内部交流。至此,无论如何详尽的测试,我们再次交流模型上再也找不到任何瓶颈。

服务器,架构,开发

前面我提到过,集群中的每个服务器都是一个完全独立的单元——这使得每个服务器在任何时间都可以独立操作,独立运行,独立提供服务。为了提供充分的可扩展性/伸缩性,我们将系统设计成节点间共享尽可能少的数据。因此,聊天集群中的服务器仅共享一小部分内部键值表,这部分表完全复制在内存中,通过一个高度优化的Erlang分布式数据库管理系统进行通讯,这个系统被称作Mnesia(如果你想学习更多有关Mnesia的内容,我强烈建议你去看一下erlang.org上的材料和这个网站learnyousomeerlang.com)。这些表将玩家或者组聊天识别符(在XMPP中被称作JIDs)与Erlang处理器进程进行映射,后者维护了一些上下文特定的数据。
对单独的玩家聊天,这些数据中可能会包括链接套接字(connection socket)、好友列表和限速器;对于群组对话、这些数据则包括房间名册和聊天记录。每次在玩家或者群组对话间有需要路由任何类型的信息时,服务器会问询这些键值表以通过JIDs来处理他们的会话句柄。因为每个服务器持有一份session表的完全拷贝,所以所有的都操作都是在本地发起,减少了整体的路由延迟。

服务器,架构,开发

上述做法的负面影响就是每个应用于这些表的更新必须被复制到其他所有已连接的聊天服务器中。据我们所知,这些表是唯一可能会阻止我们顺利线性扩展聊天集群的因素——然而,负载测试显示我们可以将聊天集群增加至30台服务器而没有任何性能损耗。
为了保证玩家的会话数据或者群组聊天数据在网络切割或者服务器故障时保持同步,每个聊天服务器运行订阅了关于集群拓扑变化的VM内部通知Erlang进程。当任何事件产生,比如聊天服务器宕机,其他节点将从它们的本地表中移除脱机节点上正在运行的所有会话条目。一旦节点恢复上线(通常是在重启或等待网络连接恢复之后),该节点会向其他集群成员推送自己的本地状态,并且下载其他节点的状态。通过这种模式,聊天服务器对其自己的数据而言扮演了绝对权威的角色,对其他聊天服务器的数据,完全信任。
为了解释这个设计,让我们一起考虑下面的示例:
① 我们有一个三台聊天服务器组成的集群:节点A(玩家Alice和Bobby连接到该节点)、节点B(玩家Charlie连接到该节点)和节点C(玩家Dan和Eve连接到该节点)。所有的玩家可以立刻进行交流:

服务器,架构,开发

② 网络故障导致节点A与集群中的其他节点脱离,下次其他机器尝试与A进行通讯时,会遇到一个关闭的TCP套接字并产生一个由信号群集拓扑改变引发的事件。这是网络断裂的一个十分典型的案例。在这个案例中,Alice和Bob就像被隔离到单独的岛屿上,不能与Charlie、Dan和Eve进行通讯,然而Charlie、Dan和Eve之间仍可正常通讯:

服务器,架构,开发

③ 现在,节点B和C不能访问单独一侧的节点A,当Erlang VM将集群拓扑变更事件传递给订阅处理程序,节点B和C会舍弃节点A上的玩家会话引用。尽管Alice和Bob仍可访问服务并相互之间可以聊天,但是他们不能与Charlie、Dan和Eve进行沟通。【译者注:原文中的下图中所示,节点A其实也把Charlie,Dan和Eve的会话引用舍弃掉了,文中并没有指明】

服务器,架构,开发

④ 网络连接恢复后,节点A重新与节点B和C之间建立TCP链接。不幸的是,连接建立后,节点A还不知道节点B和C,所以Alice和Bob仍然不能与Charlie、Dan和Eve沟通:

服务器,架构,开发

⑤ 最后,Erlang VM再次发起了集群拓扑变更事件,这次发出的通知是服务器加入。节点A下载节点B和节点C的会话数据到A本地Mnesia表,节点B和C同理将节点A的会话数据下载到本地。现在集群再一次复制完毕,可以允许Aclice、Bob、Charlie、Dan和Eve之间所有的通讯:

服务器,架构,开发

这个设计可以使我们构建健壮可自修复的基础架构,不再需要在连接失败的情况下立即手动干预。所以,服务可以自动从网络异常中恢复,并对玩家恢复其功能。
数据流
基于上面谈到的服务器实现,让我们来审查下提供给玩家聊天的软件过程。无论任何时候,当玩家客户端链接到聊天服务器时,客户端便向其公共的XMPP终端开放了一个持久的、加密的(采用AES256-SHA加密算法)TCP链接。集群负载均衡器会在后端选择聊天服务器中的一个,并且将该玩家的会话指定分配到这个服务器。目前,我们使用一个正则循环负载平衡策略以在所有可用的服务器之间分发负载均匀。
一旦链接建立,聊天服务器会创建一个新的专用的Erlang进程来处理该玩家的会话。这个进程(又被称作c2s,即client to server, 客户端到服务端)维护了玩家的TCP套接字、XML解析器实例、好友列表和黑名单、最后状态数据、召唤师名称、速率限制配置和其他重要的服务器所使用的用于提供玩家体验的详细信息。在链接中,我们的系统会立即要求身份验证,校验该玩家身份。在这里,我们试用了兼容第三方客户端的XMPP标准身份验证机制
为了进一步说明,我们还是举Alice和Bob的例子。二位都是青铜2的玩家,期待有一天可以打上王者段位。为此,Alice和Bob天天一起训练,在召唤师峡谷磨练他们的技术。
Alice想给Bob发信息,邀请Bob一起双排去打晋级青铜1的晋级赛。下面是一旦Alice通过验证链接到聊天服务器后台的一系列操作:
① Alice的游戏客户端通过其c2s进程维护的加密的TCP链接发送了一条XMPP信息(包含这样一条信息“要来一起打晋级赛生死局吗”)到聊天服务器
② Alice的c2s进程收到信息后进行解密喝转换成XML
③ 转换之后,该进程在这条消息上进行了几个验证,包括速率限制遵从性、防欺骗验证、黑名单和好友列表成员测试
④ 通过验证之后,Alice的c2s在其内部的映射表中查找Bob的会话句柄,并验证是否可达
⑤ 如果Bob当前不在线,则信息会被持久化到数据存储中,下次Bob登陆游戏之后再次发送他。根据分片的不同,数据库选用MySQL(对于老式环境)或者Riak(对于新的分片)。数据存储将是我下一片讨论聊天服务架构文章的主题
⑥ 如果Bob当前在线,则服务器将使用标准Erlang信息传递机制将信息发送至他的c2s进程
⑦ 当Bob的c2s进程接收到信息,将会像前面那样进行一系列校验
⑧ 校验结束,进程将将消息序列化为XML,然后发送至Bob的TCP套接字
⑨ 最终,Bob的游戏客户端可以接收到信息,并展示在合适的信息窗口
显而易见,一旦收到信息,Bob会很乐意加入Alice,两人将carry他们的团队,很快就可以晋级青铜1了。
内部接口
除了直接提供玩家聊天特性,Riot的聊天服务器还公开了几个私有的内部消费相关的REST接口。一贯地,服务使用这些REST端点来访问社交图谱(由玩家之间的好友关系确定)
例如:
1) 对于内容馈赠,如英雄皮肤,在游戏内部的商店背后,由服务器验证他们的好友关系是否足够“成熟”——这避免了威胁账号的恶意赠送
2) 建立战队的功能使用了LoL(League of Legends简写)的社交图谱,用来构建一个建议好友列表供玩家在建立战队时选择邀请的好友
3)  对于联盟相关的服务,系统会在后端查询好友列表用来决定哪些是新手玩家,偏向于将这些玩家与其好友放置在一方——即匹配时,更有可能与自己的好友在一个联盟中。
这里拿一个真实的例子,考虑一下请求ID13131召唤师的好友列表:

“`
GET /friends/summoner/13131 HTTP/1.1 … < HTTP/1.1 200 OK < server: Cowboy < connection: keep-alive [ { “ask”: “none”, “askmessage”: “”, “createdat”: “2015-06-30 10:52:26”, “group”: “Work”, “nick”: “Riot Teemo”, “note”: “top laner!”, “subscription”: “both”, “summonerid”: 112233 }, { “ask”: “none”, “askmessage”: “”, “createdat”: “2015-06-25 11:25:07”, “group”: “Family”, “nick”: “Pentakill Morg”, “note”: “Mom”, “subscription”: “both”, “summonerid”: 223344 }, { “ask”: “none”, “askmessage”: “”, “createdat”: “2015-06-17 17:57:17”, “group”: “Work”, “nick”: “Jax Jax Jax”, “note”: “plays only Jax?”, “subscription”: “both”, “summoner_id”: 334455 }, … ] “`

为了支持这些请求,聊天服务器运行了Cowboy,一个用于处理其他内部服务传来的HTTP请求的嵌入式Web服务器。为了方便集成,每个后端通过Swagger返回JSON对象来填充请求。
尽管当前,我们使用了一个集中的内部均衡器来分发这些请求,在将来,我们更倾向于使用自动发现模型和客户端的负载均衡机制。服务可进行自配置可以使我们在不用进行网络的重新配置的前提下便可以动态的重新部署集群大小,同时还可以十分简单的建立新的分区(对内提供测试或者对外提供玩家使用)。
结语
在单独的一天之中,Riot的聊天服务器通常会路由转发大约十亿的事件(如在线状态、信息等),并且处理上百万的REST查询。尽管现在系统并不完美,基础设施的健壮性和可扩展性还是能够保持聊天服务对玩家持续可用——今年,系统由于时不时出现的硬件问题常需要关闭某一个独立的服务,但是自修复的特性为Riot的所有区服提供了99.999%的运行时间。尽管我在这里仅仅探讨了很表层的内容,但是我还是希望能对于如何在服务器端增加了聊天功能进行一个抛砖引玉。
如有任何问题或者评论,欢迎留言,我很期待大家的留言。这个系列的下一篇文章,也是最后一篇文章,将会着重关注Riot聊天服务的数据库部分,届时见~

——————-好久不见的分割线——————-

如果您发现这篇译文的任何问题,可随时与杰微刊联系。

我们水平有限,但理想高远。杰微刊旨在分享优质的内容。

杰微刊也同样期待理想的您对这个世界的贡献。欢迎任何目的的联系。

杰微刊的有偿投稿邮箱是:weikan@jointforce.com

我们的QQ是:3272840549。

[转载请保留原文出处、译者和审校者。 可以不保留我们的链接]

iOS开发中@property的属性weak nonatomic strong readonly等介绍

@property与@synthesize是成对出现的,可以自动生成某个类成员变量的存取方法。在Xcode4.5以及以后的版本,@synthesize可以省略。

1.atomic与nonatomic
atomic:默认是有该属性的,这个属性是为了保证程序在多线程情况,编译器会自动生成一些互斥加锁代码,避免该变量的读写不同步问题。
nonatomic:如果该对象无需考虑多线程的情况,请加入这个属性,这样会让编译器少生成一些互斥加锁代码,可以提高效率。

2.readwrite与readonly
readwrite:这个属性是默认的情况,会自动为你生成存取器。
readonly:只生成getter不会有setter方法。
readwritereadonly这两个属性的真正价值,不是提供成员变量访问接口,而是控制成员变量的访问权限。

3.strong与weak
strong:强引用,也是我们通常说的引用,其存亡直接决定了所指向对象的存亡。如果不存在指向一个对象的引用,并且此对象不再显示在列表中,则此对象会被从内存中释放。
weak:弱引用,不决定对象的存亡。即使一个对象被持有无数个弱引用,只要没有强引用指向它,那么还是会被清除。
strongretain功能相似;weakassign相似,只是当对象消失后weak会自动把指针变为nil;

4.assign、copy、retain
assign:默认类型,setter方法直接赋值,不进行任何retain操作,不改变引用计数。一般用来处理基本数据类型。
retain:释放旧的对象(release),将旧对象的值赋给新对象,再令新对象引用计数为1。我理解为指针的拷贝,拷贝一份原来的指针,释放原来指针指向的对象的内容,再令指针指向新的对象内容。
copy:与retain处理流程一样,先对旧值release,再copy出新的对象,retainCount为1.为了减少对上下文的依赖而引入的机 制。我理解为内容的拷贝,向内存申请一块空间,把原来的对象内容赋给它,令其引用计数为1。对copy属性要特别注意:被定义有copy属性的对象必须要 符合NSCopying协议,必须实现- (id)copyWithZone:(NSZone *)zone方法。
也可以直接使用:
使用assign: 对基础数据类型 (NSInteger,CGFloat)和C数据类型(int, float, double, char, 等等)
使用copy: 对NSString
使用retain: 对其他NSObject和其子类

5.getter setter
getter:是用来指定get方法的方法名
setter:是用来指定set访求的方法名
在@property的属性中,如果这个属性是一个BOOL值,通常我们可以用getter来定义一个自己喜欢的名字,例如:
@property (nonatomic, assign, getter=isValue) boolean value;
@property (nonatomic, assign, setter=setIsValue) boolean value;


一,retain, copy, assign区别

1.
假设你用malloc分配了一块内存,并且把它的地址赋值给了指针a,后来你希望指针b也共享这块内存,于是你又把a赋值给(assign)了b。此时a
和b指向同一块内存,请问当a不再需要这块内存,能否直接释放它?答案是否定的,因为a并不知道b是否还在使用这块内存,如果a释放了,那么b在使用这块
内存的时候会引起程序crash掉。

2.
了解到1中assign的问题,那么如何解决?最简单的一个方法就是使用引用计数(reference
counting),还是上面的那个例子,我们给那块内存设一个引用计数,当内存被分配并且赋值给a时,引用计数是1。当把a赋值给b时引用计数增加到
2。这时如果a不再使用这块内存,它只需要把引用计数减1,表明自己不再拥有这块内存。b不再使用这块内存时也把引用计数减1。当引用计数变为0的时候,
代表该内存不再被任何指针所引用,系统可以把它直接释放掉。

3. 上面两点其实就是assign和retain的区别,assign就是直接赋值,从而可能引起1中的问题,当数据为int, float等原生类型时,可以使用assign。retain就如2中所述,使用了引用计数,retain引起引用计数加1, release引起引用计数减1,当引用计数为0时,dealloc函数被调用,内存被回收。

4. copy是在你不希望a和b共享一块内存时会使用到。a和b各自有自己的内存。

5. atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。加了atomic,setter函数会变成下面这样:

if (property != newValue) {
[property release];
property = [newValue retain];
}

二,深入理解一下(包括autorelease)1. retain之后count加一。alloc之后count就是1,release就会调用dealloc销毁这个对象。
如果 retain,需要release两次。通常在method中把参数赋给成员变量时需要retain。
例如:
ClassA有 setName这个方法:
-(void)setName:(ClassName *) inputName
{
name = inputName;
[name retain]; //此处retian,等同于[inputName retain],count等于2
}
调用时:
ClassName *myName = [[ClassName alloc] init];
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,在ClassA的dealloc中release name才能真正释放内存。

2. autorelease 更加tricky,而且很容易被它的名字迷惑。我在这里要强调一下:autorelease不是garbage collection,完全不同于Java或者.Net中的GC。
autorelease和作用域没有任何关系!
autorelease 原理:
a.先建立一个autorelease pool
b.对象从这个autorelease pool里面生成。
c.对象生成 之后调用autorelease函数,这个函数的作用仅仅是在autorelease pool中做个标记,让pool记得将来release一下这个对象。
d.程序结束时,pool本身也需要rerlease, 此时pool会把每一个标记为autorelease的对象release一次。如果某个对象此时retain count大于1,这个对象还是没有被销毁。
上面这个例子应该这样写:
ClassName *myName = [[[ClassName alloc] init] autorelease];//标记为autorelease
[classA setName:myName]; //retain count == 2
[myName release]; //retain count==1,注意,在ClassA的dealloc中不能release name,否则release pool时会release这个retain count为0的对象,这是不对的。

记住一点:如果这个对象是你alloc或者new出来的,你就需要调用release。如果使用autorelease,那么仅在发生过retain的时候release一次(让retain count始终为1)。

3 xcode 中的新标记 strong weak
strong 用来修饰强引用的属性;对应以前retain
weak 用来修饰弱引用的属性;对应以前的assign

雪幕秋夕 简历

个人信息

  • 雪幕秋夕 / 男 / 1995
  • 山东大学 / 数学系 / 大三

联系方式

  • Email:i@lujq.me
  • QQ:549559373
  • 微信:ljq_0225
  • 手机:15165172012

技术笔记以及翻译文章

  1. 蚂蜂窝爬虫技术细节
  2. 关于全站Ajax的笔记
  3. py读写Excel模拟登陆代理爬取
  4. 翻译《MEAN-Web-Development》部分章节

代码经验

  1. 独立开发了一个管理Github Star的项目,以Web方式可视化管理Github Star过的项目,弥补Github原生Star功能的不足。后端采用Nodejs、数据库采用MongoDB、服务器采用Expressjs、前端采用Angularjs框架、UI使用Bootstrap库,项目已在Github开源 [ https://github.com/golmic/GithubStarManage ] 线上页面为 [http://gsm.lujq.me]
  2. 用Nodejs写了一个爬虫,爬取[[ 蚂蜂窝],并将爬取到的数据储存到Mongo数据库中,并展示。代码在 [ https://github.com/golmic/mafengwo-spider ] 技术细节在 [ http://code.lujq.me/2015/09/12/蚂蜂窝爬虫/] 上线页面为 [http://mafengwo.lujq.me]
  3. 独立开发了一个博客系统,同样是MEAN全栈实现,UI采用Google Material Design,实现Markdown编辑及实时预览,无刷新上传图片等功能。[ Github源码地址: https://github.com/golmic/G-blog ]
  4. 采用基于Nodejs的Hexo程序搭建了一个技术博客,托管在Github [ 技术博客地址 http://code.lujq.me ]
  5. 采用Wordpress搭建了个人博客,前端是基于Bootstrap框架自己写的主题,集成多个开源项目,如Animate.cssWOW等,大量使用HTML5以及CSS3特性。后端用php语言二次开发,实现了全站Ajax异步加载以及本地缓存。[ 个人博客地址 http://lujq.me ] [ 个人博客前端代码在Github开源 ]
  6. 开发微信公众号Golmic,后端采用PHP调用百度LBSAPI实现天气查询以及天气警报推送;调用API以及抓取方式实现关键词回复。
  7. 用Python写过爬虫,模拟登录爬取,处理Excel数据。
  8. 在自己的服务器上配置了ShadowSocks,供研究学习用。

技能清单

熟练使用 MEAN 栈堆

  • MongoDB
  • Express
  • AngularJS
  • Node.js

以下均为我熟练使用的技能

  • Web后端语言:Node.js/Python
  • 后端框架:Express
  • 前端:Bootstrap/AngularJS/HTML5/Material Design
  • 数据库:MongoDB
  • MVC框架
  • 版本管理:Git
  • 团队协作:Worktile/石墨
  • Linux各发行版部署及维护项目
  • 云:Microsoft Azure/DigitalOcean用户
  • 微信公众号开发
  • 《算法导论》

对以下知识均有一定了解

  • 后端语言:php
  • 后端框架:Django
  • 机器学习、数据挖掘
  • Go语言、C++
  • Linux系统运维、LNMP架构
  • Nginx、Apache服务器
  • 数据库相关:MySQL/PgSQL/SQLite
  • 《C++ Primer》《Effect C++》

其它补充

  • 接受技术岗,倾向于后端,钟情于算法;
  • 能接受的最低工作时薪为50,硬标准。
  • 数学院TOP10,主修数学。我的教材都已经是全英的了,英文水平高,无压力阅读或翻译英文文章及技术文档;
  • 重度Google用户,长期混迹Github、Stack Overflow等国内外的技术网站及社群;
  • 自学能力以及独立解决问题的能力极高;
  • 喜欢尝试各种新鲜技术和领域,Microsoft Azure用户。

致谢

感谢您花时间阅读我的简历,期待能有当面向您学习请教的机会。

前端性能优化方案索引

陆续整理和不断更新网络上给出的前端性能的优化方案。

这里只是做一个总概括式的索引,每一个方案都十分值得推敲和细说。

1 请求和响应

缓存控制

请求头里,可以发送 If-Modified-Since 以及 If-None-Match 等信息,来询问服务端请求内容是否有更新,如果没有更新,可返回304,告诉浏览器使用缓存,避免重新下载资源。Pragma 和 Cache-Control 等也能控制缓存。如告诉服务端不要缓存等。

响应头里,Expires 可以告诉浏览器过期时间,Last-Modified 最近更新时间,ETag 则可允许浏览器进行缓存验证(在 If-None-Match 请求信息中使用)。

复用TCP

请求头里,Connection 可控制 TCP 通道的使用,使用 keep-alive 可以复用上次打开的 TCP。

GZIP压缩

如果可以启用 gzip 压缩,将减少响应数据大小,加快响应。请求头里面可用 Accept-Encoding 告知浏览器支持的压缩方式,而服务端则用 Content-Encoding 作为回应。

Cookies

发送请求时,cookies 也在请求之中。因此,cookies 也可以作为减少请求的优化对象。如,根据同源限制策略,可以使用多个域名加载资源,如加载静态资源,就不会发送多余的 cookies;同时,合理设置 cookies 的路径和域名,如在子站避免不必要的来自父站的 cookies。

减少HTTP请求

有很多细节可以实现,比如CSS Sprites、Data URL等等,由于此部分内容和下述内容有所重复,故部分细节在下面会讲到。

多域名分发

同域下浏览器能并发的请求有限,而为了增加并发,尤其是一些静态资源上,可以使用多个域名。但由于域名DNS解析本身也是耗时的,所以实践原则是2-4个为宜。

需要额外提醒的是,加载图像资源的时候,并发没有问题;但在加载 JavaScript 脚本的时候,还是会暂停加载其他资源。

使用CDN

根据用户能访问的最快位置加速访问。

避免重定向和404

重定向和404将浪费加载请求。

favicon.ico

浏览器默认加载的资源,最好能够缓存之。

2 HTML

减少DOM

过多的DOM元素会影响渲染、加载、执行。除了精简页面结构外,还可以适时删除不必要的DOM元素(页面内已经不会再访问的元素),又或者可以懒加载(不一定会使用到的元素,如登录框)。

CSS 和 JavaScript 文件位置

CSS 放 head,JavaScript 放 body 闭标签前。乃是因为:

  • 样式表不参与 DOM 修改,所以不会为了解析样式停止文档解析
  • 浏览器要避免重绘,在没有拿到全部样式前不会开始渲染
  • 解析样式时,有的浏览器(FF)会停止脚本运行,而有的(Webkit)则会在脚本访问样式属性但可能受未加载样式影响时停止脚本运行
  • 脚本解析中可能请求样式,如果样式还未解析完毕就会出错
  • 脚本执行将暂停文档的解析和资源的下载

因此,将二者放在适当的位置,能够极大提高渲染效率。

脚本延迟加载

可将脚本添加 defer 和 async 属性。两个属性的共通点在于,脚本的加载和文档的解析是同步进行的,而区别在于:async 一旦加载完毕,立即停止文档解析并执行脚本;defer 等待文档解析完毕后再执行。

合理使用内联

脚本和样式,应按需选择内联或者外链。对于访问少、样式和脚本复用少的页面,可以考虑使用内联样式从而减少 HTTP 请求。但如果页面访问频繁,样式脚本在多个页面经常复用,使用外链则是最优选择。

无论如何,需要避免使用 @import 来导入样式。

而图像也是一样,高级浏览器支持将图像数据直接 base64 编码在 src 属性里,必要时可直接在 HTML 里输出图片数据。

减少iframe

iframe 本身有许多优点,比如可以并行下载脚本,适合加载慢内容(如广告),同时浏览器可以对其进行安全控制。

减少使用 iframe 的主要考虑是:iframe 会阻碍页面加载,同时也没有语义。

3 CSS

选择器

选择器效率排行如下:

  1. ID选择器
  2. 类选择器
  3. 标签选择器
  4. 相邻选择器
  5. 子选择器
  6. 后代选择器
  7. 通配符选择器
  8. 属性选择器
  9. 伪类选择器

效率与优先级并不是对等关系,优先级高的不一定效率高。如 #id.class 合用比 单个 #id 的优先级高,但效率却比值慢。

选择器书写建议是:

  1. 避免使用通配符
  2. 不使用标签名或类名修饰ID规则:如果规则使用ID选择器作为关键选择器,不要给规则添加标签名。因为ID本身就是唯一的,添加标签名会不必要地降低匹配效率
  3. 不使用标签名修饰类:相较于标签,类更具独特性
  4. 尽量选择最具体的方式:造成低效的最简单粗暴的原因就是在标签上使用太多规则。给元素添加类可以更快细分到类方式,可以减少规则去匹配标签的时间
  5. 关于后代选择器和子选择器:避免使用后代选择器,非要用的话建议用子选择器代替,但子选择器也要慎用,标签规则永远不要包含子选择器
  6. 利用可继承性:没必要在一般内容上声明样式

避免滤镜、表达式、Hack

效率低。

Sprites

合并图片可减少 HTTP 请求。其他建议有:

  1. Sprite 中水平排列图片,垂直排列会增加文件大小
  2. Sprite 中把颜色较近的组合在一起可以降低颜色数,理想状况是低于256色以便适用PNG8格式
  3. 不要在Spirite的图像中间留有较大空隙。这虽然不大会增加文件大小,但对于用户代理来说它需要更少的内存来把图片解压为像素地图。100×100的图片为1万像素,1000×1000就是100万像素

使用3D动画

使用 transform: translate3d 等可加速 GPU 渲染。

4 JavaScript

避免重排

渲染中可能存在的高成本操作:

  1. 修改、增加、删除DOM节点
  2. 移动DOM位置或者动画效果
  3. CSS样式修改(重绘比重排好些)
  4. 调整窗口大小,或者滚动时有绝对定位、fixed 背景以及动画
  5. 修改页面默认字体

浏览器一般会缓存Render Tree的更新渲染,但以下情况除外:

  1. 调整窗口大小和修改页面默认字体
  2. client/offset/scroll
  3. getComputedStyle() currentStyle

优化建议:

  1. 修改 className 而非 style
  2. 离线 DOM 后修改,如 documentFragment 或者 display:none 后再调整样式
  3. 缓存属性值
  4. 动画使用 absolute/fixed
  5. 不使用 table 布局(牵一发动全身)
  6. 修改层级比较低的 DOM

事件委托

将多个节点上的事件放到其父节点(经典案例:将 li 上的事件绑定到 ul 上)。

内存管理

合理释放和缓存内存。如缓存复用的属性,接触对象引用等。

5 资源

压缩大小

压缩样式、脚本、图像等资源的大小。

针对图像资源,可从预览小图、格式选择等多角度优化。

懒加载

如图像的懒加载(滚动到显示区域后才加载)等。

预加载

针对之后会用到的资源提前加载。

5 客户端

localStorage 缓存

相比 cookies,localStorage 存储容量更大。可以将一些静态资源(如 jQuery库)等缓存。

强迫症的 Mac 设置指南

如何配置一个高效的 Mac 工作环境

Table of Contents

  1. OS X
  2. 常用工具
  3. 开发工具

一直想写这么一篇文章,把我从同事那里学到的经验分享出来。市面上有很多类似的文章,写得都非常好,让我受益匪浅。不过我还是有一些自己总结出来的经验想要分享。

在工作中,我一般会在 1 到 10 人的团队中,经常会结对编程,即两个人共用一台 Mac 工作,因此也经常会把 Mac 外接一个大显示器、鼠标和键盘。我的常用开发平台有 Java、Ruby、Node.js、Web 等,使用 JetBrains 的开发工具,比如 IntelliJ IDEA、RubyMine、WebStorm 等。

我深知自己的知识有限,所以写下本文以便和大家切磋交流。同时更有效率的方法和更好的工具也在不断涌现,我也贪心的希望把更好的方法和工具都收集更到到这里,我会不断更新本文,让它尽量不过时。最新内容请访问:https://github.com/macdao/ocds-guide-to-setting-up-mac。欢迎通过 GitHub 的Issues或者直接Pull Requests方式来分享你的经验。期待你的反馈。

我认为“一个高效的 Mac 工作环境”有以下几个特点:

  • 自动化

    举个例子。手动安装一个应用,需要1)打开浏览器,2)搜索应用的名字,3)打开应用网站,4)寻找下载链接和安装方法,5)下载并等待下载完成,6)安装下载文件,7)可能还有后续的安装步骤。而自动化安装一个应用,只需要1)打开终端工具,2)敲入安装命令,3)等待完成这几个步骤。

    自动化可以大大简化操作,提高效率。

  • 统一

    我经常结对编程,偶尔会遇到快捷键不一样,命令不同等问题。我强烈建议,至少在一个团队中,大家尽量使用相同的快捷键、命令等环境。(我记得有个实践就是这个,可是我一直没找到该实践的名字和出处,求告诉)

  • 够用

    够用就好,如果系统本身已经满足了我的需求,我不会再使用第三方工具。

  • 效率

    效率,一切都是为了效率。

本文对于第三方应用如何安装和使用只有最简单的介绍,具体还请参考官方网站和相关文档。

有些章节标题标注了[OCD],意思是这些章节带有我强烈的个人色彩,如果你跟我臭味相投,欢迎借鉴,如果你并不认同,请忽略掉好了。

PS:虽然本文名为“强迫症”,但其实并不是真正意义上的强迫症,真正意义上的强迫症是一种会对患者的日常生活产生负面影响的疾病。

1. OS X

本节介绍操作系统本身的一些设置。

功能键

默认情况下,F1-F12 都是特殊功能,比如调节屏幕亮度。而当你需要键入 F1-F12 时(比如在使用 IntelliJ IDEA 的快捷键时),需要同时按住 Fn。这对于开发人员来说是非常不方便的。

把 F1-F12 改成标准功能键:选择System Preferences > Keyboard,在Keyboard标签页中选中Use all F1, F2, etc. keys as standard function keys

全键盘控制

当你在 Sublime Text 里关闭文件时,可能会遇到这样的对话框:

dialog-box-without-all-controls

注意这个Save按钮跟其他两个按钮不太一样,它的底色是蓝的。这种按钮被称为默认按钮,除了用鼠标点击触发外,还可以通过回车键触发。

那么问题来了,如果你不想保存,想点击Don't Save,是不是只能用鼠标点击了呢?

并不是这样:选择System Preferences > Keyboard,在Shortcuts标签页中选择All controls;或者使用快捷键⌃F7。之后这个对话框会变成这样:

dialog-box-with-all-controls

这个Don't Save按钮有了一圈蓝边,这个意味着你可以通过空格键触发。不仅如此,你还可以用Tab键把蓝边转移到其他按钮,来实现全键盘控制。

除了All controls这个方法,你还可以用⌘⌫来选择Don't Save⌘⌫的作用是在包含“删除”或“不存储”按钮的对话框中选择“删除”或“不存储”。

除了上述两个办法之外,居然还有个方法!就是按⌘D!据说是因为按⌘+按钮的大写首字母可以触发该按钮。可是!我按了⌘C⌘S想取消和保存都没用!但是⌘D真的有用!如果仅仅是这也就算了,可是我又手贱试了下 TextEdit,在关闭未保存的文件时弹出的对话框上有三个按钮DeleteCancelSave。然而⌘D⌘C都没用,但是!⌘S可以保存!我完全不能理解!我整个人几乎都是崩溃的,只好以咆哮体写下这段文字。如果谁能解释请务必告诉我,必有重谢!

⌘C不能用应该是因为它绑定到了复制功能;而⌘D不能用因为它的作用是从“打开”对话框或“存储”对话框中选择“桌面”文件夹。

在这个对话框上,你可以用Esc来执行Cancel操作。

Spotlight 快捷键

中文版 OS X 的 Spotlight 的快捷键是⌃Space。这个快捷键有一些问题:

  • JetBrains 的 IDE,比如 IntelliJ IDEA、WebStorm 等都使用⌃Space作为自动完成这个最常用功能的快捷键。我不建议更改 IDE 的快捷键,而建议更改 Spotlight 的快捷键。
  • 对于没有添加中文输入法的 Mac 来说,Spotlight 的快捷键是⌘Space。英语国家的人都是这样的。所以我建议把 Spotlight 的快捷键设置为⌘Space,跟他们一致。

输入法快捷键

一般来说切换输入法的快捷键是⌘Space。由于我建议把 Spotlight 的快捷键设置为⌘Space,所以我建议把切换输入法的快捷键设置为⌥Space

其他快捷键

让双手尽量多的键盘和快捷键,少使用鼠标和触摸板,可以大大提高效率。

设置 Trackpad 轻点来点按

默认情况下按下触摸板才是点按(click)。我喜欢设置成用轻点作为点按:

选择System Preferences > Trackpad,在Point & Click标签页中选中Tap to click

语音

OS X 自带了语音功能,可以用say命令让 Mac 开口说话:

say hello

可以和&&或者;配合使用来提示你某任务已经完成:

brew update && brew upgrade && brew cleanup ; say mission complete

通过命令行来听取发音还是有点麻烦。其实我们几乎可以在任何地方选中单词,然后使用快捷键⌥+ESC发音。仅仅需要这样设置一下:选择System Preferences > Dictation & Speech,在Text to Speech标签页中选中Speak selected text when the key is pressed

词典

OS X 自带了词典(Dictionary)。你几乎可以在任何应用中通过三指轻拍触摸板来现实对应单词的释义。

也可以打开 Dictionary 应用来查找单词。

可以在 Dictionary 应用中添加英汉汉英词典。

Dock Position

默认 Dock 在屏幕下方。我们的屏幕一般都是 16:10,Dock 在屏幕下方的话会占据本来就不大的垂直空间。建议把 Dock 放到左边或者右边。

更改 Caps Lock 键为 Control 键

我经常用到Control键,但这个键在键盘的左下角,很难按到。同时我发现我很少使用Caps Lock键,我一般会用Shift键加字母来输入大写字母,或者先输入小写再(通过快捷键)转换成大写。

基于以上原因,我把Caps Lock键的功能改成了Control键。很多同事也都这么做的,可能是受到HHKB 的影响。

设置方法:选择System Preferences > Keyboard,在Keyboard标签页中点击Modifier Keys...按钮,在弹出的窗口中,把Caps Lock (⇪) Key:对应的选项改成⌃ Control

Remove all Dock icons[OCD]

本条目对于强迫症适用。

默认情况下 Dock 被一堆系统自带的应用占据着,而其中大部分我都很少使用,当我打开几个常用应用后,Dock 上会有很多图标,每个图标都会被挤得很小。所以我会把所有 Dock 上固定的图标都删掉,这样一来 Dock 上只有我打开的应用。

PS:Finder 图标是删不掉的。

重置 Launchpad 上图标位置[OCD]

本条目对于强迫症适用。

新的应用被安装后,经常会跑到 Launchpad 的第一屏,所以它们的位置跟安装的顺序有关系,而我更希望它们可以按照某种更加稳定的顺序排列,比如按照系统默认的顺序:

defaults write com.apple.dock ResetLaunchPad -bool true; killall Dock

在默认顺序中,Launchpad 第一屏只有 Apple 自家应用。

2. 常用工具

本节介绍一些常用的,跟开发没有直接关系的第三方应用及其设置。

Homebrew

包管理工具,官方称之为The missing package manager for OS X

安装步骤:先打开 Terminal 应用,输入:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

有了 brew 以后,要下载工具,比如 MySQL、Gradle、Maven、Node.js 等工具,就不需要去网上下载了,只要一行命令就能搞定:

brew install mysql gradle maven node

PS:安装 brew 的时候会自动下载和安装 Apple 的 Command Line Tools。

brew 的替代品有 MacPorts,现在基本没人用它。

Homebrew Cask

brew-cask 允许你使用命令行安装 OS X 应用。比如你可以这样安装 Chrome:brew cask install google-chrome。还有 Evernote、Skype、Sublime Text、VirtualBox 等都可以用 brew-cask 安装。

brew-cask 是社区驱动的,如果你发现 brew-cask 上的应用不是最新版本,或者缺少你某个应用,你可以自己提交 pull request。

安装:

brew install caskroom/cask/brew-cask

应用也可以通过 App Store 安装,而且有些应用只能通过 App Store 安装,比如 Xcode 等一些 Apple 的应用。App Store 没有对应的命令行工具,还需要 Apple ID。倒是更新起来很方便。

几乎所有常用的应用都可以通过 brew-cask 安装,而且是从应用的官网上下载,所以你要安装新的应用时,建议用 brew-cask 安装。如果你不知道应用在 brew-cask 中的 ID,可以先用brew cask search命令搜索。

iTerm2

iTerm2 是最常用的终端应用,是 Terminal 应用的替代品。提供了诸如Split Panes一群实用特性。它默认的黑色背景让我毫不犹豫的抛弃了 Terminal。

安装:

brew cask install iterm2

感谢 brew-cask,我们可以通过命令行自动安装 iTerm2 了。

在终端里,除了可以用⌃E等快捷键(详见其他快捷键)之外,还可以使用⌥B⌥F等快捷键(具体可以参考这里)。前提是这样设置一下:

选择Iterm菜单 > Preferences > Profiles,选择你在使用的 Profile(默认是Default),在Keys标签页中把Left option (⌥) key acts asRight option (⌥) key acts as都设置成+ESC

在打开新的窗口/标签页的时候,默认情况下新窗口总是 HOME 目录,还需要我每次敲命令才能进入工作目录。如果想要这个新窗口在打开的时候就自动进入工作目录,需要如下设置:

选择Iterm菜单 > Preferences > Profiles,选择你在使用的 Profile(默认是Default),在General标签页中的Working Directory部分中选择Reuse previous seesion's directory

至此,Terminal 应用已经出色的完成了其历史使命。后面命令行就交给 iTerm2 啦。

在 iTerm2 中双击会自动选中对应的词,三击会选中对应的整行。选中的内容会自动进入剪贴板,不需要再按⌘C复制。

Oh My Zsh

默认的 Bash 是黑白的,没有色彩。而 Oh My Zsh 可以带你进入彩色时代。Oh My Zsh 同时提供一套插件和工具,可以简化命令行操作。后面我们会看到很多介绍,你会看到我爱死这家伙了。

安装:

sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

目前我使用的插件有:git z sublime history rbenv bundler rake

Oh My Zsh 使用了 Z shell(zsh),一个和 Bash 相似的 Shell,而非 Bash。

在 Z shell 中,~/.zshrc是最重要的配置文件。Oh My Zsh 在安装的时候会把当前环境的$PATH写入~/.zshrc中。这并不是我期望的行为,因为使用了 brew,我们基本不再需要去定制$PATH,而 Oh My Zsh 提供的默认$PATH$HOME/bin:/usr/local/bin:$PATH是非常合适的一个值,它把$HOME/bin加入了$PATH,可以让我们把自己用的脚本放到$HOME/bin下。

所以建议把~/.zshrc重置:

cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc

Oh My Zsh 还有很多有价值的插件

替代品有 Oh My Fish,使用了 Fishshell 作为基础。

Git 常用别名

几乎每个人都会使用一些方法比如 Git 别名来提高效率,几乎所有人都会把使用git st来代替git status。然而这需要手动设置,每个人也都不完全一样。

Oh My Zsh 提供了一套系统别名(alias),来达到相同的功能。比如gst作为git status的别名。而且 Git 插件是 Oh My Zsh 默认启用的,相当于你使用了 Oh My Zsh,你就拥有了一套高效率的别名,而且还是全球通用的。是不是棒棒哒?下面是一些我常用的别名:

Alias Command
gapa git add --patch
gc! git commit -v --amend
gcl git clone --recursive
gclean git reset --hard && git clean -dfx
gcm git checkout master
gcmsg git commit -m
gco git checkout
gd git diff
gdca git diff --cached
glola git log --graph --pretty = format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all
gp git push
grbc git rebase --continue
gst git status
gup git pull --rebase
gwip git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit -m "--wip--"

完整列表请参考:https://github.com/robbyrussell/oh-my-zsh/wiki/Plugin:git

Scroll Reverser

当你在浏览一个很长的网页时,你看完了当前显示的内容,想要看后续的内容,你可以在 Trackpad 上双指上滑,或者鼠标滚轮向上滚动。这是被称作“自然”的滚动方向。

然而在 Windows 里鼠标滚动的行为是相反的:鼠标滚轮向下滚动才会让浏览器显示后续的内容,向上滚动会达到页面的顶部。你可以在 OS X 的系统偏好设置里修改(选择System Preferences > Trackpad,在Scroll & Zoom标签页中不选中Scroll direction: natural),但是这样会同时改变鼠标滚轮的方向和 Trackpad 的方向。

要想只改变鼠标滚轮的方向,而保持 Trackpad 依旧是“自然”的,我们需要 Scroll Reverser:

brew cask install scroll-reverser

PS:这货会让三指点击失效

ShiftIt

原生 OS X 下只能手动调整窗口大小,所以我们需要窗口管理工具。我用过很多窗口管理工具,可惜大部分工具都存在快捷键冲突的问题(对我来说主要是 IntelliJ IDEA)。ShiftIt 是少见的没有冲突的窗口管理工具:

brew cask install shiftit

PS:ShiftIt的旧版本需要安装 X11,最新版本已经修正了这个问题。

替代者有 SizeUp,主要快捷键和 ShiftIt 相同。

当然如果喜欢 hacking,Slate 是个不错的 hackable 的窗口管理工具。配置可以参照http://thume.ca/howto/2012/11/19/using-slate/

Sublime Text 2

安装:

brew cask install sublime-text

在命令行中指定使用 Sublime Text 打开某文件,是一个非常常用的功能,一般我们会按照 OS X Command Line 中所说执行 ln -s "/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl" ~/bin/subl 来增加subl链接。但是如果你用 brew-cask 安装的话,恭喜你,你不需要运行这个命令,因为 brew-cask 自动帮你做了这件事情。而且你卸载 Sublime Text 的时候 brew-cask 会自动删掉这个链接。

同时 Oh My Zsh 也提供了 Sublime Text 插件,叫做sublime。参考:https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/sublime,这个插件和通过 brew-cask 安装的 Sublime Text 完美兼容。

替代品有 Atom、TextMate、Sublime Text 3 等,跟 Sublime Text 2 一样,用 brew-cask 安装的话命令行工具会被自动加入$PATH

MacDown

MacDown 是 Markdown 编辑器。由于 Mou 一直不支持代码高亮,我就转向了 MacDown。完美支持GFM

我特别喜欢 Markdown,我用 Makdown 来写文章(包括本文),写幻灯片(reveal.js)。Markdown 可以让我专注于内容本身,而无需花精力在排版和样式上。

安装:

brew cask install macdown

z

在打开终端后,你是怎么进入项目的工作目录?是cd xxx⌃R还是用别名?

z 工具可以帮你快速进入目录。比如在我的 Mac 上运行z cask就会进入/usr/local/Library/Taps/caskroom/homebrew-cask/Casks目录。

这货的安装非常方便,甚至都不需要下载任何东西,因为它已经整合在了 Oh My Zsh 中。编辑~/.zshrc文件,在plugins=(git)这行中加上z变成plugins=(git z),然后运行source ~/.zshrc重新加载配置文件,就可以使用 z 了。

替代品有 autojump。autojump 需要使用 brew 安装。

Vimium

Vimium 是一个 Google Chrome 扩展,让你可以纯键盘操作 Chrome,把你的 Chrome 变成“黑客的浏览器”。

安装方法请参考官方网站。

其他浏览器也有类似的工具,比如 FireFox 的 KeySnail

LastPass

LastPass 是管理密码的工具,支持二次验证,提供所有浏览器插件以及 Mac 桌面版本。

最重要的是,它提供 命令行 的版本,可以直接通过 brew 安装

brew install lastpass-cli --with-pinentry

之后,只需要登陆:

lpass login you@email.com

就可以拷贝密码或者集成到其他命令中了:

lpass show --password gmail.com -c

SourceTree

SourceTree 是 Atlassian 公司出品的一款优秀的 Git 图形化客户端。如果你发现命令行无法满足你的要求,可以试试 SourceTree。

安装:

brew cask install sourcetree

用 brew-cask 安装会自动增加命令行工具stree$PATH里。在命令行中输入stree可以快速用 SourceTree 打开当前 Git 仓库。详细用法请参见stree --help

CheatSheet

CheatSheet 能够显示当前程序的快捷键列表,默认的快捷键是长按

CheatSheet

安装:

brew cask install cheatsheet

3. 开发工具

Java

现在 OS X 都不会自带 JDK 了,所以进行 Java 开发的话,需要下载 JDK。在 brew-cask 之前,我们需要从 https://developer.apple.com/downloads/ 或者 Oracle 网站上下载。还有更麻烦的--卸载 JDK 和升级 JDK。

JDK 安装文件是 pkg 格式,卸载和.app不一样,且没有自动卸载方式。

而 brew-cask 提供了自动安装和卸载功能,能够自动从官网上下载并安装 JDK 8。

brew cask install java

如果你需要安装 JDK 7 或者 JDK 6,可以使用homebrew-cask-versions

brew tap caskroom/versions
brew cask install java6

在 OS X 上,你可以同时安装多个版本的 JDK。你可以通过命令/usr/libexec/java_home -V来查看安装了哪几个 JDK。

那问题来了,当你运行java或者 Java 程序时使用的是哪个 JDK 呢?在 OS X 下,java也就是/usr/bin/java在默认情况下指向的是已经安装的最新版本。但是你可以设置环境变量JAVA_HOME来更改其指向:

$ java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
$ JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home java -version
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-466.1-11M4716)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-466.1, mixed mode)

其中JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home可以用JAVA_HOME=`/usr/libexec/java_home -v 1.6`这种更加通用的方式代替。

jEnv

也可以使用 jEnv 来管理不同版本的 JDK,这个工具跟 rbenv 类似,通过当前目录下的.java-version来决定使用哪个 JDK。jEnv 也可以用 brew 安装。不过要使用 jEnv 要有几个问题:

  • 需要手动把eval "$(jenv init -)"加入 profile,没有 Oh My Zsh 插件。这点是我非常反感的。

    可以把eval "$(jenv init -)"加入~/.zlogin,这样可以避免修改~/.zshrc

  • 需要手动添加 JDK,不会自动采集系统 JDK。跟 Ruby 不同,OS X 已经提供/usr/libexec/java_home工具来管理安装的 JDK。
  • 需要 jenv rehash。这个是跟 rbenv 学的。

所以我建议不要使用 jEnv。

Java[OCD]

作为一个强迫症患者,每当我看到 Java 的错误写法就想纠正过来。

当指编程语言时,Java 的正确写法是首字母大写,其余小写。其他写法比如JAVAjava都是不对的。

在其他一些地方会使用小写的java

  • java命令
  • 原文件Main.java
  • 包名java.lang

只有在全大写的标题里使用JAVA或者环境变量JAVA_HOME

IntelliJ IDEA

Java 开发必备工具 IntelliJ IDEA。可以安装 Ultimate Edition:

brew cask install intellij-idea

也可以安装开源免费的 Community Edition:

brew cask install intellij-idea-ce

IntelliJ IDEA 有几套内建的快捷键方案(Keymap)。其中适用于 OS X 的有Mac OS XMac OS X 10.5+两种。区别是:

  • Mac OS X方案和其他平台上的快捷键类似,
  • Mac OS X 10.5+更加符合 OS X 常用的快捷键。

一个团队使用不同的快捷键会严重影响效率。可以用View | Quick Switch Scheme⌃ Back Quote)快速切换 Keymap。

如果可以选择的话,我建议使用Mac OS X方案。因为我经常遇到使用 Windows 的客户,而 Windows 平台上的快捷键和Mac OS X方案类似。

可以从 IDEA 的Help > Default Keymap Reference打开快捷键的参考手册。不过从这里打开的是Mac OS X 10.5+方案的,而Mac OS X方案的可以从这里找到:http://www.basrikahveci.com/static/ij_keymap_mac.pdf

rbenv

人人都需要一个 Ruby 版本管理工具。rbenv 就是这样一个轻量级工具,它可以通过 brew 安装。

安装:

brew install rbenv ruby-build

然后在~/.zshrc中加上rbenv插件。否则你需要手动添加eval "$(rbenv init -)"~/zshrc或者~/.zprofile文件里。

有时候项目会依赖一些奇怪的版本号,比如ruby-2.1.0,这个时候你需要 rbenv-aliases 帮忙:

brew install rbenv-aliases

替代品有 RVM、chruby。因为 RVM 不能通过 brew 安装,并且安装的时候会没有节操的修改一堆文件,所以被我早早的弃用了。chruby 也是一个轻量级工具,而且可以完美的和 Oh My Zsh 集成在一起,我看到有些生产环境在用它。

Ruby 常用别名

几乎所有 Ruby 开发人员都会把bi作为bundle install的别名。Oh My Zsh 提供builder插件,这个插件提供了一套别名,比如bibe。同时还能让你在运行一些常用 gem 的时候直接输入rspec,不需要be rspec这样了。具体包括哪些命令请参考这里

Z shell 对于[]符号有特殊的处理,所以在运行rake task[parameter]的时候会报错,你需要改成rake task\[parameter\]或者noglob rake task[parameter]。然而 Oh My Zsh 已经看穿这一切,自带的 rake 插件已经解决了这个问题:brake task[parameter]

添加插件的时候注意把rake放到bundler后面,例如这样:

plugins=(git z sublime history rbenv bundler rake)

参考资料

redis info命令详解

以一种易于解释(parse)且易于阅读的格式,返回关于 Redis 服务器的各种信息和统计数值。

通过给定可选的参数 section ,可以让命令只返回某一部分的信息:

  • server : 一般 Redis 服务器信息,包含以下域:

    • redis_version : Redis 服务器版本
    • redis_git_sha1 : Git SHA1
    • redis_git_dirty : Git dirty flag
    • os : Redis 服务器的宿主操作系统
    • arch_bits : 架构(32 或 64 位)
    • multiplexing_api : Redis 所使用的事件处理机制
    • gcc_version : 编译 Redis 时所使用的 GCC 版本
    • process_id : 服务器进程的 PID
    • run_id : Redis 服务器的随机标识符(用于 Sentinel 和集群)
    • tcp_port : TCP/IP 监听端口
    • uptime_in_seconds : 自 Redis 服务器启动以来,经过的秒数
    • uptime_in_days : 自 Redis 服务器启动以来,经过的天数
    • lru_clock : 以分钟为单位进行自增的时钟,用于 LRU 管理
  • clients : 已连接客户端信息,包含以下域:

    • connected_clients : 已连接客户端的数量(不包括通过从属服务器连接的客户端)
    • client_longest_output_list : 当前连接的客户端当中,最长的输出列表
    • client_longest_input_buf : 当前连接的客户端当中,最大输入缓存
    • blocked_clients : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量
  • memory : 内存信息,包含以下域:

    • used_memory : 由 Redis 分配器分配的内存总量,以字节(byte)为单位
    • used_memory_human : 以人类可读的格式返回 Redis 分配的内存总量
    • used_memory_rss : 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 topps 等命令的输出一致。
    • used_memory_peak : Redis 的内存消耗峰值(以字节为单位)
    • used_memory_peak_human : 以人类可读的格式返回 Redis 的内存消耗峰值
    • used_memory_lua : Lua 引擎所使用的内存大小(以字节为单位)
    • mem_fragmentation_ratio : used_memory_rssused_memory 之间的比率
    • mem_allocator : 在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。
    在理想情况下, used_memory_rss 的值应该只比 used_memory 稍微高一点儿。
    rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。
    内存碎片的比率可以通过 mem_fragmentation_ratio 的值看出。
    used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。

    Because Redis does not have control over how its allocations are mapped to memory pages, high used_memory_rss is often the result of a spike in memory usage.

    当 Redis 释放内存时,分配器可能会,也可能不会,将内存返还给操作系统。
    如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 used_memory 的值可能和操作系统显示的 Redis 内存占用并不一致。
    查看 used_memory_peak 的值可以验证这种情况是否发生。
  • persistence : RDBAOF 的相关信息

  • stats : 一般统计信息

  • replication : 主/从复制信息

  • cpu : CPU 计算量统计信息

  • commandstats : Redis 命令统计信息

  • cluster : Redis 集群信息

  • keyspace : 数据库相关的统计信息

除上面给出的这些值以外,参数还可以是下面这两个:

  • all : 返回所有信息
  • default : 返回默认选择的信息

当不带参数直接调用 INFO 命令时,使用 default 作为默认参数。

不同版本的 Redis 可能对返回的一些域进行了增加或删减。

因此,一个健壮的客户端程序在对 INFO 命令的输出进行分析时,应该能够跳过不认识的域,并且妥善地处理丢失不见的域。

可用版本:
>= 1.0.0
时间复杂度:
O(1)
返回值:
具体请参见下面的测试代码。
redis> INFO
# Server
redis_version:2.5.9
redis_git_sha1:473f3090
redis_git_dirty:0
os:Linux 3.3.7-1-ARCH i686
arch_bits:32
multiplexing_api:epoll
gcc_version:4.7.0
process_id:8104
run_id:bc9e20c6f0aac67d0d396ab950940ae4d1479ad1
tcp_port:6379
uptime_in_seconds:7
uptime_in_days:0
lru_clock:1680564

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:439304
used_memory_human:429.01K
used_memory_rss:13897728
used_memory_peak:401776
used_memory_peak_human:392.36K
used_memory_lua:20480
mem_fragmentation_ratio:31.64
mem_allocator:jemalloc-3.0.0

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1338011402
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1

# Stats
total_connections_received:1
total_commands_processed:0
instantaneous_ops_per_sec:0
rejected_connections:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0

# Replication
role:master
connected_slaves:0

# CPU
used_cpu_sys:0.03
used_cpu_user:0.01
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

Win10开发必备:Visual Studio 2015正式版下载

7月21日凌晨消息,面向大众用户的Visual Studio 2015集成开发工具正式版免费试用版已经推出。本文帮大家汇总一下简体中文社区版、专业版以及企业版在线安装版以及ISO离线安装镜像下载地址。

Visual Studio Community 2015简体中文版(社区版,针对个人免费):

在线安装 || ISO镜像

镜像SHA1:1044F9F4E0EA1304AFECF6780BF599F1DA248DF8

Visual Studio Professional 2015简体中文版(专业版):

在线安装 || ISO镜像

镜像SHA1:629E7154E2695F08A3C692C0B3F6CE19DF6D3A72

Visual Studio Enterprise 2015简体中文版(企业版):

在线安装 || ISO镜像

镜像SHA1:4FFA1EE3E2D3337D3EDAE550A3583ABE9C426BEF

更多版本点此下载