月度归档:2016年09月

linux l2tp

yum install openswan xl2tpd ppp

/etc/ipsec.conf

config setup
	protostack=netkey
	dumpdir=/var/run/pluto/
	virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10
	nat_traversal=yes
	oe=off

 

/etc/ipsec.d/l2tp-psk.conf

conn L2TP-PSK-NAT
	rightsubnet=vhost:%priv
	also=L2TP-PSK-noNAT

conn L2TP-PSK-noNAT
	authby=secret
	pfs=no
	auto=add
	keyingtries=3
	rekey=no
	ikelifetime=8h
	keylife=1h
	type=transport
	left=HOST_IP
	leftprotoport=17/1701
	right=%any
	rightprotoport=17/%any
	dpddelay=40
	dpdtimeout=130
	dpdaction=clear
	leftnexthop=%defaultroute
	rightnexthop=%defaultroute

/etc/ipsec.secrets
HOST_IP %any: PSK "密钥"

/etc/xl2tpd/xl2tpd.conf

[global]
ipsec saref = yes
[lns default]
ip range = 192.168.0.200-192.168.0.254
local ip = 192.168.0.196
refuse chap = yes
refuse pap = yes
require authentication = yes
ppp debug = yes
pppoptfile = /etc/ppp/options
length bit = yes

/etc/sysctl.conf
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.default.rp_filter = 0

test

sysctl -p
service ipsec start

ipsec verify

rp_filter
echo 0 > /proc/sys/net/ipv4/conf/lo/rp_filter
echo 0 > /proc/sys/net/ipv4/conf/eth0/rp_filter

 

#network 参考(新手别完全照抄)。
*nat
:PREROUTING ACCEPT [39:3503]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A POSTROUTING -s 192.168.7.0/24 -o eth0 -j MASQUERADE
COMMIT
# Completed on Thu Jun 28 15:50:40 2012
# Generated by iptables-save v1.4.7 on Thu Jun 28 15:50:40 2012
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [121:13264]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 53 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 53 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 1194 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 1701 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 500 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 4500 -j ACCEPT-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -d 192.168.7.0/24 -j ACCEPT
-A FORWARD -s 192.168.7.0/24 -j ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Thu Jun 28 15:50:40 2012

Command:
iptables -t nat -A POSTROUTING -s 192.168.195.0/24 -o eth0 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.196.0/24 -o eth0 -j MASQUERADE

 

使用ipsec whack --status查看vpn的状态;

-----------------------------------------------------

windows 系统使用l2tp出现 809错误时处理方式:

微软官网推荐方法,新建注册表值
注: 修改后必需要重启电脑才能生效

Windows Registry Editor Version 5.00


[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\PolicyAgent]
"AssumeUDPEncapsulationContextOnSendRule"=dword:00000002

 

--------------------------------------------------------------------------------------------------

参考2:

一、/etc/ipsec.conf

version 2.0
config setup
    nat_traversal=yes
    virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12
    oe=off
    protostack=netkey

conn L2TP-PSK-NAT
    rightsubnet=vhost:%priv
    also=L2TP-PSK-noNAT

conn L2TP-PSK-noNAT
    authby=secret
    pfs=no
    auto=add
    keyingtries=3
    rekey=no
    ikelifetime=8h
    keylife=1h
    type=transport
    left=YOUR.SERVER.IP.ADDRESS
    leftprotoport=17/1701
    right=%any
    rightprotoport=17/%any

 

二、/etc/ipsec.secrets:

YOUR.SERVER.IP.ADDRESS   %any:  PSK "YourSharedSecret"

(「YOUR.SERVER.IP.ADDRESS」这部分换成你的服务器的 IP 地址,把「YourSharedSecret」部分换成随便一个字串,例如你喜欢的一句话,等等。)

三、运行以下命令:

for each in /proc/sys/net/ipv4/conf/*
do
    echo 0 > $each/accept_redirects
    echo 0 > $each/send_redirects
done

四、检查一下 IPSec 能否正常工作:

sudo ipsec verify

如果在结果中看到「Opportunistic Encryption Support」被禁用了,没关系,其他项 OK 即可。

五、重启 openswan:

sudo /etc/init.d/ipsec restart

六、安装 L2TP

运行以下命令:

sudo aptitude install xl2tpd

八、用文字编辑器打开 /etc/xl2tpd/xl2tpd.conf,改成这样:

[global]
ipsec saref = yes

[lns default]
ip range = 10.1.2.2-10.1.2.255
local ip = 10.1.2.1
;require chap = yes
refuse chap = yes
refuse pap = yes
require authentication = yes
ppp debug = yes
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes

这里要注意的是 ip range 一项里的 IP 地址不能和你正在用的 IP 地址重合,也不可与网络上的其他 IP 地址冲突。

九、安装 ppp。这是用来管理 VPN 用户的。

sudo aptitude install ppp

十、检查一下 /etc/ppp 目录里有没有 options.xl2tpd 这个文件,没有的话就建一个,文件内容如下:

require-mschap-v2
ms-dns 208.67.222.222
ms-dns 208.67.220.220
asyncmap 0
auth
crtscts
lock
hide-password
modem
debug
name l2tpd
proxyarp
lcp-echo-interval 30
lcp-echo-failure 4

注意 ms-dns 可更换为你最近服务地址。

十一、添加 VPN 用户。
用文字编辑器打开 /etc/ppp/chap-secrets:

# user      server      password            ip
test        l2tpd       testpassword        *

如果你之前设置过 PPTP VPN,chap-secrets 文件里可能已经有了其他用户的列表。
你只要把 test l2tpd testpassword * 这样加到后面即可。

十二、重启 xl2tpd:

sudo /etc/init.d/xl2tpd restart

 

参考:
https://segmentfault.com/a/1190000000646294  (配置)

lucene

lucene3.0中BooleanQuery 实现与或的复合搜索 .
BooleanClause用于表示布尔查询子句关系的类,


括:

BooleanClause.Occur.MUST,

BooleanClause.Occur.MUST_NOT,

BooleanClause.Occur.SHOULD。

 

必须包含,不能包含,可以包含三种.有以下6种组合: 
 
1.MUST和MUST:取得连个查询子句的交集。 
2.MUST和MUST_NOT:表示查询结果中不能包含MUST_NOT所对应得查询子句的检索结果。 
3.SHOULD与MUST_NOT:连用时,功能同MUST和MUST_NOT。
4.SHOULD与MUST连用时,结果为MUST子句的检索结果,但是SHOULD可影响排序。
5.SHOULD与SHOULD:表示“或”关系,最终检索结果为所有检索子句的并集。
6.MUST_NOT和MUST_NOT:无意义,检索无结果。

...

构造出“与”的关系: bquery.Add(query, BooleanClause.Occur.MUST);

构造“或”关系:bquery.Add(query, BooleanClause.Occur.SHOULD);

构造“非”关系:bquery.Add(query, BooleanClause.Occur.MUST_NOT);

...

Field.Store.YES:存储字段值(未分词前的字段值) 

       Field.Store.NO:不存储,存储与索引没有关系 

       Field.Store.COMPRESS:压缩存储,用于长文本或二进制,但性能受损 



       Field.Index.ANALYZED:分词建索引 

       Field.Index.ANALYZED_NO_NORMS:分词建索引,但是Field的值不像通常那样被保存,而是只取一个byte,这样节约存储空间 

       Field.Index.NOT_ANALYZED:不分词且索引 

       Field.Index.NOT_ANALYZED_NO_NORMS:不分词建索引,Field的值去一个byte保存 



       TermVector表示文档的条目(由一个Document和Field定位)和它们在当前文档中所出现的次数 

       Field.TermVector.YES:为每个文档(Document)存储该字段的TermVector 

       Field.TermVector.NO:不存储TermVector 

       Field.TermVector.WITH_POSITIONS:存储位置 

       Field.TermVector.WITH_OFFSETS:存储偏移量 

       Field.TermVector.WITH_POSITIONS_OFFSETS:存储位置和偏移量

...

 Apache Lucene 几种分词系统

1、 StopAnalyzer

StopAnalyzer能过滤词汇中的特定字符串和词汇,并且完成大写转小写的功能。

2、 StandardAnalyzer

StandardAnalyzer根据空格和符号来完成分词,还可以完成数字、字母、E-mail地址、IP地址以及中文字符的分析处理,还可以支持过滤词表,用来代替StopAnalyzer能够实现的过滤功能。

3、 SimpleAnalyzer

SimpleAnalyzer具备基本西文字符词汇分析的分词器,处理词汇单元时,以非字母字符作为分割符号。分词器不能做词汇的过滤,之进行词汇的分析和分割。输出地词汇单元完成小写字符转换,去掉标点符号等分割符。

在全文检索系统开发中,通常用来支持西文符号的处理,不支持中文。由于不完成单词过滤功能,所以不需要过滤词库支持。词汇分割策略上简单,使用非英文字符作为分割符,不需要分词词库的支持。

4、 WhitespaceAnalyzer

WhitespaceAnalyzer使用空格作为间隔符的词汇分割分词器。处理词汇单元的时候,以空格字符作为分割符号。分词器不做词汇过滤,也不进行小写字符转换。

实际中可以用来支持特定环境下的西文符号的处理。由于不完成单词过滤和小写字符转换功能,也不需要过滤词库支持。词汇分割策略上简单使用非英文字符作为分割符,不需要分词词库支持。

5、 KeywordAnalyzer

KeywordAnalyzer把整个输入作为一个单独词汇单元,方便特殊类型的文本进行索引和检索。针对邮政编码,地址等文本信息使用关键词分词器进行索引项建立非常方便。

6、 CJKAnalyzer

CJKAnalyzer内部调用CJKTokenizer分词器,对中文进行分词,同时使用StopFilter过滤器完成过滤功能,可以实现中文的多元切分和停用词过滤。在Lucene3.0版本中已经弃用。

7、 ChineseAnalyzer

ChineseAnalyzer功能与StandardAnalyzer分析器在处理中文是基本一致,都是切分成单个的双字节中文字符。在Lucene3.0版本中已经弃用。

8、 PerFieldAnalyzerWrapper

PerFieldAnalyzerWrapper功能主要用在针对不同的Field采用不同的Analyzer的场合。比如对于文件名,需要使用KeywordAnalyzer,而对于文件内容只使用StandardAnalyzer就可以了。通过addAnalyzer()可以添加分类器。

9、 IKAnalyzer

实现了以词典为基础的正反向全切分,以及正反向最大匹配切分两种方法。IKAnalyzer是第三方实现的分词器,继承自Lucene的Analyzer类,针对中文文本进行处理。

10、JE-Analysis

JE-Analysis是Lucene的中文分词组件,需要下载。

11、 ICTCLAS4J

ictclas4j中文分词系统是sinboy在中科院张华平和刘群老师的研制的FreeICTCLAS的基础上完成的一个java开源分词项目,简化了原分词程序的复杂度,旨在为广大的中文分词爱好者一个更好的学习机会。

12、 Imdict-Chinese-Analyzer

imdict-chinese-analyzer 是 imdict智能词典 的智能中文分词模块,算法基于隐马尔科夫模型(Hidden Markov Model, HMM),是中国科学院计算技术研究所的ictclas中文分词程序的重新实现(基于Java),可以直接为lucene搜索引擎提供简体中文分词支持。

13、 Paoding Analysis

Paoding Analysis中文分词具有极 高效率 和 高扩展性。引入隐喻,采用完全的面向对象设计,构思先进。其效率比较高,在PIII 1G内存个人机器上,1秒可准确分词100万汉字。采用基于不限制个数的词典文件对文章进行有效切分,使能够将对词汇分类定义。能够对未知的词汇进行合理解析。

14、 MMSeg4J

mmseg4j 用 Chih-Hao Tsai 的 MMSeg 算法(http://technology.chtsai.org/mmseg/ )实现的中文分词器,并实现 lucene 的 analyzer 和 solr 的TokenizerFactory 以方便在Lucene和Solr中使用。 MMSeg 算法有两种分词方法:Simple和Complex,都是基于正向最大匹配。Complex 加了四个规则过虑。官方说:词语的正确识别率达到了 98.41%。mmseg4j 已经实现了这两种分词算法。

...

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Lucene.Net.Store;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.Documents;
using Lucene.Net.Search;
using Lucene.Net.QueryParsers;
using System.Diagnostics;

namespace LuceneNet.Web.Controllers {
    public class HomeController : Controller {
        public ActionResult Index() {
            ViewBag.Message = "欢迎使用 ASP.NET MVC!";
            return View();
        }
        public ActionResult About() {
            return View();
        }
        /// <summary>
        /// 添加索引
        /// </summary>
        /// <returns></returns>
        public ActionResult AddIndex() {
            //为索引存储目录
            string INDEX_STORE_PATH = Server.MapPath("~/SearchIndex");
#if DEBUG
            ///如果存在文件则删除(测试用)
            if (System.IO.Directory.Exists(INDEX_STORE_PATH)) {
                System.IO.Directory.Delete(INDEX_STORE_PATH, true);
            }
#endif
            Directory indexDirectory = FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH));
            Analyzer analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29);
            IndexWriter writer = null;

            try {
                //检查索引文件是否存在
                bool iscreate = !Lucene.Net.Index.IndexReader.IndexExists(indexDirectory);
                //如果索引文件不存在则创建索引文件,否则创建索引文件
                writer = new IndexWriter(indexDirectory, analyzer, iscreate, IndexWriter.MaxFieldLength.UNLIMITED);

                //开始添加索引
                foreach (var item in Get()) {
                    Document doc = new Document();
                    doc.Add(new Field("id", item.Id, Field.Store.YES, Field.Index.ANALYZED));//存储,不分词索引
                    doc.Add(new Field("classid", item.ClassId, Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,不分词索引
                    doc.Add(new Field("classname", item.ClassName, Field.Store.YES, Field.Index.ANALYZED));//存储,不分词索引
                    doc.Add(new Field("title", item.Title, Field.Store.YES, Field.Index.ANALYZED));//存储,分词索引
                    doc.Add(new Field("summary", item.Summary, Field.Store.YES, Field.Index.ANALYZED));//存储,分词索引
                    doc.Add(new Field("createtime", item.CreateTime.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));//存储,分词索引
                    writer.AddDocument(doc);
                }
                writer.Optimize();
            } catch (Exception) {
                throw;
            } finally {
                if (analyzer != null)
                    analyzer.Close();
                if (writer != null)
                    writer.Close();
                if (indexDirectory != null)
                    indexDirectory.Close();
            }
            return RedirectToAction("index");
        }
        /// <summary>
        /// 搜索
        /// </summary>
        /// <param name="k"></param>
        /// <param name="cid"></param>
        /// <returns></returns>
        public ActionResult Search(string k, string cid) {
            Stopwatch st = new Stopwatch();
            st.Start();//计时开始  
            //为索引存储目录
            string INDEX_STORE_PATH = Server.MapPath("~/SearchIndex");
            var ver = Lucene.Net.Util.Version.LUCENE_29;
            Directory indexDirectory = FSDirectory.Open(new System.IO.DirectoryInfo(INDEX_STORE_PATH));
            Analyzer analyzer = new StandardAnalyzer(ver);
            IndexSearcher searcher = null;
            List<Article> list;
            int recCount = 0;
            try {
                searcher = new IndexSearcher(indexDirectory, true);
                string[] fields = { "title", "summary" };
                BooleanQuery booleanQuery = new BooleanQuery();
                //多字段查询同时搜索title和summary
                MultiFieldQueryParser parser = new MultiFieldQueryParser(ver, fields, analyzer);
                Query query = parser.Parse(k);
                //Query query1 = new QueryParser(ver, "classid", analyzer).Parse("1");

                //TermQuery只能查询不分词的索引(Field.Index.NOT_ANALYZED)
                Query query1 = new TermQuery(new Term("id", "1"));
                //当classname为ANALYZED时搜不到
                // Query query2 = new TermQuery(new Term("classname", "体育新闻"));
                //只有当classname为NOT_ANALYZED才可以搜得到,
                //由此得出TermQuery只能查询不分词的索引(Field.Index.NOT_ANALYZED)的结论
                //但当id为ANALYZED时TermQuery却可以收的到,
                //当搜classname中包含“体”时即Query query2 = new TermQuery(new Term("classname", "体"));
                //当搜classname中包含“育”时即Query query2 = new TermQuery(new Term("classname", "育"));
                //可以搜得到。因此,由此得出,TermQuery搜的是最小单位,由此又得出Lucene是把“体育新闻”拆分成了"体/育/新/闻"四部分
                //听说Lucene分词是按空格分的,那么把“体育新闻”,改成“体育 新闻”后再重新生成索引是不是可以搜的到呢?
                //Query query2 = new TermQuery(new Term("classname", "体育"));
                //但是结果却是搜不到,纳闷...难道Lucene的分词不是这么分而是更复杂?
                //StandardAnalyzer看来是对中文分词不怎么好,当ClassName = "sports news"可以搜sports和news
                //StandardAnalyzer只支持英文的空格分词
                Query query2 = new TermQuery(new Term("classname", k));
                //关于QueryParser的搜索当k为Empty或null时会报错注意处理
                //Query query3 = new QueryParser(ver, "title", analyzer).Parse(k);
                Query query3 = new QueryParser(ver, "title", analyzer).Parse(k);

                Query query4 = new PrefixQuery(new Term("classname", k));
                Query query5 = new QueryParser(ver, "title", analyzer).Parse(k);
                TermRangeQuery query6 = new TermRangeQuery("createtime", "2012-1-3", "2012-5-3", true, true);

                //booleanQuery.Add(query1, BooleanClause.Occur.MUST);
                //booleanQuery.Add(query2, BooleanClause.Occur.MUST);
                //booleanQuery.Add(query3, BooleanClause.Occur.MUST);
                booleanQuery.Add(query4, BooleanClause.Occur.MUST);
                //booleanQuery.Add(query5, BooleanClause.Occur.MUST);
                booleanQuery.Add(query6, BooleanClause.Occur.MUST);
                TopDocs ts = searcher.Search(booleanQuery, null, 100);//执行搜索,获取查询结果集对象

                recCount = ts.totalHits;//获取命中的文档个数
                ScoreDoc[] hits = ts.scoreDocs;//获取命中的文档信息对象
                st.Stop();//计时停止
                ViewBag.EvenTime = string.Format("{0}毫秒,生成的Query语句:{1}", st.ElapsedMilliseconds, booleanQuery.ToString());
                ViewBag.Count = recCount;
                list = new List<Article>();
                foreach (var item in hits) {
                    list.Add(new Article()
                    {
                        Id = searcher.Doc(item.doc).Get("id"),
                        ClassId = searcher.Doc(item.doc).Get("classid"),
                        ClassName = searcher.Doc(item.doc).Get("classname"),
                        Title = searcher.Doc(item.doc).Get("title"),
                        Summary = searcher.Doc(item.doc).Get("summary"),
                        Score = item.score.ToString(),
                        CreateTime = DateTime.Parse(searcher.Doc(item.doc).Get("createtime"))
                    });
                }
            } catch (Exception) {
                throw;
            } finally {
                if (searcher != null) {
                    searcher.Close();
                }
            }

            return View(list);
        }

        public List<Article> Get() {
            List<Article> list = new List<Article>();
            list.Add(new Article() { Id = "1", ClassId = "1", ClassName = "体育新闻", Title = "微软发布MVC4.0了", Summary = "微软发布MVC4.0了,此版本更加强大", CreateTime = DateTime.Parse("2012-2-3") });
            list.Add(new Article() { Id = "2", ClassId = "1", ClassName = "IT新闻", Title = "跟谷歌测试工程师的对话", Summary = "本文主人公Alan是谷歌的一名的软件测试工程师,他的工作对象是谷歌的DoubleClick广告管理系统(Bid Manager),这个系统提供让广告代理商和广告客户在多个广告上进行报价竞标的功能。", CreateTime = DateTime.Parse("2012-3-3") });
            list.Add(new Article() { Id = "3", ClassId = "1", ClassName = "体育 新闻", Title = "好的程序员应该熟悉的几门编程语言", Summary = "如果想成为一个好的程序员,甚至架构师、技术总监等,显然只精通一种编程语言是不够的,还应该在常见领域学会几门编程语言,正如我们要成为高级人才不仅要会中文还要会英文", CreateTime = DateTime.Parse("2012-4-3") });
            list.Add(new Article() { Id = "4", ClassId = "2", ClassName = "娱乐新闻", Title = "Javascript开发《三国志曹操传》-开源讲座(五)-可移动地图的实现", Summary = "这一讲的内容很简单,大家理解起来会更快。因此我只对重点加以分析,其他的就轮到大家思考哦!首先来说,我对游戏开发可以算是不怎么深入,因为现在的程序员爱用canvas,我却就只会拿几个div凑和。", CreateTime = DateTime.Parse("2012-5-3") });
            list.Add(new Article() { Id = "5", ClassId = "2", ClassName = "体育新闻", Title = "Android之BaseExpandableListAdapter使用心得", Summary = " 但是我最近做那个QQ项目是遇到一个问题,如果给这个ExpandableListView添加动态从网上获取的数据呢?前面跟大家分享的时候,是用了静态的数据,很好处理。", CreateTime = DateTime.Parse("2012-6-3") });
            list.Add(new Article() { Id = "6", ClassId = "3", ClassName = "sports news", Title = "对话CSDN蒋涛:微软移动互联网马太效应不可避免,小团队需学会利用平台", Summary = "CSDN是全球最大的中文IT社区,也是雷锋网最重要的合作伙伴之一,自1999年创办至今,有着非常强大的业界影响力和号召力,其专注IT信息传播、技术交流、教育培训和专业技术人才服务,在2012年移动开发者大会即将举办之际,雷锋网对CSDN的掌门人蒋涛做了一次专访,一起探讨移动互联网的新技术浪潮和下一波发展趋势。", CreateTime = DateTime.Parse("2012-7-3") });
            list.Add(new Article() { Id = "7", ClassId = "3", ClassName = "体育新闻", Title = "基于MySQL的分布式事务控制方案", Summary = "基于MySQL的分布式事务控制方案", CreateTime = DateTime.Parse("2012-8-3") });
            list.Add(new Article() { Id = "8", ClassId = "4", ClassName = "sports news", Title = "IOS和Android开发的一些个人感受", Summary = "最近公司的产品 Android版本第二版也算到了收尾,新加了几个功能性模块,我基本也就捡了几个好玩的模块做了下。", CreateTime = DateTime.Parse("2012-9-3") });
            list.Add(new Article() { Id = "9", ClassId = "5", ClassName = "IT资讯", Title = "Google Code的简单使用", Summary = "google code简介:用于管理代码的仓库,反正我是这么理解的。就比我们在公司的时候也会有个用于存放公司代码的主机一样,google同样给我们提供了这样的一个host。这样我们可以在不同电脑不同地方随时的checkout,commit,同时分享我们的项目。", CreateTime = DateTime.Parse("2012-10-3") });
            list.Add(new Article() { Id = "10", ClassId = "33", ClassName = "IT资讯", Title = "谷歌在印度推Gmail免费短信服务", Summary = "歌一直在努力桥接发展中国家功能手机SMS服务和Gmail之间的服务,这不,近日谷歌在印度推出“Gmail SMS”服务,这使得印度的Gmail用户可以从Gmail的窗口发送信息到手机上并且接受聊天信息的回复,目前谷歌的这项服务已经得到印度的八大运营商的支持。", CreateTime = DateTime.Parse("2012-11-3") });
            list.Add(new Article() { Id = "11", ClassId = "11", ClassName = "体育新闻", Title = "鲍尔默:微软新时代 软硬结合“赢”未来", Summary = "微软CEO鲍尔默在年度公开信中表示,微软在未来将紧密结合硬件和软件。鲍尔默认为,这是微软的一个新时代。“我们看到了前所未有的机会,我们对此很兴奋,并且保持着乐观的心态。”", CreateTime = DateTime.Parse("2012-12-3") });
            return list;
        }
    }

    public class Article {
        public string Id { get; set; }
        public string ClassId { get; set; }
        public string ClassName { get; set; }
        public string Title { get; set; }
        public string Summary { get; set; }
        public string Score { get; set; }
        public DateTime CreateTime { get; set; }
    }
}

 

 

 

 

 

 

...

...

Zookeeper的核心:ZAB原子消息广播协议

 点击查看原图
        ZooKeeper为高可用的一致性协调框架,自然的ZooKeeper也有着一致性算法的实现,ZooKeeper使用的是ZAB协议作为数据一致性的算法,
ZAB(ZooKeeper Atomic Broadcast )
称为:原子消息广播协议;ZAB可以说是在Paxos算法基础上进行了扩展改造而来的,ZAB协议设计了支持崩溃恢复,ZooKeeper使用单一主进程
Leader用于处理客户端所有事务请求,采用ZAB协议将服务器数状态以事务形式广播到所有Follower上;由于事务间可能存在着依赖关系,ZAB
协议保证Leader广播的变更序列被顺序的处理,:一个状态被处理那么它所依赖的状态也已经提前被处理;ZAB协议支持的崩溃恢复可以保证在
Leader进程崩溃的时候可以重新选出Leader并且保证数据的完整性;

  在ZooKeeper中
所有的事务请求都由一个主服务器也就是Leader来处理,其他服务器为Follower,Leader将客户端的事务请求转换为事务Proposal,
并且将Proposal分发给集群中其他所有的Follower,然后Leader等待Follwer反馈,当有
过半数(>=N/2+1)的Follower反馈信息后,Leader将再次向集群内Follower广播Commit信息,Commit为将之前的Proposal提交;

一、协议状态

  ZAB协议中存在着三种状态,每个节点都属于以下三种中的一种:
  1. Looking(发现):系统刚启动时或者Leader崩溃后正处于选举状态
  2. Following(同步):Follower节点所处的状态,Follower与Leader处于数据同步阶段;
  3. Leading(领导):Leader所处状态,当前集群中有一个Leader为主进程;

  ZooKeeper启
动时所有节点初始状态为Looking,这时集群会尝试选举出一个Leader节点,选举出的Leader节点切换为Leading状态;当节点发现集群
中已经选举出Leader则该节点会切换到Following状态,然后和Leader节点保持同步;当Follower节点与Leader失去联系时
Follower节点则会切换到Looking状态,开始新一轮选举;在ZooKeeper的整个生命周期中每个节点都会在Looking、
Following、Leading状态间不断转换;

    点击查看原图

  选举出Leader节
点后ZAB进入原子广播阶段,这时Leader为和自己同步的每个节点Follower创建一个操作序列,一个时期一个Follower只能和一个
Leader保持同步,Leader节点与Follower节点使用心跳检测来感知对方的存在;当Leader节点在超时时间内收到来自Follower
的心跳检测那Follower节点会一直与该节点保持连接;若超时时间内Leader没有接收到来自过半Follower节点的心跳检测或TCP连接断
开,那Leader会结束当前周期的领导,切换到Looking状态,所有Follower节点也会放弃该Leader节点切换到Looking状态,然
后开始新一轮选举;

二、算法阶段

  ZAB协议定义了选举(election)、发现(discovery)、同步(sync)、广播(Broadcast)
个阶段;ZAB选举(election)时当Follower存在ZXID(事务ID)时判断所有Follower节点的事务日志,只有lastZXID
的节点才有资格成为Leader,这种情况下选举出来的Leader总有最新的事务日志,基于这个原因所以ZooKeeper实现的时候把
发现(discovery)与同步(sync)合并为恢复(recovery)阶段;
  1. Election:在Looking状态中选举出Leader节点,Leader的lastZXID总是最新的;
  2. Discovery:Follower节点向准Leader推送FOllOWERINFO,该信息中包含了上一周期的epoch,接受准Leader的NEWLEADER指令,检查newEpoch有效性,准Leader要确保Follower的epoch与ZXID小于或等于自身的;
  3. sync:将Follower与Leader的数据进行同步,由Leader发起同步指令,最总保持集群数据的一致性;
  4. Broadcast:Leader广播Proposal与Commit,Follower接受Proposal与Commit;
  5. Recovery:在Election阶段选举出Leader后本阶段主要工作就是进行数据的同步,使Leader具有highestZXID,集群保持数据的一致性;

  1、选举(Election)
  election阶段必
须确保选出的Leader具有highestZXID,否则在Recovery阶段没法保证数据的一致性,Recovery阶段Leader要求
Follower向自己同步数据没有Follower要求Leader保持数据同步,所有选举出来的Leader要具有最新的ZXID;

  在选举的过程中会对每个Follower节点的ZXID进行对比只有highestZXID的Follower才可能当选Leader;
选举流程:
  1. 每个Follower都向其他节点发送选自身为Leader的Vote投票请求,等待回复;
  2. Follower接受到的Vote如果比自身的大(ZXID更新)时则投票,并更新自身的Vote,否则拒绝投票;
  3. 每个Follower中维护着一个投票记录表,当某个节点收到过半的投票时,结束投票并把该Follower选为Leader,投票结束;

  ZAB协议中使用ZXID作为事务编号,ZXID为64位数字
低32位为一个递增的计数器,每一个客户端的一个事务请求时Leader产生新的事务后该计数器都会加1,高32位为Leader周期epoch编号,当
新选举出一个Leader节点时Leader会取出本地日志中最大事务Proposal的ZXID解析出对应的epoch把该值加1作为新的epoch,
将低32位从0开始生成新的ZXID;ZAB使用epoch来区分不同的Leader周期;

  2、恢复(Recovery)
  在election阶段选举出来的Leader已经具有最新的ZXID,所有本阶段的主要工作是根据Leader的事务日志对Follower节点数据进行更新;
  
Leader:Leader生成新的ZXID与epoch,接收Follower发送过来的FOllOWERINFO(含有当前节点的LastZXID)
然后往Follower发送NEWLEADER;Leader根据Follower发送过来的LastZXID根据数据更新策略向Follower发送更
新指令;

  同步策略:
  1. SNAP:如果Follower数据太老,Leader将发送快照SNAP指令给Follower同步数据;
  2. DIFF:Leader发送从Follolwer.lastZXID到Leader.lastZXID议案的DIFF指令给Follower同步数据;
  3. TRUNC:当Follower.lastZXID比Leader.lastZXID大时,Leader发送从Leader.lastZXID到Follower.lastZXID的TRUNC指令让Follower丢弃该段数据;
  Follower:往
Leader发送FOLLOERINFO指令,Leader拒绝就转到Election阶段;接收Leader的NEWLEADER指令,如果该指令中
epoch比当前Follower的epoch小那么Follower转到Election阶段;Follower还有主要工作是接收SNAP/DIFF
/TRUNC指令同步数据与ZXID,同步成功后回复ACKNETLEADER,然后进入下一阶段;Follower将所有事务都同步完成后Leader
会把该节点添加到可用Follower列表中;

  SNAP与DIFF用于保证集群中Follower节点已经Committed的数据的一致性,TRUNC用于抛弃已经被处理但是没有Committed的数据;

  3、广播(Broadcast)
  客户端提交事务请求时
Leader节点为每一个请求生成一个事务Proposal,将其发送给集群中所有的Follower节点,收到过半Follower的反馈后开始对事务
进行提交,ZAB协议使用了原子广播协议;在ZAB协议中只需要得到过半的Follower节点反馈Ack就可以对事务进行提交,这也导致了Leader
几点崩溃后可能会出现数据不一致的情况,ZAB使用了崩溃恢复来处理数字不一致问题;消息广播使用了TCP协议进行通讯所有保证了接受和发送事务的顺序
性。广播消息时Leader节点为每个事务Proposal分配一个全局递增的ZXID(事务ID),每个事务Proposal都按照ZXID顺序来处
理;

  Leader节点为每一
个Follower节点分配一个队列按事务ZXID顺序放入到队列中,且根据队列的规则FIFO来进行事务的发送。Follower节点收到事务
Proposal后会将该事务以事务日志方式写入到本地磁盘中,成功后反馈Ack消息给Leader节点,Leader在接收到过半Follower节点
的Ack反馈后就会进行事务的提交,以此同时向所有的Follower节点广播Commit消息,Follower节点收到Commit后开始对事务进行
提交;

摘自: http://blog.itpub.net/30316686/viewspace-2106956/

TcpTimedWaitDelay/MaxUserPort

当TCP连接被关闭时,{ Protocol, Local IP, Local Port, Remote IP, Remote Port}五元组就进入TIME_WAIT状态,默认时间是4分钟。可以通过一组命令看看tcp的连接状态:

netstat -ano>>c:\port.txt

netstat -n | find /C /I "established"
查看连接与内存
ss -s && free -g

本地ip,远程ip,远程端口都是固定的,只有本地端口是变化的,本地端口只能使用1024-5000,因此如果在4分钟内发起了大约4000个连接,这时就会发生异常,下面是使用WCF,客户端的异常:

System.Net.Sockets.SocketException: Only one usage of each socket
address (protocol/network address/port) is normally permitted
192.168.101.5:8888
at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
at System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri, TimeSpan timeout)

TcpTimedWaitDelay 描述:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/TCPIP/Parameters
确定 TCP/IP 可释放已关闭连接并重用其资源前,必须经过的时间。关闭和释放之间的此时间间隔通称 TIME_WAIT 状态或两倍最大段生命周期(2MSL)状态。
此时间期间,重新打开到客户机和服务器的连接的成本少于建立新连接。
减少此条目的值允许 TCP/IP 更快地释放已关闭的连接,为新连接提供更多资源。
如果运行的应用程序需要快速释放和创建新连接,而且由于 TIME_WAIT 中存在很多连接,导致低吞吐量,则调整此参数。

参考:https://technet.microsoft.com/en-us/library/cc938217.aspx
TYPE:    REG_DWORD   
VALUE:    0x1E 0x12C ( 30–300 seconds )
DEFAULT:    0xF0 ( 240 seconds = 4 minutes )

将此值设置为十进制 30,其为十六进制 0x0000001e。该值将等待时间设置为 30 秒。
建议值:最小值为 0x1E,它将等待时间设置为 30 秒。

MaxUserPort 描述:
HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/TCPIP/Parameters
TYPE:    REG_DWORD   
VALUE:    5,000–65,534 ( port number )
DEFAULT:    5000

确定在应用程序从系统请求可用用户端口时,TCP/IP 可指定的最高端口号。
缺省值:无 建议值:至少十进制 32768。

参考:https://technet.microsoft.com/en-us/library/cc938196.aspx

注意: 如果调整 MaxUserPort 或 TcpTimedWaitDelay 设置,您必须重新启动 Microsoft Windows 以使新设置生效。

使用 Exchange Server 2007 :
建议将 MaxUserPort 值设置为 60000。
如果设置的 MaxUserPort 值低于 60000,服务器可能会显示名称服务提供程序接口 (NSPI) 代理警告,例如事件 9040。

描述:

http://longwhiteclouds.com/2012/03/22/1-million-iops-microsoft-vs-vmware-comparison/

 

Links:

http://www.xiaobo.li/network/572.html

 

PPTP/L2TP over PPPoE的準確MTU/MRU值

Ethernet MinSize = 512bit = 64 Byte
Ethernet MaxSize = 1518 Byte
so Ethernet IP MTU = 1518 - 18 ( 6 SRCMAC+ 6 DSTMAC+ 2 TYPE+ 4 CRC) = 1500 B
so Ethernet IP TCP MSS = 1500 - 40 ( 20 IP_HEADER + 20 TCP_HEADER) = 1460 B
so Ethernet IP UDP MTU/MRU = 1500 - 28 ( 20 IP_HEADER + 8 UDP_HEADER ) = 1472 B
so PPPoE MTU/MRU = 1500 - 8 ( 6 PPPoE_SESSION + 2 PPP_HEADER ) = 1492 B
so TCP over PPPoE MSS = 1492 ( PPPoE MTU/MRU ) - 40 ( 20 IP_HEADER + 20 TCP_HEADER) = 1452
so PPTP MTU/MRU = 1500 - 56 ( 20 IP_HEADER + 20 TCP_HEADER + 12 GRE_HEADER + 4 PPP_HEADER ) = 1444 B
so TCP over PPTP MSS = 1444 ( PPTP MTU/MRU ) - 40 ( 20 IP_HEADER + 20 TCP_HEADER) = 1404
so L2TP MTU/MRU = 1500 - 40 ( 20 IP_HEADER +8 UDP_HEADER + 8 L2TP_HEADER + 4 PPP_HEADER ) = 1460 B
so TCP over L2TP MSS = 1460 ( L2TP MTU/MRU ) - 40 ( 20 IP_HEADER + 20 TCP_HEADER) = 1420 B
so PPTP over PPPoE MTU/MRU = 1492 ( PPPoE MTU/MRU ) - 56 ( 20 IP_HEADER + 20 TCP_HEADER + 12 GRE_HEADER + 4 PPP_HEADER ) = 1436 B
so PPTP over PPTP MTU/MRU = 1444 ( PPTP MTU/MRU ) - 56 ( 20 IP_HEADER + 20 TCP_HEADER + 12 GRE_HEADER + 4 PPP_HEADER ) = 1388 B
so PPTP over L2TP MTU/MRU = 1460 ( L2TP MTU/MRU ) - 56 ( 20 IP_HEADER + 20 TCP_HEADER + 12 GRE_HEADER + 4 PPP_HEADER ) = 1404 B
so L2TP over PPPoE MTU/MRU = 1492 ( PPPoE MTU/MRU ) - 40 ( 20 IP_HEADER +8 UDP_HEADER + 8 L2TP_HEADER + 4 PPP_HEADER ) = 1452 B
so L2TP over PPTP MTU/MRU = 1444 ( PPTP MTU/MRU ) - 40 ( 20 IP_HEADER +8 UDP_HEADER + 8 L2TP_HEADER + 4 PPP_HEADER ) = 1404 B
so L2TP over L2TP MTU/MRU = 1460 ( L2TP MTU/MRU ) - 40 ( 20 IP_HEADER +8 UDP_HEADER + 8 L2TP_HEADER + 4 PPP_HEADER ) = 1420 B

 

PPTP over PPPoE的準確MTU值是 1436,L2TP over PPPoE的準確MTU是1452。別人說的 1400 偏保守了點。

如果你用 ADSL 上網,然後用 PPTP 來翻Wall,那麼,你實際上是 PPP 協議跑在 TCP 協議上再跑在 IP 協議上再跑在
PPP 協議上再跑在 IP 協議上再跑在以太網協議上。1518 字節的最大以太網 frame,扣來扣去,就剩下
1436。同理L2TP跑在PPP鏈路上,扣來扣去也就只剩1452B了,難怪筆者之前VPN上不去網,原來是全把數據包丟掉了。

如果讀者看明白了上面的解釋,那麼考慮你用 pptp 連公司的 vpn,公司又 pppoe(adsl撥號),然後你再 pptp 來翻功夫網,那麼,你的 MTU 只能設為 1518-18-8-56-56=1380 字節。