<< 十二月 2014 | 首页 | 二月 2015 >>

java Jackson 库操作 json 的基本演示 - joyous的专栏 - 博客频道 - CSDN.NET

核心库下载地址

http://repo1.maven.org/maven2/com/fasterxml/jackson/core/

jackson-annotations-2.2.2.jar

jackson-core-2.2.2.jar

jackson-databind-2.2.2.jar

 

文件类型支持模块

http://repo1.maven.org/maven2/com/fasterxml/jackson/dataformat/

jackson-dataformat-xml-2.2.2.jar

 

导入库

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonParseException;

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /** 
  2.  * Map 转换为 json 
  3.  */  
  4. public static void MyTest01()  
  5. {  
  6.   Map<String, String> hashMap = new HashMap<String, String>();  
  7.   hashMap.put("name""zhang");  
  8.   hashMap.put("sex""1");  
  9.   hashMap.put("login""Jack");  
  10.   hashMap.put("password""123abc");  
  11.   
  12.   try  
  13.   {  
  14.     ObjectMapper objectMapper = new ObjectMapper();  
  15.     String userMapJson = objectMapper.writeValueAsString(hashMap);  
  16.   
  17.     JsonNode node = objectMapper.readTree(userMapJson);  
  18.   
  19.     // 输出结果转意,输出正确的信息  
  20.     System.out.println(node.get("password").asText());  
  21.     // 输出不转意,输出结果会包含"",这是不正确的,除非作为json传递,如果是输出结果值,必须如上一行的操作  
  22.     System.out.println(node.get("name"));  
  23.   }  
  24.   catch (IOException e)  
  25.   {  
  26.   }  
  27. }  

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /** 
  2.    * 解析 json 格式字符串 
  3.    */  
  4.   public static void MyTest03()  
  5.   {  
  6.     try  
  7.     {  
  8.       String str = "{\"data\":{\"birth_day\":7,\"birth_month\":6},\"errcode\":0,\"msg\":\"ok\",\"ret\":0}";  
  9.   
  10.       ObjectMapper mapper = new ObjectMapper();  
  11.       JsonNode root = mapper.readTree(str);  
  12.   
  13.       JsonNode data = root.path("data");  
  14.   
  15.       JsonNode birth_day = data.path("birth_day");  
  16.       System.out.println(birth_day.asInt());  
  17.         
  18.       JsonNode birth_month = data.path("birth_month");  
  19.       System.out.println(birth_month.asInt());  
  20.   
  21.       JsonNode msg = root.path("msg");  
  22.       System.out.println(msg.textValue());  
  23.     }  
  24.     catch (IOException e)  
  25.     {  
  26.     }  
  27.   }  

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /** 
  2.    * json 直接提取 值 
  3.    */  
  4.   public static void MyTest05()  
  5.   {  
  6.     try  
  7.     {  
  8.       // 演示字符串  
  9.       String str = "{\"data\":{\"hasnext\":0,\"info\":[{\"id\":\"288206077664983\",\"timestamp\":1371052476},{\"id\":\"186983078111768\",\"timestamp\":1370944068},{\"id\":\"297031120529307\",\"timestamp\":1370751789},{\"id\":\"273831022294863\",\"timestamp\":1369994812}],\"timestamp\":1374562897,\"totalnum\":422},\"errcode\":0,\"msg\":\"ok\",\"ret\":0,\"seqid\":5903702688915195270}";  
  10.   
  11.       ObjectMapper mapper = new ObjectMapper();  
  12.       JsonNode root = mapper.readTree(str);  
  13.   
  14.       // 提取 data  
  15.       JsonNode data = root.path("data");  
  16.       // 提取 info  
  17.       JsonNode info = data.path("info");  
  18.   
  19.       System.out.println(info.size());  
  20.   
  21.       // 得到 info 的第 0 个  
  22.       JsonNode item = info.get(0);  
  23.       System.out.println(item.get("id"));  
  24.       System.out.println(item.get("timestamp"));  
  25.   
  26.       // 得到 info 的第 2 个  
  27.       item = info.get(2);  
  28.       System.out.println(item.get("id"));  
  29.       System.out.println(item.get("timestamp"));  
  30.   
  31.       // 遍历 info 内的 array  
  32.       if (info.isArray())  
  33.       {  
  34.         for (JsonNode objNode : info)  
  35.         {  
  36.           System.out.println(objNode);  
  37.         }  
  38.       }  
  39.   
  40.     }  
  41.     catch (Exception e)  
  42.     {  
  43.   
  44.     }  
  45.   }  

 

[java] view plaincopy在CODE上查看代码片派生到我的代码片
 
  1. /** 
  2.  * 创建一个 json,并向该 json 添加内容 
  3.  */  
  4. public static void MyTest07()  
  5. {  
  6.   try  
  7.   {  
  8.     ObjectMapper mapper = new ObjectMapper();  
  9.     ObjectNode root1 = mapper.createObjectNode();  
  10.   
  11.     root1.put("nodekey1"1);  
  12.     root1.put("nodekey2"2);  
  13.   
  14.     System.out.println(root1.toString());  
  15.   
  16.   //Create the root node  
  17.     ObjectNode root = mapper.createObjectNode ();  
  18.     //Create a child node  
  19.     ObjectNode node1 = mapper.createObjectNode ();  
  20.     node1.put ("nodekey1"1);  
  21.     node1.put ("nodekey2"2);  
  22.     //Bind the child nodes  
  23.     root.put ("child", node1);  
  24.     //Array of nodes  
  25.     ArrayNode arrayNode = mapper.createArrayNode ();  
  26.     arrayNode.add (node1);  
  27.     arrayNode.add (1);  
  28.     //Bind array node  
  29.     root.put ("arraynode", arrayNode);  
  30.   
  31.     System.out.println (mapper.writeValueAsString (root));  
  32.   }  
  33.   catch (Exception e)  
  34.   {  
  35.   
  36.   }  
  37. }  


 

参考资料

http://wiki.fasterxml.com/JacksonInFiveMinutes

阅读全文……

标签 : ,

如何用Mule创建动态的HTTP代理服务

 

目的

引入动态http代理的主要目的是在加入新的http代理而不需要重启Mule代理服务。注意,要真正的动态代理,需要注入实现了路径与服务器地址映射的检索服务的Spring的Bean,在enricher位置通过groovy获得Bean的实例进行调用。

 

实例程序的限制:

这个例子程序缺乏生产环境中使用处理:

  • 错误处理
  • 从数据库检索路径的映射配置信息

            这个例子将HTTP相对路径和目标服务器之间的映射写在XML配置文件里。这当然不能允许动态修改代理配置。

  • 支持更多的HTTP方法

             只支持HTTP get和post方法

  • 处理的HTTP参数。

             实例程序没考虑HTTP参数但这些都被认为是在HTTP相对路径的一部分。

  • 支持HTTPS。

 

为了能够有一个服务代理,一个简单的SOAP问候服务使用一个Mule配置文件和一个Java类实现。

Mule配置包含以下配置:

01.<?xml version="1.0" encoding="UTF-8"?>
02.<mule
09.xsi:schemaLocation="
14. 
15.<spring:beans>
16.<spring:bean id="helloService" class="com.ivan.mule.dynamichttpproxy.HelloService"/>
17.</spring:beans>
18. 
19.<flow name="GreetingFlow">
20.<inbound-endpoint address="http://localhost:8182/services/GreetingService"
21.exchange-pattern="request-response"/>
22. 
23.<cxf:jaxws-service serviceClass="com.ivan.mule.dynamichttpproxy.HelloService"/>
24.<component>
25.<spring-object bean="helloService"/>
26.</component>
27.</flow>
28.</mule>

 

服务类:

01.package com.ivan.mule.dynamichttpproxy;
02. 
03.import java.util.Date;
04.import javax.jws.WebParam;
05.import javax.jws.WebResult;
06.import javax.jws.WebService;
07. 
08./**
09.* SOAP web service endpoint implementation class that implements
10.* a service that extends greetings.
11.*
12.* @author Ivan Krizsan
13.*/
14.@WebService
15.public class HelloService {
16./**
17.* Greets the person with the supplied name.
18.*
19.* @param inName Name of person to greet.
20.* @return Greeting.
21.*/
22.@WebResult(name = "greeting")
23.public String greet(@WebParam(name = "inName") final String inName) {
24.return "Hello " + inName + ", the time is now " + new Date();
25.}
26.}

 

 

服务器信息Bean,用于存储原始HTTP请求路径与对应目标服务器ip端口的映射信息:

01.package com.ivan.mule.dynamichttpproxy;
02. 
03./**
04.* Holds information about a server which to forward requests to.
05.*
06.* @author Ivan Krizsan
07.*/
08.public class ServerInformationBean {
09.private String serverAddress;
10.private String serverPort;
11.private String serverName;
12. 
13./**
14.* Creates an instance holding information about a server with supplied
15.* address, port and name.
16.*
17.* @param inServerAddress
18.* @param inServerPort
19.* @param inServerName
20.*/
21.public ServerInformationBean(final String inServerAddress,
22.final String inServerPort, final String inServerName) {
23.serverAddress = inServerAddress;
24.serverPort = inServerPort;
25.serverName = inServerName;
26.}
27. 
28.public String getServerAddress() {
29.return serverAddress;
30.}
31. 
32.public String getServerPort() {
33.return serverPort;
34.}
35. 
36.public String getServerName() {
37.return serverName;
38.}
39.}

 

动态HTTP 代理Mule配置:

001.<?xml version="1.0" encoding="UTF-8"?>
002.<!--
003.The dynamic HTTP proxy Mule configuration file.
004. 
005.Author: Ivan Krizsan
006.-->
015.version="CE-3.4.0"
016.xsi:schemaLocation="
 
022. 
023.<spring:beans>
024.<!--
025.Mappings from path to server represented by a hash map.
026.A map has been choosen to limit the scope of this example.
027.Storing data about mappings between path to server in a database
028.will enable runtime modifications to the mapping data without
029.having to stop and restart the general proxy Mule application.
030.-->
031.<util:map id="pathToServerAndPortMapping" map-class="java.util.HashMap">
032.<!-- Entry for MyServer. -->
033.<spring:entry key="services/GreetingService">
034.<spring:bean class="com.ivan.mule.dynamichttpproxy.ServerInformationBean">
035.<spring:constructor-arg value="localhost"/>
036.<spring:constructor-arg value="8182"/>
037.<spring:constructor-arg value="MyServer"/>
038.</spring:bean>
039.</spring:entry>
040.<!-- Entry for SomeOtherServer. -->
041.<spring:entry key="services/GreetingService?wsdl">
042.<spring:bean class="com.ivan.mule.dynamichttpproxy.ServerInformationBean">
043.<spring:constructor-arg value="127.0.0.1"/>
044.<spring:constructor-arg value="8182"/>
045.<spring:constructor-arg value="SomeOtherServer"/>
046.</spring:bean>
047.</spring:entry>
048.</util:map>
049.</spring:beans>
050. 
051.<flow name="HTTPGeneralProxyFlow">
052.<!--
053.Note that if you increase the length of the path to, for instance
054.generalProxy/additionalPath, then the expression determining
055.the outgoing path need to be modified accordingly.
056.Changing the path, without changing its length, require no
057.modification to outgoing path.
058.-->
059.<http:inbound-endpoint
060.exchange-pattern="request-response"
061.host="localhost"
062.port="8981"
063.path="dynamicHttpProxy" doc:name="HTTP Receiver"/>
064. 
065.<!-- Extract outgoing path from received HTTP request. -->
066.<set-property
067.value="#[org.mule.util.StringUtils.substringAfter(org.mule.util.StringUtils.substringAfter(message.inboundProperties['http.request'], '/'), '/')]"
068.propertyName="outboundPath"
069.doc:name="Extract Outbound Path From Request" />
070. 
071.<logger message="#[string:Outbound path = #[message.outboundProperties['outboundPath']]]"level="DEBUG"/>
072. 
073.<!--
074.Using the HTTP request path, select which server to forward the request to.
075.Note that there should be some kind of error handling in case there is no server for the current path.
076.Error handling has been omitted in this example.
077.-->
078.<enricher target="#[variable:outboundServer]">
079.<scripting:component doc:name="Groovy">
080.<!--
081.If storing mapping data in a database, this Groovy script
082.should be replaced with a database query.
083.-->
084.<scripting:script engine="Groovy">
085.<![CDATA[
086.def theMap = muleContext.getRegistry().lookupObject("pathToServerAndPortMapping")
087.def String theOutboundPath = message.getOutboundProperty("outboundPath")
088.def theServerBean = theMap[theOutboundPath]
089.theServerBean
090.]]>
091.</scripting:script>
092.</scripting:component>
093.</enricher>
094. 
095.<logger
096.message="#[string:Server address = #[groovy:message.getInvocationProperty('outboundServer').serverAddress]]"
097.level="DEBUG"/>
098.<logger
099.message="#[string:Server port = #[groovy:message.getInvocationProperty('outboundServer').serverPort]]"
100.level="DEBUG"/>
101.<logger
102.message="#[string:Server name = #[groovy:message.getInvocationProperty('outboundServer').serverName]]"
103.level="DEBUG"/>
104. 
105.<!-- Log the request and its metadata for development purposes, -->
106.<test:component logMessageDetails="true"/>
107. 
108.<!--
109.Cannot use a MEL expression in the value of the method attribute
110.on the HTTP outbound endpoints so have to revert to this way of
111.selecting HTTP method in the outgoing request.
112.In this example, only support for GET and POST has been implemented.
113.This can of course easily be extended to support additional HTTP
114.verbs as desired.
115.-->
116.<choice doc:name="Choice">
117.<!-- Forward HTTP GET requests. -->
118.<when expression="#[message.inboundProperties['http.method']=='GET']">
119.<http:outbound-endpoint
120.exchange-pattern="request-response"
121.host="#[groovy:message.getInvocationProperty('outboundServer').serverAddress]"
122.port="#[groovy:message.getInvocationProperty('outboundServer').serverPort]"
123.method="GET"
124.path="#[message.outboundProperties['outboundPath']]"
125.doc:name="Send HTTP GET"/>
126.</when>
127.<!-- Forward HTTP POST requests. -->
128.<when expression="#[message.inboundProperties['http.method']=='POST']">
129.<http:outbound-endpoint
130.exchange-pattern="request-response"
131.host="#[groovy:message.getInvocationProperty('outboundServer').serverAddress]"
132.port="#[groovy:message.getInvocationProperty('outboundServer').serverPort]"
133.method="POST"
134.path="#[message.outboundProperties['outboundPath']]"
135.doc:name="Send HTTP POST"/>
136.</when>
137.<!-- If HTTP method not recognized, use GET. -->
138.<otherwise>
139.<http:outbound-endpoint
140.exchange-pattern="request-response"
141.host="#[groovy:message.getInvocationProperty('outboundServer').serverAddress]"
142.port="#[groovy:message.getInvocationProperty('outboundServer').serverPort]"
143.method="GET"
144.path="#[message.outboundProperties['outboundPath']]"
145.doc:name="Default: Send HTTP GET"/>
146.</otherwise>
147.</choice>
148.</flow>
149.</mule>

 

 

注意:

  • 一个名称为“pathToServerAndPortMapping”用Spring XML配置了路径与服务器地址的映射
  • <set-property>元素设置了outboundPath属性的值,outboundPath即服务的相对路径,用于检索目标服务器,并对目标服务器发起http:outbound-endpoint.
  • <enricher>元素部分是使用outboundpath检索对应的ServerInformationBean实例
  • <choice>元素包含了多个outbound HTTP endpoints。

 

启动Mule工程服务后,现在访问真正的目标服务

http://localhost:8182/services/GreetingService?wsdl

应该能看到WSDL文件内容了。通过soapUI访问,应该能收到包含日期和时间的问候了。

 

接下来,通过soapUI访问代理服务

http://localhost:8981/dynamicHttpProxy/services/GreetingService

 

控制台上会打印如下内容:

1.... Outbound path = services/GreetingService
2.... Server address = localhost
3.... Server port = 8182
4.... Server name = MyServer

 

转载请注明原创首发地址:如何用Mule创建动态HTTP代理服务

 

每个jQuery开发者应该知道的重要技巧

 

1. stopPropagation or preventDefault or return false?

 

开发新手对stopPropagation,preventDefault和返回false经常混淆该使用哪一个技术以及什么时候用。

 

 

stopPropagation()

 

要了解stopPropagation,我们需要首先了解事件冒泡。让我们来举个例子。让我们假设你有链接<a>在<div>里,如下所示:

<div id="divone">

    <a href="#" id="aone">Click me</a>

</div>

 

click事件挂在链接和DIV上:

$("#divone").click(function (e) {

    alert("div clicked");

});

 

$("a").click(function (e) {

    alert("link clicked");

});

 

当你点击链接,click()事件触发以及函数运行显示一个警告框“link clicked”。然而,事件并没有就此止步。你会看到另一个警告框“div clicked”。换句话说,即使你单击<a>,由于<div>是它的祖先元素,也接收到click事件。这就是所谓的事件冒泡或事件传播。

 

因此为了从阻止冒泡事件,需要以下列方式使用stopPropagation:

$("a").click(function (e) {

    alert("link clicked");

    e.stopPropagation();

});

 

 

现在,当你点击链接,单击事件将激发以及功能运行显示一个警告框“link clicked”。然而,由于e.stopPropagation,该事件不会冒泡。这就是为什么你不会看到第二个警告框。

 

preventDefault()

 

如果你想阻止Web浏览器事件的正常反应,使用preventDefault()。默认情况下,当你点击超链接,事件正常反应,转向到超链接href属性所示的网址。让我们以同样的例子定义超链接在div里如下:

<div id="divone">

    <a href="http://www.jquerycookbook.com" id="aone">Click me</a>

</div>

 

在这里,点击超链接将转移到网页www.jquerycookbook.com。如果你想阻止这种默认行为,使用preventDefault(),如下所示:

$("#divone").click(function (e) {

    alert("div clicked");

});

 

$("a").click(function (e) {

    e.preventDefault();

});

 

 

现在,当您运行代码,你会看到,点击超链接并没有转向到网站地址,因为我们已经阻止了浏览器的默认事件。

 

然而,“div clicked”警告框显示了,因为我们阻止默认事件,而没有阻止发生事件冒泡/传播。如果你想阻止事件的发生冒泡,再同时使用,如下所示:

$("a").click(function (e) {

    e.stopPropagation();

    e.preventDefault();

});

 

现在,我们这两个都做了,所以浏览器不按照链接转向并且div事件也不会触发,因此我们没有看到alert()框。

 

return false

 

返回false实际上是调用stopPropagation()和preventDefault()的快捷方式。它告诉jQuery来防止缺省事件和停止冒泡的一种方式。大多数时候,你不想调用stopPropagation,所以我强烈建议不使用return false,而在代码中使用preventDefault()。

 

2、一些选择器技巧

这里有一些选择器技巧,你可以用它来提高选择的性能:

 

a。如果可能的话,使用ID选择器去选择代码中的元素。

 

b。在选择之前,不要在前面加上了标签名。所以,来看看下面:

<input type="text" id="code" value="54325454" />

..不要用 $("input#code"), 应该用 $("#code").

 

 

c. 只要有可能,使用过滤器方法来提高性能。可以使用$("div").has('p')来代替$( "div:has(p)"),这里 .has() 使用本地的DOM querySelectorAll() 方法 因此理论上比 :has更快。

 

d. 使用slice() 代替使用 :lt和 :gt 选择器

 

e. 推荐优先使用伪选择器,例如带有tag名的:text或者其他的选择器,否则隐含的通用选择器 ("*")就被使用了。也就是,$(":text") 相当于 $( "*:text"),所以应该使用$("input:text")

 

f. 不用 Not Equal 不等于选择器,尽可能使用 .not()获得小小的性能优势

 

g。不用过滤器,使用相当的属性选择器。例如用$('[type=image]' 来代替 $(':image')

 

延伸阅读:

http://learn.jquery.com/performance/optimize-selectors/

 

http://api.jquery.com/?s=selectors

 

3 - 使用 attr() 还是 prop()

attr() 处理 attributes 而 prop() 处理 properties. 考虑下面的标签:

<input type="text" value="original" />

 

输入域有attribute "value",有一个缺省的值并且这个attribute不会随着用户的输入交互而改变。如果用户输入改变了这个输入域,它在DOM Tree里改变了property的"value"而不是attribute的"value"

 

 

看看 jsfiddle 上 的demo 来理解两者的不同:

http://jsfiddle.net/jquerycookbook/s1gsLcLb/

 

运行演示,一旦你从“original”输入别的东西改变文本框的值,回车。你会看到,ATTR()将返回原来的价值,但prop()返回更改后的值。

 

所以attributes不会改变,但properties可以在后台通过用户操作来改变(选中/取消选中复选框)或以编程方式。

 

因此,什么时候使用什么?如果你想设置一个HTML标记属性的默认值,可以使用ATTR()。然而,当您在窗口或文档对象设置属性,你应该总是使用道具prop()。

 

虽然我用这个文本框例子说明目的,实际上,既不用.attr(),也不用.prop()用于获取/设定值。你应该使用.val()方法。

 

jQuery的1.6之前,我们只有ATTR()。

 

延伸阅读: http://blog.jquery.com/2011/05/12/jquery-1-6-1-released/

 

4 - <script> in head or body?

 

在一个HTML文件里可以在两个地方放置js,在</ body>标记结束之前和<head>里面。网页浏览器处理一个HTML页,从上到下,执行任何它找到<script>标记之间的JavaScript。由于这个原因,如果脚本中的一个需要花费时间来执行,网页的加载被阻止。因此,最好放在body元素结束之前,以确保您的脚本在加载DOM后运行。

 

在我的一些文章,甚至我的书,我经常选择把脚本中的<head>标签里面,但是这仅仅是为了可读性。不过,我也请务必使用$(document).ready() 或快捷方式$(function(){ }),它可确保只有当浏览器加载所有的HTML文档中的内容后脚本才执行。因此,我把脚本放在结束</ body>标签之前达到相同的效果。

 

说了这么多,记住,通过在页面底部引入你的脚本,就可以完全避免使用$(document).ready()。事实上,在我所有的生产准备的应用程序,我的脚本都在页面的底部。

 

5 - Difference between this, $this and $(this)

 

 

让我们用一个例子来理解$this和$(this)的不同。看看下面的代码:

$('div').each(function () {

    var $this = $(this);

    $this.css("background-color", "blue");

    $this.slideUp('3000');

    $this.slideDown('3000');            

});

 

在这里,我们使用each()遍历了一堆div。一旦在你的循环中,this引用的是不是一个jQuery对象的DOM元素。因此,要使它成为一个jQuery对象,并在其上运行jQuery方法,我们用$(this)。现在就来看看这句话中:var $this = $(this);

 

如果你要引用的DOM元素多次在代码中,像我们上面这个例子;那么由于性能考虑,你应该获得一个jQuery的引用它,然后保存到一个变量。在这里,$this是那个变量。这也被称为高速缓存选择器,因为它是昂贵的运行jQuery函数$(this)各一次。因此,存储在一个变量的输出可以让您重用这个选择器,而不会再次调用jQuery函数。

 

注意:不要混淆$this。你可以把它叫做任何你喜欢的。我通常是指包含的jQuery对象作为$ VARIABLENAME变量。

原创文章转载请保留原文链接
英文地址

 

标签 : ,

mysql-5.6 Slave支持crash-safe | ISADBA|FH.CN

mysql异常关机会导致slave复制故障,slave复制中断,解决办法是启用crash-safe,或者找到前一个pos号重新启动进行同步,或者使用relay_log_recovery=ON参数启动。
 
slave支持crash-safe是mysql-5.6复制功能最重要的改进之一。但是如何正确配置开启这个功能呢?我们来澄清一下如何完成.
具体方法:
1、停止slave的mysql实例
2、my.cnf文件中添加relay_log_info_repository=TABLE 和 relay_log_recovery=ON
3、重启slave的mysql实例
 
重要的细节:
为了完全明白为什么要这样设置才能开启crash-safe的功能,首先看看什么原因会导致slave crash后复制中断。
在slave上,复制包含两个线程:
IO线程负责从master拷贝binlog文件保存到本地,拷贝过来的binlog称为relay-log.SQL线程负责执行relay-log.
当前两个线程的执行进度(偏移量)都保存在文件中.IO线程的进度保存在master.info,SQL线程的进度保存在relay-log.info文件。
 
到目前为止还没有问题。第一个问题是这些文件被修改后不是同步写入磁盘的,每当发生crash,存储的偏移量可能都不准确.mysql-5.5修复了这个问题,使用sync_master_info=1和
sync_replay_log_info=1来保证两个文件的修改和写入是一个事务。同步当然不是免费的,需要消耗性能,如果你的raid设备设置为write-back,那么这种方法是可以接受的。
 
但是,即时设置了sync_master_info=1和sync_relay_info=1,坏事还是可能发生。原因是复制信息是在transactions提交后写入的,如果crash发生在事务提交和写文件之间,那么relay-log.info就可能
是错误的。当slave从新启动的时候,最后那个事务可能会被执行两次.具体的影响取决于事务的具体操作.复制可能会继续运行,或者报错,主从数据的一致性可能会被破坏。
 
mysql-5.6可以通过将复制的信息存放到表中代替文件来解决此问题.当relay_log_info_repository=TABLE时,mysql.slave_relay_log_info表会被创建。master_info_repository=TABLE时,mysql.slave_master_info表会被创建.
这个方法很简单,就是把SQL线程的事务和更新mysql.slave_replay_log_info的语句看成一个事务处理,这样就会一直同步的.

伪代码如下:

old:
START TRANSACTION;
--Statement 1
--...
--Statement N
COMMIT;

--Update replication info files

new:
START TRANSACTION;
--...Statement1
.....
--...Statement N
UPdate replication info
COMMIT;
不幸的是,这不是看起来那么简单,现在sql线程看上去没有问题了,但是IO线程,他更新表没有办法依赖任何事务。所以服务器不知道什么时候更新表?
答案就是:通过sync_master_info来控制.默认值是10000,表示IO线程的偏移量每10000个事务更新一次.这个样明显的不能支持slave的crash-safe.一种解决方案是sync_master_info=1,
但是注意,这样会影响性能.
 
另外一种更加高雅的处理方案是使用relay_log_recovery = ON,但是设置这个参数生效,需要服务器重启。这个参数可以让slave重启的时候,抛弃现有的IOthread的偏移量,从slave_relay_log_info表中获取当前的
IO线程偏移量,这样你就不需要以为crash-safe存储IO线程的信息到表里。也就是说master_info_repository = TABLE不是必须的。
 
最后注意,relay_log_info_repository = TABLE和sync_relay_log_info是没有关联的.所以你可以放心的从配置文件中移除sync_relay_log_info。
http://www.mysqlperformanceblog.com/2013/09/13/enabling-crash-safe-slaves-with-mysql-5-6/

+++++++++++++++++++++++++++++++++++++++++++++++++++++++
TIPS:
针对mariadb-10.0.12环境.
还不支持master_info_repository功能.但是支持sync_master_info,sync_relay_log,sync_relay_log_info,relay_log_recovery
所以可以通过这些参数最大限度保证slave crash safe。

阅读全文……

标签 : ,

浏览器缓存机制

 

浏览器缓存机制,其实主要就是HTTP协议定义的缓存机制(如: Expires Cache-control等)。但是也有非HTTP协议定义的缓存机制,如使用HTML Meta 标签,Web开发者可以在HTML页面的<head>节点中加入<meta>标签,代码如下:

html code

<META HTTP-EQUIV="Pragma" CONTENT="no-cache">

上述代码的作用是告诉浏览器当前页面不被缓存,每次访问都需要去服务器拉取。使用上很简单,但只有部分浏览器可以支持,而且所有缓存代理服务器都不支持,因为代理不解析HTML内容本身。

下面我主要介绍HTTP协议定义的缓存机制。

Expires策略

ExpiresWeb服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。

下面是宝宝PK项目中,浏览器拉取jquery.js web服务器的响应头:

clip_image001

注:Date头域表示消息发送的时间,时间的描述格式由rfc822定义。例如,Date: Mon,31 Dec 2001 04:25:57GMT

Web服务器告诉浏览器在2012-11-28 03:30:01这个时间点之前,可以使用缓存文件。发送请求的时间是2012-11-28 03:25:01,即缓存5分钟。

不过Expires HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。

Cache-control策略(重点关注

Cache-ControlExpires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control选择更多,设置更细致,如果同时设置的话,其优先级高于Expires

http协议头Cache-Control   

值可以是publicprivateno-cacheno- storeno-transformmust-revalidateproxy-revalidatemax-age

各个消息中的指令含义如下:

  1. Public指示响应可被任何缓存区缓存。
  2. Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。
  3. no-cache指示请求或响应消息不能缓存
  4. no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。
  5. max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。
  6. min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。
  7. max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

还是上面那个请求,web服务器返回的Cache-Control头的值为max-age=300,即5分钟(和上面的Expires时间一致,这个不是必须的)。

clip_image002

Last-Modified/If-Modified-Since

Last-Modified/If-Modified-Since要配合Cache-Control使用。

l  Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。

l  If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache

Etag/If-None-Match

Etag/If-None-Match也要配合Cache-Control使用。

l  Etagweb服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器觉得)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的

l  If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match Etag的值)web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200304

既生Last-Modified何生Etag

你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新,为什么还需要Etag(实体标识)呢?HTTP1.1Etag的出现主要是为了解决几个Last-Modified比较难解决的问题:

l  Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间

l  如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存

l  有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形

Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-ModifiedETag是可以一起使用的,服务器会优先验证ETag,一致的情况下,才会继续比对Last-Modified,最后才决定是否返回304

用户行为与缓存

浏览器缓存行为还有用户的行为有关!!!

用户操作

Expires/Cache-Control

Last-Modified/Etag

地址栏回车

有效

有效

页面链接跳转

有效

有效

新开窗口

有效

有效

前进、后退

有效

有效

F5刷新

无效

有效

Ctrl+F5刷新

无效

无效

总结

浏览器第一次请求:

clip_image004

浏览器再次请求时:

clip_image006

 

 

 

作者:吴秦
出处:http://www.cnblogs.com/skynet/
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名吴秦(包含链接).

 
 
标签 : ,

如何利用Nginx的缓冲、缓存优化提升性能

使用缓冲释放后端服务器

 

反向代理的一个问题是代理大量用户时会增加服务器进程的性能冲击影响。在大多数情况下,可以很大程度上能通过利用Nginx的缓冲和缓存功能减轻。

 

当代理到另一台服务器,两个不同的连接速度会影响客户的体验:

从客户机到Nginx代理的连接。

从Nginx代理到后端服务器的连接。

 

Nginx具有优化这些连接调整其行为的能力。

 

如果没有缓冲,数据从代理的服务器发送并立即开始被发送到客户。如果假定客户端很快,缓冲可以关闭而尽快使数据到客户端,有了缓冲,Nginx代理将暂时存储后端的响应,然后按需供给数据给客户端。如果客户端是缓慢的,允许Nginx服务器关闭到后端的连接。然后,它可以处理数据分配到客户端,以任何可能的速度。

 

Nginx默认有缓冲设计,因为客户端往往有很大的不同的连接速度。我们可以用以下指令调节缓冲行为。可以在HTTP,server或location位置来设置。重要的是要记住,大小size指令是针对每个请求配置的,所以增加超出你需求会影响你的性能,如果这时有许多客户端请求:

 

proxy_buffering:该指令控制缓冲是否启用。默认情况下,它的值是“on”。

proxy_buffers:该指令控制代理响应缓冲区的数量(第一个参数)和大小(第二个参数)。默认配置是8个缓冲区大小等于一个内存页(4K或者8K)。增加缓冲区的数目可以让你缓冲更多信息。

proxy_buffer_size:从后端服务器的响应头缓冲区大小,它包含headers,和其他部分响应是分开的。该指令设置响应部分的缓冲区大小。默认情况下,它和proxy_buffers是相同的尺寸,但因为这是用于头信息,这通常可以设置为一个较低的值。

proxy_busy_buffers_size:此指令设置标注“client-ready”缓冲区的最大尺寸。而客户端可以一次读取来自一个缓冲区的数据,缓冲被放置在队列中,批量发送到客户端。此指令控制允许是在这种状态下的缓冲空间的大小。

proxy_max_temp_file_size:这是每个请求能用磁盘上临时文件最大大小。这些当上游响应太大不能装配到缓冲区时被创建。

proxy_temp_file_write_size:这是当被代理服务器的响应过大时Nginx一次性写入临时文件的数据量。

proxy_temp_path:当上游服务器的响应过大不能存储到配置的缓冲区域时,Nginx存储临时文件硬盘路径。

正如你所看到的,Nginx提供了相当多的不同的指令来调整缓冲行为。大多数时候,你不必担心太多,但它对于调整一些值可能是有用的。可能最有用的调整是proxy_buffers和proxy_buffer_size指令。

 

一个例子:、

# server context

 

proxy_buffering on;

proxy_buffer_size 1k;

proxy_buffers 24 4k;

proxy_busy_buffers_size 8k;

proxy_max_temp_file_size 2048m;

proxy_temp_file_write_size 32k;

 

location / {

proxy_pass http://example.com;

}

 

配置代理服务缓存来减少响应时间

 

尽管缓冲可以帮助释放后端服务器以处理更多的请求,Nginx还提供了一种方法来缓存从后端服务器的内容,对于许多请求无需连接到上游。

 

配置代理缓存

要设置缓存用于代理内容,我们可以使用proxy_cache_path指令。这将创建区域保存来自被代理服务器返回的数据。该proxy_cache_path指令必须在HTTP上下文部分进行设置。

 

在下面的例子中,我们将配置一些相关的指令来建立我们的缓存系统。

 

# http context

 

proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=backcache:8m max_size=50m;

proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args";

proxy_cache_valid 200 302 10m;

proxy_cache_valid 404 1m;

 

用proxy_cache_path指令,我们首先应该已经定义在文件系统中希望存储缓存的目录。在这个例子中,我们选择在/var/lib/nginx/cache目录。如果该目录不存在,你可以用正确的权限和所有权创建它:

 

sudo mkdir -p /var/lib/nginx/cache

sudo chown www-data /var/lib/nginx/cache

sudo chmod 700 /var/lib/nginx/cache

levels=参数指定缓存将如何组织。 Nginx将通过散列键(下方配置)的值来创建一个缓存键。我们选择了上述的levels决定了单个字符目录(这是散列值的最后一个字符)配有两个字符的子目录(下两个字符取自散列值的末尾)将被创建。你通常不必对这个细节关注,但它可以帮助Nginx快速找到相关的值。

 

keys_zone=参数定义缓存区域的名字,我们称之为backcache。这也是我们定义多少元数据存储的地方。在这个例子里,我们是存储8 MB的key。对于每兆字节,Nginx可存储8000左右的条目。MAX_SIZE参数设置实际缓存数据的最大尺寸。

 

我们使用上面的另一个指令是proxy_cache_key。这个设置将设置用于存储缓存值的键。此键用于检查是否一个请求可以从高速缓存提供服务。我们将它设置成方案(http或https),HTTP请求方法,以及被请求的主机和URI的组合。

 

proxy_cache_valid指令可以被指定多次。它依赖于状态代码值使我们能够配置多长时间存储。在我们的例子中,我们对于后端返回200和302存储10分钟,404响应的一分钟过期。

 

现在,我们已经配置了缓存区,但我们仍然需要告诉Nginx什么时候使用缓存。

 

在我们代理到后端的location位置,我们可以配置使用这个缓存:

 

# server context

 

location /proxy-me {

    proxy_cache backcache;

    proxy_cache_bypass $http_cache_control;

    add_header X-Proxy-Cache $upstream_cache_status;

 

    proxy_pass http://backend;

}

 

 

使用proxy_cache指令,就可以指定该backcache缓存区被用于这个位置。 Nginx会在这里检查传递给后端有效的条目。

 

上述proxy_cache_bypass指令被设置为$ http_cache_control变量。这将包含一个指示器,用以指示该客户端是否被明确地请求一个最新的,非缓存版本。设置此指令允许Nginx正确处理这些类型的客户端请求。无需进行进一步的配置。

 

我们还增加了被称为X-Proxy-Cache的额外头。我们设置这个头部为$ upstream_cache_status变量的值。这个设置头,使我们能够看到,如果请求导致高速缓存命中,高速缓存未命中,或者高速缓存被明确旁路。这是对于调试特别有价值,也对客户端是有用的信息。

 

关于缓存结果的注意事项

 

 

高速缓存能够极大地提高代理服务器的性能。不过,也需要明确的考虑配置缓存时候,要记住。

 

首先,任何用户相关的数据不应被高速缓存。这可能导致一个用户的数据被呈现给其他用户。如果你的网站是完全静态的,这可能不是一个问题。

 

如果你的网站有一些动态元素,你将不得不考虑到这一点。你如何处理要看是什么应用程序或服务器处理的后端处理。对于私人的内容,你应该设置Cache-Control头为“no-cache”,“no-sotre”,或者“private”依赖于数据的性质:

 

no-cache:

请求: 告知缓存者,必须原原本本的转发原始请求,并告知任何缓存者,需要去转发请求,并验证缓存(如果有的话).对应名词:端对端重载.    

响应: 允许缓存者缓存副本.那么其实际价值是,总是强制缓存者,校验缓存的新鲜度.一旦确认新鲜,则可以使用缓存副本作为响应. no-cache,还可以指定某个包含字段,比如一个典型应用,no-cache=Set-Cookie. 这样做的结果,就是告知缓存者,对于Set-Cookie字段,你不要使用缓存内容.而是使用新滴.其他内容则可以使用缓存

no-store:表示在任何时候收到的数据不被缓存。这对于私人数据是最安全,因为它意味着,该数据必须从服务器每次进行检索。

private:这表明共享的缓存空间不能缓存此数据。这可以用于指示用户的浏览器高速缓存数据,但代理服务器不应当考虑随后的请求数据有效。

public:这表明该响应是可在连接的任何点被高速缓存的公共数据。

一个相关的可以控制此行为报头是max-age头,其指示,任何资源应该缓存的秒数。

 

根据内容的敏感性,正确设置这些头,会帮助你利用缓存优势,同时保持你的私人数据安全,并使您的动态数据最新。

 

如果你的后端也使用Nginx,你可以设置使用过期指令,设置max-age来实现Cache-Control:

 

location / {

    expires 60m;

}

 

location /check-me {

    expires -1;

}

在上面的例子中,第一个块允许缓存一个小时的内容。第二块设置Cache-Control头为“无缓存”。要设置其他值,可以使用add_header指令,就像这样:

 

location /private {

    expires -1;

    add_header Cache-Control "no-store";

}

 

 

标签 : ,

图灵社区 : 图书 : 一步步搭建物联网系统

设计物联网系统是件有意思的事情,它需要考虑到软件、硬件、通讯等多个不同方面。通过探索不同的语言,不同的框架,从而形成不同的解决方案。在这里,我们将对设计物联网系统有一个简单的介绍,并探讨如何设计一个最小的物联网系统。

关于内容的选择,这是一个有意思的话题,因为我们很难判断不同的开发者用的是怎样的语言,用的是怎样的框架。 

于是我们便自作主张地选择了那些适合于理论学习的语言、框架、硬件,去除掉其他一些我们不需要考虑的因素,如语法,复杂度等等。当然,这些语言、框架、硬件也是最流行的。 

Arduino: 如果你从头开始学过硬件的话,那么你会爱上它的。 
Raspberry PI: 如果你从头编译过GNU/Linux的话,我想你会爱上她的。 
Python: 简单地来说,你可以方便地使用一些扩展,同时代码就表达了你的想法。 
PHP : 这是一门容易部署的语言,我想你只需要在你的Ubuntu机器上,执行一下脚本就能完成安装了。而且,如果你是一个硬件开发者的话,你会更容易地找到其他开发者。 
Javascript : 考虑到javascript这门语言已经无处不在了,而且会更加流行。所以,在这里CoAP、MQTT等版本是基于Nodejs的。 
HTML、CSS : 这是必须的,同样,他们仍然无处不在。 
GNU/Linux: 作为部署到服务器的一部分——你需要掌握他。当然如果你要用WAMP也是可以的。 
CoAP: 用NodeJS构建IOT CoAP物联网 

本文档对一些概念(如)只做了一些基本介绍,以方便读者理解。如果您想进一步了解这些知识,会列出一些推荐书目,以供参考。

作者黄峰达,1991年出生于闽南,双子座,毕业于西安文理学院。 
农村长大,热爱大自然,热爱生活。和哈比特人一样喜欢土地里长出来的东西。 
是一个文艺控。喜欢读书,喜欢纸的质感,喜欢用笔铭刻记忆和思想。 
是一个设计控,一个DIY爱好者。喜欢自行设计一些小东西,相比理论而言更喜欢动手实践,比如拆装自己的手机、电脑等。 
最喜欢折腾与计算机相关的东西:SEO、前端开发、硬件相关(如:Raspberry Pi,51,Arduino,OpenWRT,uCOS...)。 
在编程的路上已经走了较长一段,但始终相信前路更长更加广阔。

阅读全文……

标签 :

Nginx负载均衡服务器实现会话粘贴的几种方式

1、使用Nginx 的ip_hash作为负载均衡服务并支持Session sticky 

2、使用nginx sticky第三方模块实现基于cookie的负载均衡 

3、使用nginx的map指令根据cookie分流:

map $COOKIE_abcdexpid $group {
	~*1$	apache001;
	~*2$	apache002;
	default	root;
}
 
upstream apache001 {
	server 192.168.1.1:8080 weight=1 max_fails=1 fail_timeout=30s;
}
 
upstream apache002 {
	server 192.168.1.2:8080 weight=1 max_fails=1 fail_timeout=30s;
}
 
upstream root {
	server 192.168.1.0:8080 weight=1 max_fails=1 fail_timeout=30s;
}
 
server {
	listen       8080;
	server_name  neoremind.net;
 
	log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
					  '$status $body_bytes_sent "$http_referer" "group=$group"'
					  '"$http_user_agent" $gzip_ratio $request_time "$http_x_forwarded_for"';
 
	access_log  logs/access_log main;
	error_log   logs/error_log;
 
	location / {
        proxy_pass http://$group;
		proxy_set_header X-Forwarded-For $remote_addr;
    }	
}

 4、利用set和if…else… 根据cookie分流

 

upstream apache001 {
	server 192.168.1.1:8080 weight=1 max_fails=1 fail_timeout=30s;
}
 
upstream apache002 {
	server 192.168.1.2:8080 weight=1 max_fails=1 fail_timeout=30s;
}
 
upstream root {
	server 192.168.1.0:8080 weight=1 max_fails=1 fail_timeout=30s;
}
 
server {
	listen       8080;
	server_name  beidoutest.baidu.com;
 
	#match cookie
	set $group "root";
	if ($http_cookie ~* "abcdexpid=([^;]+)(1$)"){
		set $group apache001;
	}
	if ($http_cookie ~* "abcdexpid=([^;]+)(2$)"){
		set $group apache002;
	}
 
	log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
					  '$status $body_bytes_sent "$http_referer" "group=$group"'
					  '"$http_user_agent" $gzip_ratio $request_time "$http_x_forwarded_for"';
 
	access_log  logs/access_log main;
	error_log   logs/error_log;
 
	location / {
		proxy_pass http://$group;
		proxy_set_header X-Forwarded-For $remote_addr;
	}
 
}

 

 

5、nginx1.7.2版本后提供的hash方法:

# http context  
upstream backend_hosts {      
hash $cookie_JSESSIONID consistent;      
server host1.example.com;     
server host2.example.com;     
server host3.example.com; 

             } 

 

提升tomcat服务器性能的七条经验

1. 服务器资源

    服务器所提供足够CPU、内存、硬盘

2. 利用缓存和压缩

         企业nginx的gzip,客户端资源文件缓存,服务器端页面缓存,数据库缓存等等

3. 采用集群

         Nginx负载均衡,加上Tomcat的session共享或复制集群

4. 优化tomcat参数

    这里以tomcat7的参数配置为例,需要修改conf/server.xml文件,主要是优化连接配置,关闭客户端dns查询。

  1. <Connector port="8080"   
  2.            protocol="org.apache.coyote.http11.Http11NioProtocol"  
  3.            connectionTimeout="20000"  
  4.            redirectPort="8443"   
  5.            maxThreads="500"   
  6.            minSpareThreads="20"  
  7.            acceptCount="100" 
  8.            disableUploadTimeout="true" 
  9.            enableLookups="false"   
  10.            URIEncoding="UTF-8" /> 

5. 改用APR库

    tomcat默认采用的BIO模型,在几百并发下性能会有很严重的下降。tomcat自带还有NIO的模型,另外也可以调用APR的库来实现操作系统级别控制。

    NIO模型是内置的,调用很方便,只需要将上面配置文件中protocol修改成org.apache.coyote.http11.Http11NioProtocol,重启即可生效。上面配置我已经改过了,默认的是HTTP/1.1。

    APR则需要安装第三方库,在高并发下会让性能有明显提升。具体安装办法可以参考http://www.cnblogs.com/huangjingzhou/articles/2097241.html。安装完成后重启即可生效。如使用默认protocal就是apr,但最好把将protocol修改成org.apache.coyote.http11.Http11AprProtocol,会更加明确

    在官方找到一个表格详细说明了这三种方式的区别:

  1.                   Java Blocking Connector   Java Nio Blocking Connector   APR/native Connector 
  2.                              BIO                         NIO                       APR 
  3. Classname                AjpProtocol               AjpNioProtocol           AjpAprProtocol 
  4. Tomcat Version           3.x onwards                 7.x onwards              5.5.x onwards 
  5. Support Polling              NO                          YES                       YES 
  6. Polling Size                 N/A                   maxConnections             maxConnections 
  7. Read Request Headers      Blocking                  Sim Blocking                   Blocking 
  8. Read Request Body         Blocking                  Sim Blocking                   Blocking 
  9. Write Response            Blocking                  Sim Blocking                   Blocking 
  10. Wait for next Request     Blocking                  Non Blocking               Non Blocking 
  11. Max Connections        maxConnections              maxConnections             maxConnections 

6. 优化网络

    Joel也明确提出了优化网卡驱动可以有效提升性能,这个对于集群环境工作的时候尤为重要。由于我们采用了linux服务器,所以优化内核参数也是一个非常重要的工作。给一个参考的优化参数:

  1. 1. 修改/etc/sysctl.cnf文件,在最后追加如下内容: 
  2.  
  3. net.core.netdev_max_backlog = 32768 
  4. net.core.somaxconn = 32768 
  5. net.core.wmem_default = 8388608 
  6. net.core.rmem_default = 8388608 
  7. net.core.rmem_max = 16777216 
  8. net.core.wmem_max = 16777216 
  9. net.ipv4.ip_local_port_range = 1024 65000 
  10. net.ipv4.route.gc_timeout = 100 
  11. net.ipv4.tcp_fin_timeout = 30 
  12. net.ipv4.tcp_keepalive_time = 1200 
  13. net.ipv4.tcp_timestamps = 0 
  14. net.ipv4.tcp_synack_retries = 2 
  15. net.ipv4.tcp_syn_retries = 2 
  16. net.ipv4.tcp_tw_recycle = 1 
  17. net.ipv4.tcp_tw_reuse = 1 
  18. net.ipv4.tcp_mem = 94500000 915000000 927000000 
  19. net.ipv4.tcp_max_orphans = 3276800 
  20. net.ipv4.tcp_max_syn_backlog = 65536 
  21.  
  22. 2. 保存退出,执行sysctl -p生效 
  23.  

将Session会话存储在Redis并使用Nginx来实现Tomcat负载均衡

一段时间以来,我一直在寻找一种方式来发布代码到生产系统而不需要宕机,不影响任何活动用户。出人意料的是,该解决方案花了很少的时间就实现了。我们有Nginx负载平衡的Tomcat两个实例。Tomcat的Session存储在Redis里。 nginx配置成无粘性的,因为一个请求可以分到群集中的任何节点。当我们需要发布新代码,只需停下任何Tomcat实例。当前所有用户将被路由到其他活动实例。由于会话数据外部存储在Redis,活跃的用户将不会受到影响。一旦不活动实例已被更新,重启并可恢复服务。

 

我们先从Nginx开始:

[raoul@raoul-wp ~]$ sudo rpm -ivh nginx-1.4.2-1.el6.ngx.x86_64.rpm

 

编辑/etc/nginx/nginx.conf并添加下面文字

http {
2.upstream tomcat  {
3.server localhost:8080;
4.server localhost:8081;
5.}
6.include       /etc/nginx/mime.types;
7.default_type  application/octet-stream;

修改/etc/nginx/conf.d/default.conf,用下面的替换location部分:

location / {
2.proxy_pass  http://tomcat;

 重启Nginx:

[raoul@raoul-wp nginx]$ sudo service nginx restart

 

接下来,安装Tomcat两个实例。改变第二个实例的服务器端口,使他们不冲突。如果你在浏览器中输入https://localhost,将进入默认的tomcat页面。但是,由于我们还没有建立粘性会话,每个请求将以轮询的方式获得负载平衡,这实际上意味着它会每个请求创建一个新的会话。使用内置的tomcat的例子可以很容易地看到这种行为,导航到http://localhost/examples/servlets/servlet/SessionExample 并刷新此页面几次,并注意会话ID每次都改变。现在来解决这个问题。

 

下载并安装Redis。在http://redis.io/download有个好文档,所以不打算详谈。启动服务器,并使用客户端程序检查它是否正常工作。

最后,需要配置Tomcat来存储会话在Redis。为此,我们将使用Tomcat的Redis会话管理器(https://github.com/jcoleman/tomcat-redis-session-manager)。这个不能开箱即用需要进行一些调整。您需要下载这个项目的源代码,并更新相关的库版本后,重新构建它。我用的版本是commons-pool2-2.2.jar和jedis-2.6.1.jar。将这些JAR复制到两个Tomcat实例的lib目录。

 

更新在   tomcat-redis-session-manager 中build.gradle指定的commons-pool,jedis和tomcat的版本,构建项目。然后将tomcat-redis-session-manager-1.2.jar复制到每个实例的tomcat的lib目录下。修改两个tomcat的context.xml:

<Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" />
2.<Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager"
3.host="localhost"
4.port="6379"
5.database="0"
6.maxInactiveInterval="60" />

重新启动Tomcat实例,我们就大功告成了。现在你可以看到Tomcat的会话存储在Redis了。转载请保留原文链接.

几个可用于数据挖掘和统计分析的java库

WEKA:WEKA是一个可用于数据挖掘任务的机器学习算法集合。该算法可以直接应用到数据集或从自己的Java代码调用。 WEKA包含数据预处理,分类,回归,聚类,关联规则,和可视化工具。它也非常适用于开发新的机器学习方案。

jmotif:时间序列、分类、数据挖掘开发库

java-ml:Java机器学习库,聚类、分类、特征选择、

flanagan: 数学和统计java开发库,包含回归算法,一次二次线性非线性回归算法,数据平滑算法,傅里叶变换,数值积分,插值法。http://www.ee.ucl.ac.uk/~mflanaga/java/

Mahout:Apache Mahout 是 Apache Software Foundation(ASF) 旗下的一个开源项目,提供一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建智能应用程序。经典算法包括聚类、分类、协同过滤、进化编程等等,并且,在 Mahout 的最近版本中还加入了对 Apache Hadoop 的支持,使这些算法可以更高效的运行在云计算环境中。

matlab:

JMulTi:时间序列分析开发库

标签 :

Drill:企业级Hadoop和NoSQL的SQL查询引擎

 

Apache的Drill是一个开源的,用于Hadoop和NoSQL的低延迟SQL查询引擎。

 

现代大数据的应用,如社交,移动互联网,互联网和物联网有着大量的用户,比传统的事务应用程序更大的数据量。这些应用程序相关的数据集的发展非常迅速,往往是自我描述,可以包括复杂的类型,比如JSON,和Parquet。 Apache的Drill从底层建立了可伸缩性地提供低延迟查询对这种快速发展的多结构化数据集。

 

零日分析及快速应用开发

 

Apache的Drill可以直接查询自我描述和半结构化数据文件(如JSON,,Parquet)和HBase表,而无需定义和维护架构的集中存储,如Hive里metastore。这意味着用户可以在线探索数据,而以前需要数据准备,建模,ETL和随后的管理模式花费数周或数月时间。

 

专为半结构化/嵌套数据

 

Drill提供了一个像JSON般的内部数据模型来表示和处理数据。这个数据模型的灵活性允许Drill查询,不压扁,既简单又复杂/嵌套数据类型以及不断变化的常见于Hadoop/ NoSQL的应用程序驱动的模式。Drill还提供了直观的扩展SQL复杂/嵌套数据类型的工作。

 

与现有的SQL环境的和Apache Hive兼容

 

使用Drill,企业可以最大限度地降低转换成本和学习曲线,为用户提供熟悉的ANSI SQL语法。分析师可以继续使用该工具并自动生成ANSI SQL代码,通过利用Drill公开标准的JDBC/ ODBC接口使用Hadoop数据交互和熟悉的BI /分析工具。用户还可以通过即插即用使用Hive环境,低延迟的即席查询现有的Hive里表和重用Hive里的元数据,数以百计的文件格式和UDF开箱。

转载请保留原文链接

SourceForge上的FileZilla是个恶意软件

SourceForge上actioncheese评论道:

SourceForge下载的 FileZilla FTP 软件中发现包含多个恶意软件,其中包括isearch.omiga-plus.com浏览器劫持。虽然容易清除,它改变了你的默认主页设置,并添加主页地址到浏览器图标的目标地址。我希望一个狡猾的下载网站的行为,不是来自Sourceforge。 FileZilla是伟大的软件,我以前极力推荐:) 不过这个评论仍然得到一个1星的话我必须得卸载它。

 

也有网友说:“我没有注意到不好的评论,因为几个月前,我下载它安装在一台电脑,并且安装得很顺利。我重新启动Windows后,每次我连接到互联网,我的Windows就死机,而且没有办法恢复正常。我不确定FileZilla是否被SourceForge强制使用坏的安装程序,因为我从SourceForge下载其他程序的安装程序,一切都进行得很顺利。”

 

FileZilla是一种快速、可信赖的FTP客户端以及服务器端开放源代码程序,具有很多丰富的功能。

 

FileZilla在2003年11月获选为SourceForge.net当月最佳推荐项目

FileZilla功能有:

  • 可以断点续传进行上传、下载(需要服务器支持)
  • 自定义命令
  • 可进行站点管理
  • 防超时功能(有的FTP服务器会将超时过久的用户赶出,这样超时的用户就得重复登录)
  • 超时侦测
  • 支持防火墙
  • 支持SOCKS4/5、HTTP1.1代理
  • 可进行SSL加密连接
  • 支持SFTP(Secure FTP)
  • 可以排队进行上传、下载
  • 支持拖放
  • 多国语言支持,包括简体、繁体中文(Linux平台需额外安装“filezilla-locales”包)
  • 可通过Kerberos进行GSS验证与加密

转载请保留 原文地址

标签 : , ,

Hue ——一个用于Apache Hadoop大数据分析的Web界面应用

Hue是一个用于Apache Hadoop分析数据的Web界面。它支持文件和作业浏览器,Hive,Pig,Impala,Spark,Oozie的编辑器,Solr的搜索仪表板,HBase,Sqoop2,等等。

Hue官方网站:http://gethue.com

 

它的特点: 

  • 文件浏览器用于访问HDFS
  • 编辑器开发和运行Hive查询
  • 搜索应用程序查询,探索,可视化数据和仪表板使用Solr
  • Impala应用程序执行交互式SQL查询
  • Spark编辑器和Dashboard
  • Pig编辑器提交Pig脚本
  • Oozie的编辑器和Dashboard提交和监控工作流程,协管员和调度
  • HBase浏览器的可视化,查询和修改HBase的表
  • 用于访问Hive元数据和HCatalog 的Metastore浏览器
  • 作业浏览器用于访问MapReduce作业(MR1/ MR2-YARN)
  • 作业设计器用于创建MapReduce/流/ Java的作业
  • 一个Sqoop2编辑器和Dashboard
  • ZooKeeper浏览器和编辑器
  • 一个DB查询编辑器可用于MySQL,Postgres,SQLite和Oracle
  • 最重要的是,一个SDK可用于创建集成Hadoop的新的应用程序。

ElasticSearch: Java API | Javalobby

ElasticSearch Java API 官方文档:

http://www.elasticsearch.org/guide/en/elasticsearch/client/java-api/current/index.html

ElasticSearch提供了Java API,因此可通过使用Client对象异步执行所有操作。Client对象可以批量执行操作,累计。 Java的API可以在内部使用,以执行所有的API在ElasticSearch。

在本教程中,我们将考虑如何开展将Java API一些操作用在一个独立的Java应用程序里,类似于那些我们在上一篇文章中做的。

Dependency

ElasticSearch托管于Maven的中央。在你的Maven项目,你可以定义你想要的,如下图所示在你的pom.xml文件使用哪个版本ElasticSearch:

 

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>0.90.3</version>
</dependency>

 

 

Client

使用Client,您可以执行在正在运行的群集管理任务,如一些操作,如标准索引,get,删除和搜索操作,在现有的集群中。另外,还可以启动所有节点。


获得ElasticSearchclient的最常见的方式是建立它就像在一个群集中的节点的嵌入式节点以及请求客户端从该嵌入节点。


另一种方式获得客户端是创建TransportClient(它从远程连接集群通过使用transport组件),其连接到群集的另一种方式。


应该考虑使用客户端和集群的相同版本,当使用Java API时。客户端和群集版本之间的差异可能会导致某些不兼容性。

 

Node Client

The simplest way of getting a client instance is the node based client. 

 

Node node  = nodeBuilder().node();
Client client = node.client();

 

When a node is started, it joins to the "elasticsearch" cluster. You can create different clusters using the cluster.name setting or clusterName method in the/src/main/resources directory and in elasticsearch.yml file in your project:

 

cluster.name: yourclustername

 

Or in Java code:

 

Node node = nodeBuilder().clusterName("yourclustername").node();
Client client = node.client();

 

Creating Index

 

The Index API allows you to type a JSON document into a specific index, and makes it searchable. There are different ways of generating JSON documents. Here we used map, which represents JSON structure very well. 

 

public static Map<String, Object> putJsonDocument(String title, String content, Date postDate, 
                                                      String[] tags, String author){
        
        Map<String, Object> jsonDocument = new HashMap<String, Object>();
        
        jsonDocument.put("title", title);
        jsonDocument.put("conten", content);
        jsonDocument.put("postDate", postDate);
        jsonDocument.put("tags", tags);
        jsonDocument.put("author", author);
        
        return jsonDocument;
    }

 

Node node    = nodeBuilder().node();
Client client   = node.client();
        
client.prepareIndex("kodcucom", "article", "1")
              .setSource(putJsonDocument("ElasticSearch: Java API",
                                         "ElasticSearch provides the Java API, all operations "
                                         + "can be executed asynchronously using a client object.",
                                         new Date(),
                                         new String[]{"elasticsearch"},
                                         "Hüseyin Akdoğan")).execute().actionGet();
                
        node.close();

 

With the above code, we generate an index by the name of kodcucom and a type by the name of article with standard settings and a record (we don’t have to give an ID here) whose ID value of 1 is stored to ElasticSearch. 

 

Getting Document

The Get API allows you to get a typed JSON document, based on the ID, from the index. 

 

GetResponse getResponse = client.prepareGet("kodcucom", "article", "1").execute().actionGet();

Map<String, Object> source = getResponse.getSource();
        
System.out.println("------------------------------");
System.out.println("Index: " + getResponse.getIndex());
System.out.println("Type: " + getResponse.getType());
System.out.println("Id: " + getResponse.getId());
System.out.println("Version: " + getResponse.getVersion());
System.out.println(source);
System.out.println("------------------------------");

 

Search

The Search API allows you to execute a search query and get the matched results. The query can be executed across more than one indices and types. The query can be provided by using query Java API or filter Java API. Below you can see an example whose body of search request is built by using SearchSourceBuilder. 

 

public static void searchDocument(Client client, String index, String type,
                                      String field, String value){
        
        SearchResponse response = client.prepareSearch(index)
                                        .setTypes(type)
                                        .setSearchType(SearchType.QUERY_AND_FETCH)
                                        .setQuery(fieldQuery(field, value))
                                        .setFrom(0).setSize(60).setExplain(true)
                                        .execute()
                                        .actionGet();
        
        SearchHit[] results = response.getHits().getHits();
        
        System.out.println("Current results: " + results.length);
        for (SearchHit hit : results) {
            System.out.println("------------------------------");
            Map<String,Object> result = hit.getSource();   
            System.out.println(result);
        }
        
    }

 

searchDocument(client, "kodcucom", "article", "title", "ElasticSearch");

 

Updating

Below you can see an example of a field update.

 

public static void updateDocument(Client client, String index, String type, 
                                      String id, String field, String newValue){
        
        Map<String, Object> updateObject = new HashMap<String, Object>();
        updateObject.put(field, newValue);
        
        client.prepareUpdate(index, type, id)
              .setScript("ctx._source." + field + "=" + field)
              .setScriptParams(updateObject).execute().actionGet();
    }

 

updateDocument(client, "kodcucom", "article", "1", "tags", "big-data");

 

Deleting

The delete API allows you to delete a document whose ID value is specified. You can see below an example of deleting a document whose index, type and value is specified. 

 

public static void deleteDocument(Client client, String index, String type, String id){
        
        DeleteResponse response = client.prepareDelete(index, type, id).execute().actionGet();
        System.out.println("Information on the deleted document:");
        System.out.println("Index: " + response.getIndex());
        System.out.println("Type: " + response.getType());
        System.out.println("Id: " + response.getId());
        System.out.println("Version: " + response.getVersion());
    }

 

deleteDocument(client, "kodcucom", "article", "1");

See the sample application here.

 

Adding mapping to a type from Java (索引库中索引的字段名及其数据类型进行定义,包括是否存储、分词)

 

 
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
 
import java.io.IOException;
 
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.get.GetRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
 
public class MyTestClass {
 
    private static final String ID_NOT_FOUND = "<ID NOT FOUND>";
 
    private static Client getClient() {
        final ImmutableSettings.Builder settings = ImmutableSettings.settingsBuilder();
        TransportClient transportClient = new TransportClient(settings);
        transportClient = transportClient.addTransportAddress(new InetSocketTransportAddress("localhost", 9300))
        .addTransportAddress(new InetSocketTransportAddress("localhost", 9301));
        return transportClient;
    }
 
    public static void main(final String[] args) throws IOException, InterruptedException {
 
        final Client client = getClient();
        // Create Index and set settings and mappings
        final String indexName = "test";
        final String documentType = "tweet";
        final String documentId = "1";
        final String fieldName = "title";
        final String value = "bar";
 
        final IndicesExistsResponse res = client.admin().indices().prepareExists(indexName).execute().actionGet();
        if (res.isExists()) {
            final DeleteIndexRequestBuilder delIdx = client.admin().indices().prepareDelete(indexName);
            delIdx.execute().actionGet();
        }
 
        final CreateIndexRequestBuilder createIndexRequestBuilder = client.admin().indices().prepareCreate(indexName);
 
        // MAPPING GOES HERE
 
//        final XContentBuilder mappingBuilder = jsonBuilder().startObject().startObject(documentType)
//                .startObject("_ttl").field("enabled", "true").field("default", "1s").endObject().endObject()
//                .endObject();
        XContentBuilder mapping = jsonBuilder()  
              .startObject()  
                .startObject(documentType)  
                .startObject("properties")         
                  .startObject("title").field("type", "string").field("store", "yes").endObject()    
                  .startObject("description").field("type", "string").field("index", "not_analyzed").endObject()  
                  .startObject("price").field("type", "double").endObject()  
                  .startObject("onSale").field("type", "boolean").endObject()  
                  .startObject("type").field("type", "integer").endObject()  
                  .startObject("createDate").field("type", "date").endObject()                 
                .endObject()  
               .endObject()  
             .endObject();          
        System.out.println(mapping.string());
        createIndexRequestBuilder.addMapping(documentType, mapping);
 
        // MAPPING DONE
        createIndexRequestBuilder.execute().actionGet();
 
        // Add documents
        final IndexRequestBuilder indexRequestBuilder = client.prepareIndex(indexName, documentType, documentId);
        // build json object
        final XContentBuilder contentBuilder = jsonBuilder().startObject().prettyPrint();
        contentBuilder.field(fieldName, value);
 
        indexRequestBuilder.setSource(contentBuilder);
        indexRequestBuilder.execute().actionGet();
 
        // Get document
        System.out.println(getValue(client, indexName, documentType, documentId, fieldName));
 
        int idx = 0;
        while (true) {
            Thread.sleep(10000L);
            idx++;
            System.out.println(idx * 10 + " seconds passed");
            final String name = getValue(client, indexName, documentType, documentId, fieldName);
            if (ID_NOT_FOUND.equals(name)) {
                break;
            } else {
                // Try again
                System.out.println(name);
            }
        }
        System.out.println("Document was garbage collected");
    }
 
    protected static String getValue(final Client client, final String indexName, final String documentType,
            final String documentId, final String fieldName) {
        final GetRequestBuilder getRequestBuilder = client.prepareGet(indexName, documentType, documentId);
        getRequestBuilder.setFields(new String[] { fieldName });
        final GetResponse response2 = getRequestBuilder.execute().actionGet();
        if (response2.isExists()) {
            final String name = response2.getField(fieldName).getValue().toString();
            return name;
        } else {
            return ID_NOT_FOUND;
        }
    }
 
}

 

阅读全文……

标签 : , ,