Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 11805 articles
Browse latest View live

FastDFS分布式文件系统

$
0
0

一,简介

       FastDFS是一个开源的轻量级 分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务,如相册网站、视频网站等等。使用纯C语言实现,支持Linux、FreeBSD、AIX等UNIX系统。同时FastDFS提供了Java,C和PHP等语言的客户端API,我们可以在应用服务端通过API操作文件系统。

二,原理分析

      FastDFS包含两种角色:跟踪器Tracker和存储节点Storage,都可以单台或多台部署。

      Storage存储节点的 分组(同一组内的存储节点文件完全一致,负载均衡分摊IO压力):

     

 

      类Google FS都支持文件冗余备份,例如Google FS、TFS的备份数是3。一个文件存储到哪几个存储结点,通常采用动态分配的方式。 采用这种方式,一个文件存储到的结点是不确定的。举例说明,文件备份数是3,集群中有A、B、C、D四个存储结点。文件1可能存储在A、B、C三个结点, 文件2可能存储在B、C、D三个结点,文件3可能存储在A、B、D三个结点。

      FastDFS采用了分组存储方式。集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容量之和。一个组由一台或多台存储服务器组成,同组内的多台Storage server之间是互备关系,同组存储服务器上的文件是完全一致的。文件上传、下载、删除等操作可以在组内任意一台 Storage server上进行。类似木桶短板效应,一个组的存储容量为该组内存储服务器容量最小的那个,由此可见组内存储服务器的软硬件配置最好是一致的。

     采用分组存储方式的好处是灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组。一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向扩容)。当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。采用这样的分组存储方式,可以使用FastDFS对文件进行管理,使用主流的Web server如Apache、nginx等进行文件下载。

     文件上传流程:

      enter image de.ion here

            流程描述:

             1,当集群中不止一台跟踪器tracker server时,由于tracker之间是完全对等的,客户端在上传文件时可以任务选择其中的一台进行连接。

             2,选择文件存储节点的分组group。当tracker接收到client上传文件的请求时,会为该文件分配一个可以存储该文件的group(存储节点组),当然客户端也可以手动指定存储该文件的组。自动分配的策略有1,Round robin(所有存储节点组group轮询选择);2,Load balance(剩余空间的多的group优先,存储节点Storage与跟踪器tracker之间建立socket长连接,实时向tracker跟踪器汇报空间大小等存储信息)。

             3,选择分组下的一个存储节点Storage。当选定一个存储节点组group之后,接下来则需选择一个具体的存储节点Storage,具体策略有1,Round robin(该存储节点组group内轮询选择);2,First server ordered by ip(按ip排序);3,First server ordered by priority(按Storage存储节点设置的优先级排序,优先存储在级别高的Storage,该Storage存写binlog日志,然后该group内的其他存储节点基于binlog进行复制,保证最后group内所有存储节点文件完全一致)。

            4,选择Storage path。当分配好存储节点Storage server之后,接下来则是选择存储路径,Storage 会为文件分配一个存储目录,支持如下规则1,Round robin(多个存储目录间轮询);2,剩余存储空间最多的优先。  

            5,生成全局唯一的字符串File ID。由Storage server ip + 文件创建时间 + 文件大小 + 文件crc32 +随机数,然后进行base64编码而成的字符串。

            6,当选定存储目录之后,storage会为文件分配一个File ID,每个存储目录下有两级256*256的子目录,storage会按文件fileid进行两次hash(猜测),路由到其中一个子目录,然后将文件以fileid为文件名存储到该子目录下。

           7,生成文件名。当文件存储到某个子目录后,即认为该文件存储成功,接下来会为该文件生成一个文件名,文件名由group、存储目录、两级子目录、File ID、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。

          enter image de.ion here

          文件下载流程:

          enter image de.ion here

          文件下载流程分析:

          跟upload file一样,在download file时客户端可以选择任意tracker server。client发送download请求给某个tracker,必须带上文件名信息,tracke从文件名中解析出文件的group、大小、创建时间等信息,然后为该请求选择一个storage用来服务读请求。由于group内的文件同步时在后台异步进行的,所以有可能出现在读到时候,文件还没有同步到某 些storage server上,为了尽量避免访问到这样的storage,tracker按照如下规则选择group内可读的storage。

        选择读的storage规则:1. 该文件上传到的源头storage - 源头storage只要存活着,肯定包含这个文件,源头的地址被编码在文件名中。 2. 文件创建时间戳==storage被同步到的时间戳 且(当前时间-文件创建时间戳) > 文件同步最大时间(如5分钟) - 文件创建后,认为经过最大同步时间后,肯定已经同步到其他storage了。 3. 文件创建时间戳 < storage被同步到的时间戳。 - 同步时间戳之前的文件确定已经同步了 4. (当前时间-文件创建时间戳) > 同步延迟阀值(如一天)。 - 经过同步延迟阈值时间,认为文件肯定已经同步了。

三,HTTP访问支持

       FastDFS的tracker和storage都内置了http协议的支持,客户端可以通过http协议来下载文件,tracker在接收到请求时,通 过http的redirect机制将请求重定向至文件所在的storage上;除了内置的http协议外,FastDFS还提供了通过 apache或nginx扩展模块下载文件的支持。

       enter image de.ion here

四,分布式文件系统对比

       FastDFS与HDFS,TFS等特性比较。TFS是淘宝使用的分布式文件系统,用于海量小文件的存储,但使用和部署过于复杂,不够轻量化。HDFS是Hadoop分布式计算使用的文件系统,主要解决并行计算中分布式存储数据的问题。其单个数据文件通常很大,采用了分块(切分)存储的方式。

        

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




高可用消息队列框架ZBUS

$
0
0

我们在日常开发中可以需要用到消息队列 当然我们完全可以自己写一个生产者-消费者框架 但是高可用性、实时性已经大量数据堆积时候就显得问题捉襟见肘了下面推荐的框架在我时间项目中和测试中都是非常不错那么他是什么框架呢?

   zbus git地址 http://git.oschina.net/rushmore/zbus ZBUS=MQ+RPC 服务总线 1)支持消息队列, 发布订阅, RPC, 交易系统队列适配 2)亿级消息堆积能力、支持HA高可用 3)无依赖单个Jar包 ~300K 4)丰富的API--JAVA/C/C++/C#/Python/Node.JS多语言接入,支持HTTP等协议长连接入。。。详情见git描述。

 

ZBUS--轻量级MQ、RPC、服务总线

ZBUS = MQ + RPC + PROXY

  • 支持消息队列, 发布订阅, RPC, 代理(TCP/DMZ)
  • 亿级消息堆积能力、支持HA高可用
  • 单个Jar包无依赖 ~300K
  • 服务代理 -- 适配改造已有业务系统,使之具备跨平台与语言
  • 丰富的API--JAVA/C/C++/C#/Python/Node.JS多语言接入

 怎样使用呢?

  很简单在项目中直接引入zbus-6.2.0.jar  开发c-p

 

  p:

   
public class ConsumerExample {
 public static void main(String[] args) throws Exception{ 
  //创建Broker代表
  BrokerConfig brokerConfig = new BrokerConfig();
  brokerConfig.setServerAddress("127.0.0.1:15555");
  Broker broker = new SingleBroker(brokerConfig);
  
  MqConfig config = new MqConfig();
  config.setBroker(broker);
  config.setMq("MyMQ");
  
  //创建消费者
  @SuppressWarnings("resource")
  Consumer c = new Consumer(config); 
  c.onMessage(new MessageHandler() {
   @Override
   public void handle(Message msg, Session sess) throws IOException {
    System.out.println(msg);
   }
  });
  
  c.start();
 }
}

  c:public static void main(String[] args) throws Exception {
  //创建Broker代理
  BrokerConfig config = new BrokerConfig();
  config.setServerAddress("127.0.0.1:15555");
  final Broker broker = new SingleBroker(config);
 
  Producer producer = new Producer(broker, "MyMQ");
  producer.createMQ(); // 如果已经确定存在,不需要创建

  //创建消息,消息体可以是任意binary,应用协议交给使用者
  
  long total = 0;
  for(int i=0;i<1000000000;i++){
   long start = System.currentTimeMillis();
   Message msg = new Message();
   msg.setBody("hello world"+i);
  
   producer.sendSync(msg); 
   long end = System.currentTimeMillis();
   total += (end-start);
   System.out.format("Time: %.1f\n", total*1.0/(i+1));
  }
  
  broker.close();
 }

  启动zbus服务  zbus.bat批处理文件 需要注意设置 jdk路径

   REM SET JAVA_HOME=C:\Program Files\Java\jdk1.7.0_80

SET ZBUS_HOME=.
SET JAVA_OPTS=-server -Xms64m -Xmx1024m -XX:+UseParallelGC
SET MAIN_CLASS=org.zbus.mq.server.MqServer
SET MAIN_OPTS=-h 0.0.0.0 -p 15555 -thrift 0.0.0.0:25555 -verbose false -store store -track
SET LIB_OPTS=%ZBUS_HOME%/lib;%ZBUS_HOME%/*;

IF NOT EXIST "%JAVA_HOME%" (
    SET JAVA=java
) ELSE (
    SET JAVA=%JAVA_HOME%\bin\java
)
"%JAVA%" %JAVA_OPTS% -cp %LIB_OPTS% %MAIN_CLASS% %MAIN_OPTS%

  

 ok 可以开始体验了!!!



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



HTTP 断点续传

$
0
0

所谓断点续传,也就是要从文件已经下载的地方开始继续下载。在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。一般断点下载时才用到 Range 和 Content-Range 实体头。

   Range 

  用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:

  Range:(unit=first byte pos)-[last byte pos] 

   Content-Range

  用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式: 

  Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth] 

   请求下载整个文件: 

  1. GET /test.rar HTTP/1.1 
  2. Connection: close 
  3. Host: 116.1.219.219 
  4. Range: bytes=0-801 //一般请求下载整个文件是bytes=0- 或不用这个头

   一般正常回应

  1. HTTP/1.1 200 OK 
  2. Content-Length: 801      
  3. Content-Type: application/octet-stream 
  4. Content-Range: bytes 0-800/801 //801:文件总大小

If-Range = “If-Range” “:” ( entity-tag | HTTP-date )

IF-Range头部需配合Range,如果没有Range参数,则If-Range会被视为无效。

如 果If-Range匹配上,那么客户端已经存在的部分是有效的,服务器将返回缺失部分,也就是Range里指定的,然后返回206(Partial content),否则证明客户端的部分已无效(可能已经更改),那么服务器将整个实体内容全部返回给客户端,同时返回200OK

1. 如果不满足If-None-Match,也就是任何一个Etag匹配了,那服务器就不会产生该请求的响应(412返回)。除非判断其它条件如If- Modified-Since不成立(也就是since的时间后内容没有更改),那server根据不同的请求方式发出不同的响应头,如果是GET或 HEAD请求,这种情况就要响应304 Not modified,顺便带上cache相关的头信息,特别是匹配上的Etag; 如果是其它请求方式,那就响应412Precondition Failed了

2.如果If-None-Match成立,也就是一个Etag也没匹配,那服务器会忽略任何其它诸如If-Modified-Since的条件,就不能再产生304的响应头了

 

http://blog.chinaunix.net/uid-11640640-id-3202022.html

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台

$
0
0

ELK平台介绍

在搜索ELK资料的时候,发现这篇文章比较好,于是摘抄一小段:

以下内容来自: http://baidu.blog.51cto.com/71938/1676798

日志主要包括系统日志、应用程序日志和安全日志。系统运维和开发人员可以通过日志了解服务器软硬件信息、检查配置过程中的错误及错误发生的原因。经常分析日志可以了解服务器的负荷,性能安全性,从而及时采取措施纠正错误。

通常,日志被分散的储存不同的设备上。如果你管理数十上百台服务器,你还在使用依次登录每台机器的传统方法查阅日志。这样是不是感觉很繁琐和效率低下。当务之急我们使用集中化的日志管理,例如:开源的syslog,将所有服务器上的日志收集汇总。

集中化管理日志后,日志的统计和检索又成为一件比较麻烦的事情,一般我们使用grep、awk和wc等Linux命令能实现检索和统计,但是对于要求更高的查询、排序和统计等要求和庞大的机器数量依然使用这样的方法难免有点力不从心。

开源实时日志分析ELK平台能够完美的解决我们上述的问题,ELK由ElasticSearch、Logstash和Kiabana三个开源工具组成。官方网站: https://www.elastic.co/products

  • Elasticsearch是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。

  • Logstash是一个完全开源的工具,他可以对你的日志进行收集、过滤,并将其存储供以后使用(如,搜索)。

  • Kibana 也是一个开源和免费的工具,它Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以帮助您汇总、分析和搜索重要数据日志。

----------------------------摘抄内容结束-------------------------------

画了一个ELK工作的原理图:

如图:Logstash收集AppServer产生的Log,并存放到ElasticSearch集群中,而Kibana则从ES集群中查询数据生成图表,再返回给Browser。

 

ELK平台搭建

系统环境

System: Centos release 6.7 (Final)

ElasticSearch: 2.1.0

Logstash: 2.1.1

Kibana: 4.3.0

Java: openjdk version  "1.8.0_65"

注:由于Logstash的运行依赖于Java环境, 而Logstash 1.5以上版本不低于java 1.7,因此推荐使用最新版本的Java。因为我们只需要Java的运行环境,所以可以只安装JRE,不过这里我依然使用JDK,请自行搜索安装。

 

ELK下载: https://www.elastic.co/downloads/

 

ElasticSearch

配置ElasticSearch:

1
2
tar  -zxvf elasticsearch-2.1.0.tar.gz
cd  elasticsearch-2.1.0

安装Head插件(Optional):

1
./bin/plugin  install  mobz/elasticsearch-head

然后编辑ES的配置文件:

1
vi  config/elasticsearch.yml

修改以下配置项:

1
2
3
4
5
6
7
cluster.name=es_cluster
node.name=node0
path.data=/tmp/elasticsearch/data
path.logs=/tmp/elasticsearch/logs
#当前hostname或IP,我这里是centos2
network.host=centos2
network.port=9200

其他的选项保持默认,然后启动ES:

1
./bin/elasticsearch

可以看到,它跟其他的节点的传输端口为9300,接受HTTP请求的端口为9200。

使用ctrl+C停止。当然,也可以使用后台进程的方式启动ES:

1
./bin/elasticsearch  &

然后可以打开页面localhost:9200,将会看到以下内容:

返回展示了配置的cluster_name和name,以及安装的ES的版本等信息。

刚刚安装的head插件,它是一个用浏览器跟ES集群交互的插件,可以查看集群状态、集群的doc内容、执行搜索和普通的Rest请求等。现在也可以使用它打开 localhost:9200/_plugin/head页面来查看ES集群状态:

可以看到,现在,ES集群中没有index,也没有type,因此这两条是空的。

 

Logstash

Logstash的功能如下:

其实它就是一个 收集器而已,我们需要为它指定Input和Output(当然Input和Output可以为多个)。由于我们需要把Java代码中Log4j的日志输出到ElasticSearch中,因此这里的Input就是Log4j,而Output就是ElasticSearch。

配置Logstash:

1
2
tar  -zxvf logstash-2.1.1.tar.gz
cd  logstash-2.1.1

编写配置文件(名字和位置可以随意,这里我放在config目录下,取名为log4j_to_es.conf):

1
2
mkdir  config
vi  config/log4j_to_es.conf

输入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# For detail structure of this  file
# Set: https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html
input {
  # For detail config for  log4j as input, 
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html
  log4j {
    mode => "server"
    host => "centos2"
    port => 4567
  }
}
filter {
  #Only matched data are send to output.
}
output {
  # For detail config for  elasticsearch as output, 
  # See: https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
  elasticsearch {
    action => "index"             #The operation on ES
    hosts  => "centos2:9200"      #ElasticSearch host, can be array.
    index  => "ec"                #The index to write data to, can be any string.
  }
}

logstash命令只有2个参数:

因此使用agent来启动它(使用-f指定配置文件):

1
./bin/logstash  agent -f config/log4j_to_es.conf

到这里,我们已经可以使用Logstash来收集日志并保存到ES中了,下面来看看项目代码。

 

Java项目

照例先看项目结构图:

pom.xml,很简单,只用到了Log4j库:

1
2
3
4
5
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

 

log4j.properties,将Log4j的日志输出到 SocketAppender,因为官网是这么说的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
log4j.rootLogger=INFO,console
 
for  package  com.demo.elk, log would be sent to socket appender.
log4j.logger.com.demo.elk=DEBUG, socket
 
# appender socket
log4j.appender.socket=org.apache.log4j.net.SocketAppender
log4j.appender.socket.Port=4567
log4j.appender.socket.RemoteHost=centos2
log4j.appender.socket.layout=org.apache.log4j.PatternLayout
log4j.appender.socket.layout.ConversionPattern=%d [%-5p] [%l] %m%n
log4j.appender.socket.ReconnectionDelay=10000
 
# appender console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d [%-5p] [%l] %m%n

注意: 这里的端口号需要跟Logstash监听的端口号一致,这里是4567。

 

Application.java,使用Log4j的LOGGER打印日志即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
package  com.demo.elk;
 
import  org.apache.log4j.Logger;
 
public  class  Application {
    private  static  final  Logger LOGGER = Logger.getLogger(Application.class);
    public  static  void  main(String[] args) throws  Exception {
        for  (int  i = 0; i < 10; i++) {
            LOGGER.error("Info log ["  + i + "].");
            Thread.sleep(500);
        }
    }
}

 

用Head插件查看ES状态和内容

运行Application.java,先看看console的输出(当然,这个输出只是为了做验证,不输出到console也可以的):

再来看看ES的head页面:

切换到Browser标签:

单击某一个文档(doc),则会展示该文档的所有信息:

可以看到,除了基础的message字段是我们的日志内容,Logstash还为我们增加了许多字段。而在 https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html中也明确说明了这一点:

上面使用了ES的Head插件观察了ES集群的状态和数据,但这只是个简单的用于跟ES交互的页面而已,并不能生成报表或者图表什么的,接下来使用Kibana来执行搜索并生成图表。

 

Kibana

配置Kibana:

1
2
3
tar  -zxvf kibana-4.3.0-linux-x86.tar.gz
cd  kibana-4.3.0-linux-x86
vi  config/kibana.yml

修改以下几项(由于是单机版的,因此host的值也可以使用localhost来代替,这里仅仅作为演示):

1
2
3
4
server.port: 5601
server.host: “centos2”
elasticsearch.url: http://centos2:9200
kibana.index: “.kibana”

启动kibana:

1
./bin/kibana

用浏览器打开该地址:

为了后续使用Kibana,需要配置至少一个Index名字或者Pattern,它用于在分析时确定ES中的Index。这里我输入之前配置的 Index名字applog,Kibana会自动加载该Index下doc的field,并自动选择合适的field用于图标中的时间字段:

点击Create后,可以看到左侧增加了配置的Index名字:

接下来切换到Discover标签上,注意右上角是查询的时间范围,如果没有查找到数据,那么你就可能需要调整这个时间范围了,这里我选择Today:

接下来就能看到ES中的数据了:

执行搜索看看呢:

点击右边的保存按钮,保存该查询为search_all_logs。接下来去Visualize页面,点击新建一个柱状图(Vertical Bar Chart),然后选择刚刚保存的查询search_all_logs,之后,Kibana将生成类似于下图的柱状图(只有10条日志,而且是在同一时间 段的,比较丑,但足可以说明问题了:)  ):

你可以在左边设置图形的各项参数,点击Apply Changes按钮,右边的图形将被更新。同理,其他类型的图形都可以实时更新。

点击右边的保存,保存此图,命名为search_all_logs_visual。接下来切换到Dashboard页面:

单击新建按钮,选择刚刚保存的search_all_logs_visual图形,面板上将展示该图:

如果有较多数据,我们可以根据业务需求和关注点在Dashboard页面添加多个图表:柱形图,折线图,地图,饼图等等。当然,我们可以设置更新频率,让图表自动更新:

如果设置的时间间隔够短,就很趋近于实时分析了。

到这里,ELK平台部署和基本的测试已完成。

 

参考:

http://baidu.blog.51cto.com/71938/1676798

http://blog.csdn.net/cnweike/article/details/33736429

http://my.oschina.net/itblog/blog/547250

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



应用商店最新排名:应用宝连续三月领跑 手机厂商崛起

$
0
0

应用商店作为公认的移动互联网的三大入口之一,一直是互联网巨头的必争之地。以腾讯、360、百度为首的互联网巨头和手机厂商成为应用商店市场争夺最为激烈的两大战场。回顾2015年应用商店市场,众多渠道排名座次出现较大变动,有巨头在衰落,也有新贵在崛起。

近日艾瑞咨询、Questmobile都发布了最新的安卓应用商店数据。在2015年年末最后几个月,应用商店格局突变,并且风云孕育:首先是应用宝实现了持续反超,站稳行业第一,与360手机助手、百度手机助手的差距逐渐增大。而昔日老牌应用商店豌豆荚、91助手等风光不再,在遭到巨头挤压的同时,被小米、华为等手机厂商应用商店逐渐赶超,生存环境日益艰难。

一、艾瑞:应用宝用户覆盖率连续三月第一

艾瑞咨询近日公布的2015年11月安卓应用商店用户覆盖率数据显示,应用宝以32.81%用户覆盖率位列行业第一,实现连续三月领跑;360手机助手、百度手机助手分别以29.45%、19.81%分列二、三名。整体行业格局被以腾讯、360、百度为首的第三方应用商店占据着主流阵营。

应用商店最新排名:应用宝连续三月领跑 手机厂商崛起

图1:艾瑞11月安卓应用商店用户覆盖率排名

同时,回顾艾瑞mUserTracker9月、10月安卓应用商店数据可以发现,自2015年9月起,应用宝就以32.27%月用户覆盖率居第一。10月,应用宝以32.71%保持领先,并持续增长。老牌巨头360手机助手用户覆盖率由9月开始从31.6%下降至29.45%。百度手机助手用户覆盖率10月上升20.14%后,11月再小幅下滑至19.81%。

应用商店最新排名:应用宝连续三月领跑 手机厂商崛起

图2:艾瑞9-11月安卓应用商店前三甲用户覆盖率排名

二、QuestMobile:12月应用宝月活跃用户数和新装用户数均第一

除月度覆盖人数比例外,月活跃用户数、活跃渗透率同样是衡量应用商店排名的重要标准。

来自移动互联网数据研究机构QuestMobile同期发布的12月安卓应用商店数据显示,应用宝在12月以1.56亿月活跃用户数、25.47%活跃渗透率位居行业第一,同样连续3月保持领先,360手机助手、百度手机助手依旧分列二、三名。

应用商店最新排名:应用宝连续三月领跑 手机厂商崛起

图3:Questmobile12月安卓应用商店排名

此外,Questmobile还公布了12月新安装用户数、新安装渗透率,其中应用宝同样位居行业第一。

作为应用商店厂商,新安装用户数已成为合作APP厂商的关注重点,该数据直接关系到APP新用户转化效果及质量。应用宝极强的新用户拓展能力,进一步奠定其在国内应用商店市场领先地位。

三、业内分析:应用分发创新决定行业领先地位

业内分析,在应用分发模式创新的探索中,更加贴近用户和开发者体验是应用宝稳固领先优势的重要原因。今年10月,应用宝推出了“应用+”战略,并通过新版实现“应用+”战略的第一步——体验式分发,即让用户在下载APP前就可以在应用商店提前体验APP内的服务。体验式分发以APP“试衣间”的方式,改善用户发现应用并做出决策的流程,最终提升APP的分发效率。根据此前公布的数据显示,在“体验式分发”测试之初,应用宝就帮助“图片合成器”APP提升下载转化率239%,“QQ阅读”下载转化率提升286%,分发效果显著。

而近期在微信朋友圈、公众号中APP也能一键下载,整个用户体验比以往流程精简80%。而这一体验来自应用宝推出的“微下载”功能。用户只要点击微信中朋友圈、公众号的分享链接,两步操作即可下载,通过激活微信营销下载能力,让超6亿微信用户真正成为APP的使用者和推广者,引领APP分发进入微信朋友圈分发时代。有媒体报道称,酷划锁屏在接入后整体下载转化率提升80%,日激活用户达1万。业内人士分析,“微下载”的推出或助力应用宝进一步扩大领先优势。

除此之外,百度手机助手、豌豆荚等也在过去一年推出了新分发模式。豌豆荚通过“应用预览”功能,让用户在安装之前就能方便的预览应用内最近更新的内容,在充分了解 App 内容风格的前提下挑选应用,这一功能与应用宝的“体验式分发”颇为相似。

面向未来,业界指出,分发模式的不断创新将决定应用商店的行业地位。纵观目前行业前三甲,腾讯擅长社交、360主打安全、百度拥有搜索优势,未来这三家互联网巨头只有不断完善并充分利用自身的核心优势,才能在竞争激烈的应用分发市场树立起坚固的壁垒。

 

北京大学:中国顶端1%的家庭占有全国三分之一的财产

$
0
0

20120602094235670

中国目前的收入和财产不平等状况正在日趋严重。顶端1%的家庭占有全国约三分之一的财产,底端25%的家庭拥有的财产总量仅在1%左右。此外,从教育机会到医疗保障,中国社会的不平等现象整体呈现扩大趋势。日前公布的《中国民生发展报告2015》在深入调研的基础上作出了上述判断。

《中国民生发展报告》丛书是基于北京大学中国家庭追踪调查(China Family Panel Studies, CFPS)撰写的系列专题报告,以全国25个省市160个区县的14960个家庭为基线样本,探讨民生问题状况、差异、原因和社会机制。

《中国民生发展报告2015》显示,中国目前的收入和财产不平等状况正在日趋严重。近30年来,中国居民收入基尼系数从80年代初的0.3左右上升到现在的0.45以上。而据CFPS2012资料估算,2012年,全国居民收入基尼系数约为0.49,大大超出0.4的警戒线。财产不平等的程度更加严重。估算结果显示,中国家庭财产基尼系数从1995年的0.45扩大到2012年的0.73。顶端1%的家庭占有全国约三分之一的财产,底端25%的家庭拥有的财产总量仅在1%左右。

除了收入和财产上的不平等之外,不同人群在教育机会、健康保障等方面的差异也非常明显。

以教育为例,“只要努力就一定能考上大学”,这样励志的话语正在越来失去说服力。教育这项重要的公共服务存在巨大的城乡差距、东中西区域差距和性别差距。尤其是城乡差距十分显著。《中国民生发展报告2015》显示,60年代出生的人群教育不平等程度最低,此后不平等程度不断上升,80年代出生的人群教育不平等程度达到历史最高。户口、父母的教育水平、党员身份、出生所在省份等一系列并非通过个体努力可以改变的因素对教育资源获得的影响份额在过去三十年有所上升。这表明未来相关公共政策应该着力于减少劣势境况对人力资本发展的负面影响,使社会成员获得平等的教育机会。

在医疗保障上,本应起到减小收入差距作用的社保体系反而起到逆向调节的作用。《中国民生发展报告2015》主要负责人、北京大学教授李建新的研究表明,健康状况更差的个体往往更加缺乏医疗保障资源,面临更大的就医压力。从收入上看,高收入人群享有更多的医疗补贴,医疗补贴不成比例的补贴给了富裕人群而不是穷人。

在性别方面,女性往往受教育水平更低,工作和收入更差,相应健康水平也比男性更差。女性更容易有抑郁倾向,自报慢性病的比例更高。但是,在决定个体就医机会的医疗保障方面,女性拥有医疗保险的比例却低于男性,在看病时自己负担的医疗费用比例更高。

城乡居民也存在巨大的健康和医疗不平等。农村居民的抑郁水平更高,其慢性病类型主要为高血压、呼吸系统疾病和胃肠炎,而后两者主要由落后的生活条件和医疗卫生服务导致。农村居民的新农合医保虽然覆盖率高于城市,但是保障力度明显低于城市,因而,农村居民的自付比例仍然高于城市。

李建新等人在《报告》中阐述,上述不均等现象无论从社会结构、社会阶层视角,还是跨城乡、跨地区的视角去度量,都显现出扩大的趋势。这些问题亟需得到有效解决,否则很有可能威胁到社会的稳定,进而成为未来社会发展的瓶颈。

除此之外,《中国民生发展报告2015》还考察婚姻和家庭在转型社会的极速变迁,包括夫妻间财产分配、子代对年长父母的社会支持、流动人口对家庭的支持和担当等问题。

您可能也喜欢的文章:

北京大学:中国1%的家庭占有全国1/3以上财产

吾家2015:中国人家庭调查大报告 80、90生娃意愿强烈

前程无忧:调查显示59.5%的家庭由女性掌管家庭财产

北京大学:调查显示中国家庭收入两极分化严重

北京大学:2012年中国民生发展报告 家庭支出同比增5710元
无觅

优化系列 | 实例解析MySQL性能瓶颈排查定位

$
0
0

导读

从一个现场说起,全程解析如何定位性能瓶颈。

排查过程

收到线上某业务后端的MySQL实例负载比较高的告警信息,于是登入服务器检查确认。

1. 首先我们进行OS层面的检查确认

登入服务器后,我们的目的是首先要确认当前到底是哪些进程引起的负载高,以及这些进程卡在什么地方,瓶颈是什么。

通常来说, 服务器上最容易成为瓶颈的是磁盘I/O子系统,因为它的读写速度通常是最慢的。即便是现在的PCIe SSD,其随机I/O读写速度也是不如内存来得快。当然了,引起磁盘I/O慢得原因也有多种,需要确认哪种引起的。

第一步,我们一般先看整体负载如何,负载高的话,肯定所有的进程跑起来都慢。
可以执行指令 w或者 sar -q 1来查看负载数据,例如:

[yejr@imysql.com:~ ]# w
 11:52:58 up 702 days, 56 min,  1 user,  load average: 7.20, 6.70, 6.47
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    1.xx.xx.xx        11:51    0.00s  0.03s  0.00s w

或者 sar -q的观察结果:

[yejr@imysql.com:~ ]# sar -q 1
Linux 2.6.32-431.el6.x86_64 (yejr.imysql.com)     01/13/2016     _x86_64_    (24 CPU)
02:51:18 PM   runq-sz  plist-sz   ldavg-1   ldavg-5  ldavg-15   blocked
02:51:19 PM         4      2305      6.41      6.98      7.12         3
02:51:20 PM         2      2301      6.41      6.98      7.12         4
02:51:21 PM         0      2300      6.41      6.98      7.12         5
02:51:22 PM         6      2301      6.41      6.98      7.12         8
02:51:23 PM         2      2290      6.41      6.98      7.12         8

load average大意表示当前CPU中有多少任务在排队等待,等待越多说明负载越高,跑数据库的服务器上,一般load值超过5的话,已经算是比较高的了。

引起load高的原因也可能有多种:

  1. 某些进程/服务消耗更多CPU资源(服务响应更多请求或存在某些应用瓶颈);
  2. 发生比较严重的swap(可用物理内存不足);
  3. 发生比较严重的中断(因为SSD或网络的原因发生中断);
  4. 磁盘I/O比较慢(会导致CPU一直等待磁盘I/O请求);

这时我们可以执行下面的命令来判断到底瓶颈在哪个子系统:

[yejr@imysql.com:~ ]# top
top - 11:53:04 up 702 days, 56 min,  1 user,  load average: 7.18, 6.70, 6.47
Tasks: 576 total,   1 running, 575 sleeping,   0 stopped,   0 zombie
Cpu(s):  7.7%us,  3.4%sy,  0.0%ni, 77.6%id, 11.0%wa,  0.0%hi,  0.3%si,  0.0%st
Mem:  49374024k total, 32018844k used, 17355180k free,   115416k buffers
Swap: 16777208k total,   117612k used, 16659596k free,  5689020k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
14165 mysql     20   0 8822m 3.1g 4672 S 162.3  6.6  89839:59 mysqld
40610 mysql     20   0 25.6g  14g 8336 S 121.7 31.5 282809:08 mysqld
49023 mysql     20   0 16.9g 5.1g 4772 S  4.6 10.8   34940:09 mysqld

很明显是前面两个mysqld进程导致整体负载较高。
而且,从 Cpu(s) 这行的统计结果也能看的出来, %us%wa的值较高,表示 当前比较大的瓶颈可能是在用户进程消耗的CPU以及磁盘I/O等待上
我们先分析下磁盘I/O的情况。

执行 sar -d确认磁盘I/O是否真的较大:

[yejr@imysql.com:~ ]# sar -d 1
Linux 2.6.32-431.el6.x86_64 (yejr.imysql.com)     01/13/2016     _x86_64_    (24 CPU)
11:54:32 AM    dev8-0   5338.00 162784.00   1394.00     30.76      5.24      0.98      0.19    100.00
11:54:33 AM    dev8-0   5134.00 148032.00  32365.00     35.14      6.93      1.34      0.19    100.10
11:54:34 AM    dev8-0   5233.00 161376.00    996.00     31.03      9.77      1.88      0.19    100.00
11:54:35 AM    dev8-0   4566.00 139232.00   1166.00     30.75      5.37      1.18      0.22    100.00
11:54:36 AM    dev8-0   4665.00 145920.00    630.00     31.41      5.94      1.27      0.21    100.00
11:54:37 AM    dev8-0   4994.00 156544.00    546.00     31.46      7.07      1.42      0.20    100.00

再利用 iotop确认到底哪些进程消耗的磁盘I/O资源最多:

[yejr@imysql.com:~ ]# iotop
Total DISK READ: 60.38 M/s | Total DISK WRITE: 640.34 K/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
16397 be/4 mysql       8.92 M/s    0.00 B/s  0.00 % 94.77 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
 7295 be/4 mysql      10.98 M/s    0.00 B/s  0.00 % 93.59 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
14295 be/4 mysql      10.50 M/s    0.00 B/s  0.00 % 93.57 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
14288 be/4 mysql      14.30 M/s    0.00 B/s  0.00 % 91.86 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320
14292 be/4 mysql      14.37 M/s    0.00 B/s  0.00 % 91.23 % mysqld --basedir=/usr/local/m~og_3320/mysql.sock --port=3320

可以看到,端口号是3320的实例消耗的磁盘I/O资源比较多,那就看看这个实例里都有什么查询在跑吧。

2. MySQL层面检查确认

首先看下当前都有哪些查询在运行:

[yejr@imysql.com(db)]> mysqladmin pr|grep -v Sleep
+----+----+----------+----+-------+-----+--------------+-----------------------------------------------------------------------------------------------+
| Id |User| Host     | db |Command|Time | State        | Info                                                                                          |
+----+----+----------+----+-------+-----+--------------+-----------------------------------------------------------------------------------------------+
| 25 | x | 10.x:8519 | db | Query | 68  | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>404612 order by Fvideoid) t1 |
| 26 | x | 10.x:8520 | db | Query | 65  | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>484915 order by Fvideoid) t1 |
| 28 | x | 10.x:8522 | db | Query | 130 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>404641 order by Fvideoid) t1 |
| 27 | x | 10.x:8521 | db | Query | 167 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>324157 order by Fvideoid) t1 |
| 36 | x | 10.x:8727 | db | Query | 174 | Sending data | select max(Fvideoid) from (select Fvideoid from t where Fvideoid>324346 order by Fvideoid) t1 |
+----+----+----------+----+-------+-----+--------------+-----------------------------------------------------------------------------------------------+

可以看到有不少慢查询还未完成,从slow query log中也能发现,这类SQL发生的频率很高。
这是一个非常低效的SQL写法,导致需要对整个主键进行扫描,但实际上只需要取得一个最大值而已,从slow query log中可看到:

Rows_sent: 1  Rows_examined: 5502460

每次都要扫描500多万行数据,却只为读取一个最大值,效率非常低。

经过分析,这个SQL稍做简单改造即可在个位数毫秒级内完成,原先则是需要150-180秒才能完成,提升了N次方。
改造的方法是: 对查询结果做一次倒序排序,取得第一条记录即可。而原先的做法是对结果正序排序,取最后一条记录,汗啊。。。

写在最后,小结

在这个例子中,产生瓶颈的原因比较好定位,SQL优化也不难,实际线上环境中,通常有以下几种常见的原因导致负载较高:

  1. 一次请求读写的数据量太大,导致磁盘I/O读写值较大,例如一个SQL里要读取或更新几万行数据甚至更多,这种最好是想办法减少一次读写的数据量;
  2. SQL查询中没有适当的索引可以用来完成条件过滤、排序(ORDER BY)、分组(GROUP BY)、数据聚合(MIN/MAX/COUNT/AVG等),添加索引或者进行SQL改写吧;
  3. 瞬间突发有大量请求,这种一般只要能扛过峰值就好,保险起见还是要适当提高服务器的配置,万一峰值抗不过去就可能发生雪崩效应;
  4. 因为某些定时任务引起的负载升高,比如做数据统计分析和备份,这种对CPU、内存、磁盘I/O消耗都很大,最好放在独立的slave服务器上执行;
  5. 服务器自身的节能策略发现负载较低时会让CPU降频,当发现负载升高时再自动升频,但通常不是那么及时,结果导致CPU性能不足,抗不过突发的请求;
  6. 使用raid卡的时候,通常配备BBU(cache模块的备用电池),早期一般采用锂电池技术,需要定期充放电(DELL服务器90天一次,IBM是30天),我们可以通过监控在下一次充放电的时间前在业务低谷时提前对其进行放电,不过新一代服务器大多采用电容式电池,也就不存在这个问题了。
  7. 文件系统采用ext4甚至ext3,而不是xfs,在高I/O压力时,很可能导致%util已经跑到100%了,但iops却无法再提升,换成xfs一般可获得大幅提升;
  8. 内核的io scheduler策略采用cfq而非deadline或noop,可以在线直接调整,也可获得大幅提升。

 

关于MySQL的方方面面大家想了解什么,可以直接留言回复,我会从中选择一些热门话题进行分享。 同时希望大家多多 转发,多一些阅读量是老叶继续努力分享的绝佳助力,谢谢大家 :)

最后打个广告,运维圈人士专属铁观音茶叶微店上线了,访问: http://yejinrong.com获得专属优惠

缓存系列文章–无底洞问题

$
0
0

作者:

一、背景 

 1. 什么是缓存无底洞问题:

Facebook的工作人员反应2010年已达到3000个memcached节点,储存数千G的缓存。他们发现一个问题–memcached的连接效率下降了,于是添加memcached节点,添加完之后,并没有好转。称为“无底洞”现象

2. 缓存无底洞产生的原因:

键值数据库或者缓存系统,由于通常采用hash函数将key映射到对应的实例,造成key的分布与业务无关,但是由于数据量、访问量的需求,需要使用分布式后(无论是客户端一致性哈性、redis-cluster、codis),批量操作比如批量获取多个key(例如redis的mget操作),通常需要从不同实例获取key值,相比于单机批量操作只涉及到一次网络操作,分布式批量操作会涉及到多次网络io。

 

 

3. 无底洞问题带来的危害:

(1) 客户端一次批量操作会涉及多次网络操作,也就意味着批量操作会随着实例的增多,耗时会不断增大。

(2) 服务端网络连接次数变多,对实例的性能也有一定影响。
4. 结论:

用一句通俗的话总结:更多的机器不代表更多的性能,所谓“无底洞”就是说投入越多不一定产出越多。

分布式又是不可以避免的,因为我们的网站访问量和数据量越来越大,一个实例根本坑不住,所以如何高效的在分布式缓存和存储批量获取数据是一个难点。

 

二、哈希存储与顺序存储

在分布式存储产品中,哈希存储与顺序存储是两种重要的数据存储和分布方式,这两种方式不同也直接决定了批量获取数据的不同,所以这里需要对这两种数据的分布式方式进行简要说明:

1. hash分布:

hash分布应用于大部分key-value系统中,例如memcache, redis-cluster, twemproxy,即使像mysql在分库分表时候,也经常会用user%100这样的方式。

hash分布的主要作用是将key均匀的分布到各个机器,所以它的一个特点就是数据分散度较高,实现方式通常是hash(key)得到的整数再和分布式节点的某台机器做映射,以redis-cluster为例子:

问题:和业务没什么关系,不支持范围查询。

2. 顺序分布

 

 3. 两种分布方式的比较:

分布方式特点典型产品
哈希分布1. 数据分散度高2.键值分布与业务无关3.无法顺序访问

4.支持批量操作

一致性哈希memcacheredisCluster其他缓存产品
顺序分布1.数据分散度易倾斜2.键值分布与业务相关3.可以顺序访问

4.支持批量操作

BigTableHbase

 

 

 

三、分布式缓存/存储四种Mget解决方案

 

1. IO的优化思路:

(1) 命令本身的效率:例如sql优化,命令优化

(2) 网络次数:减少通信次数

(3) 降低接入成本:长连/连接池,NIO等。

(4) IO访问合并:O(n)到O(1)过程:批量接口(mget),

 

2.  如果只考虑减少网络次数的话,mget会有如下模型:

 

 

3. 四种解决方案:

(1).串行mget

将Mget操作(n个key)拆分为逐次执行N次get操作, 很明显这种操作时间复杂度较高,它的操作时间=n次网络时间+n次命令时间,网络次数是n,很显然这种方案不是最优的,但是足够简单。

 

(2). 串行IO

将Mget操作(n个key),利用已知的hash函数算出key对应的节点,这样就可以得到一个这样的关系:Map<node, somekeys>,也就是每个节点对应的一些keys

它的操作时间=node次网络时间+n次命令时间,网络次数是node的个数,很明显这种方案比第一种要好很多,但是如果节点数足够多,还是有一定的性能问题。

 

 

(3). 并行IO

此方案是将方案(2)中的最后一步,改为多线程执行,网络次数虽然还是nodes.size(),但网络时间变为o(1),但是这种方案会增加编程的复杂度。

它的操作时间=1次网络时间+n次命令时间

 

(4). hash-tag实现。

第二节提到过,由于hash函数会造成key随机分配到各个节点,那么有没有一种方法能够强制一些key到指定节点到指定的节点呢?

redis提供了这样的功能,叫做hash-tag。什么意思呢?假如我们现在使用的是redis-cluster(10个redis节点组成),我们现在有1000个k-v,那么按照hash函数(crc16)规则,这1000个key会被打散到10个节点上,那么时间复杂度还是上述(1)~(3)

那么我们能不能像使用单机redis一样,一次IO将所有的key取出来呢?hash-tag提供了这样的功能,如果将上述的key改为如下,也就是用大括号括起来相同的内容,那么这些key就会到指定的一个节点上。

例如:

 

user1,user2,user3......user1000
{user}1,{user}2,{user}3.......{user}1000

 

 

 

例如下图:它的操作时间=1次网络时间+n次命令时间

 

 

3. 四种批量操作解决方案对比:

方案优点缺点网络IO
串行mget1.编程简单2.少量keys,性能满足要求大量keys请求延迟严重o(keys)
串行IO1.编程简单2.少量节点,性能满足要求大量node延迟严重o(nodes)
并行IO1.利用并行特性2.延迟取决于最慢的节点1.编程复杂2.超时定位较难o(max_slow(node))
hash tags性能最高1.tag-key业务维护成本较高2.tag分布容易出现数据倾斜o(1)

 

 

 

 

四、总结和建议

 

无底洞问题对资源和性能有一定影响,但是其实大部分系统不需要考虑这个问题,因为

1. 99%公司的数据和流量无法和facebook相比。

2. redis/memcache的分布式集群通常来讲是按照项目组做隔离的,以我们经验来看一般不会超过50对主从。

所以这里只是提供了一种优化的思路,开阔一下视野。

 

 

五、参考文献

  1. Facebook’s Memcached Multiget Hole: More machines != More Capacity  
  2. Multiget的无底洞问题
  3. 再说memcache的multiget hole(无底洞)

 

 

 

 

 

 

 

 

 

 

原创文章,转载请注明:转载自 并发编程网 – ifeve.com

本文链接地址:缓存系列文章–无底洞问题


从Ganglia故障说起

$
0
0

ganglia是现在市面上比较流行的一个集群健康状态监控系统。它能够提供一整套的图形化报表用以完整的监控集群中各个节点的CPU/内存/网络以及其他需要监控的信息。

这次呢是我们搭建的一套环境,通过ganglia监控,但看似所有的配置都正确,可ganglia的前端主机(web-front)始终无法得到应有的数据。

简单介绍下我们的环境:总共有10台主机的集群,通过eth0与外网相连(10.0.0.0/8网段),通过eth1连接内部的管理网络(192.168.0.0/24网段,DHCP)。ganglia front-end工作在管理网络上,同样通过eth1获得集群中主机的健康信息。
集群中的主机通过组播方式将数据发送给front-end。

首先,从组播开始说。ganglia的组播实现是通过向一个固定的ip:239.2.11.71 发送信息从而达到全网广播的目的。对于这个ip的解释如下:

        IP地址: 239.2.11.71
        所在区域: IANA保留地址 用于多点传送 
        该区域的IP段: 225.0.0.0 - 239.255.255.255

即所有向这个IP发送的消息都被视作向全网端所有的主机发送广播信息。这个应该很好理解。但往往很多情况下有个问题会被忽略,那就是:从哪个NIC向外广播?

这个问题的回答取决于你的路由配置:

~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.239.149.1    0.0.0.0         UG    0      0        0 eth0
10.239.149.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.0.1     0.0.0.0         255.255.255.0   U     0      0        0 eth1

很明显的是,如果我向239.2.11.71发送信息的话,系统会义无反顾的使用eth0通讯。其实本来我打算贴tracepath 239.2.11.71命令的结果,可由于这个地址由于是个组播地址,事实上是不会收到响应的。

既然问题已经找到,那解决起来也是很轻松的,跟解决其他的路由问题完全一样。

~# route add 239.2.11.71 eth1
~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.239.149.1    0.0.0.0         UG    0      0        0 eth0
10.239.149.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
172.18.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0
192.168.0.1     0.0.0.0         255.255.255.0   U     0      0        0 eth1
239.2.11.71     0.0.0.0         255.255.255.255 UH    0      0        0 eth1

对于ubuntu用户来说如果想要让这条路由每次启动后都能自动生效,那就需要在/etc/network/interface配置的末尾加上一条配置:

up route add 239.2.11.71 eth1

自此,问题解决!当然,如果你用过一段时间的ganglia,你会说对于这个情况,更简单的方法是将组播模式改成单播模式。强制指定数据的接收者就不会有这么奇怪的问题了。但这个方法对于eth1连接的DHCP网络来说,由于IP地址并不固定,还是采用组播的方式比较靠谱一点。

[译]GC专家系列3-GC调优

$
0
0

原文链接: http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collection/

本篇是”GC专家系列“的第三篇。在第一篇 理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别。所以,你应该已经了解了JDK 7中的5种GC类型,以及每种GC对性能的影响。

在第二篇 Java垃圾回收的监控中介绍了在真实场景中JVM是如何运行GC,如何监控GC数据以及有哪些工具可用来方便进行GC监控。

在本篇中,我将基于真实的案例来介绍一些GC调优的最佳选项。写本篇文章时,我假设你已经理解了前两篇的内容。为了深入理解本部分内容,你最好先浏览一下前两篇的内容——如果你尚未了解的话。

GC调优是必须的吗

更精确的说, 基于Java的服务是否一定需要GC调优?应该说,GC调优并非所有Java服务都必须做的事情。当然这是基于你已经使用了下面的选项或事实:

  • 通过 -Xms-Xmx选项指定了内存大小

  • 使用了 -server选项

  • 系统未产生太多超时日志

也就是说,如果你未设置内存大小并且你的系统产生了过多的超时日志,恭喜你需要为你的系统执行GC调优

但是,请记住: GC调优是不得已时的选择

思考一下GC调优的深层原因。垃圾回收器会去清理Java中创建的对象。GC需要清理的对象数据以及GC执行的次数取决于应用创建对象的多少。因此,为了控制GC的执行,首先你需要 减少对象的创建

俗话说“积重难返”。所以我们需要从小处着手,否则它们将不断壮大直到难以管理。

  • 应该多使用 StringBuilderStringBuffer对象替代 String

  • 减少不必要的日志输出。

即便如此,面对有些场景我们依然无能为力。我们知道解析XML和JSON会占用大量的内存空间。即便我们尽可能少的使用 String,尽可能好的优化日志输出,然而在解析XML和JSON时仍然会有大量的内存开销,甚至有10~100MB之多,可我们很难杜绝XML和JSON的使用。但是请记住:XML和JSON会带来很大的内存开销。

如果应用的内存占用不断提升,你就要开始对其进行GC调优了。我把GC调优的目标分为以下两类:

  • 降低移动到老年代的对象数量

  • 缩短Full GC的执行时间

降低移动到老年代的对象数量

在Oracle JVM中除了JDK 7及最高版本中引入的G1 GC外,其他的GC都是基于分代回收的。也就是对象会在Eden区中创建,然后不断在Survivor中来回移动。之后如果该对象依然存活,就会被移到老年代中。有些对象,因为占用空间太大以致于在Eden区中创建后就直接移动到了老年代。老年代的GC较新生代会耗时更长,因此减少移动到老年代的对象数量可以降低full GC的频率。减少对象转移到老年代可能会被误解为把对象保留在新生代,然而这是不可能的,相反你可以 调整新生代的空间大小

缩短Full GC耗时

Full GC的单次执行与Minor GC相比,耗时有较明显的增加。如果执行Full GC占用太长时间(例如超过1秒),在对外服务的连接中就可能会出现超时。

  • 如果企图通过缩小老年代空间的方式来降低Full GC执行时间,可能会面临 OutOfMemoryError或者带来更频繁的Full GC。

  • 如果通过增加老年代空间来减少Full GC执行次数,单次Full GC耗时将会增加。

因此,需要 为老年代空间设置适当的大小

影响GC性能的选项

理解Java垃圾回收的结尾,我说过不要有这样的想法: 别人通过某个GC选项获得了明显的性能提升,为什么我不直接用这个选项呢。因为 不同的服务所拥有的对象数量和对象的生命周期是不同的

一个简单场景,如果执行一个任务需要五个条件:A, B, C, D和E,另外一个任务只需要两个条件A和B,哪个任务会快一些?通常只需要条件A和B的任务会快一些。

Java GC选项的设置也是一样的道理。设置很多选项未必能提高GC执行速度,相反还可能会更加耗时。 GC调优的基本规则是对两台或更多的服务器设置不同的选项,并对比性能表现,然后把被证明能提升性能的选项添加到应用服务器上。请记住这一点。

下表列出了与内存相关的且会影响性能的GC选项:

表1: GC调优需要关注的选项

分类选项说明
堆空间-Xms启动JVM时的初始堆空间大小
-Xmx堆空间最大值
新生代空间-XX:NewRatio新生代与老年代的比例
-XX:NewSize新生代大小
-XX:SurvivorRatioEden区与Survivor区的比例

我经常会使用的选项是: -Xms, -Xmx-XX:NewRatio,其中 -Xms-Xmx是必须的。而如何设置 -XX:NewRatio对性能会有显著的影响。

可能有人会问 如何设置永久代(Perm)的大小, 可以使用 -XX:PermSize-XX:MaxPermSize进行设置,但记住只有发生由Perm空间不足导致的 OutOfMemoryError时才需要设置。

另外一个会影响GC性能的选项是 GC类型,下表列出了JDK 6.0中能使用的相关设置选项:

表2: GC类型选项

分类选项说明
Serial GC-XX:+UseSerialGC
Parallel GC-XX:+UseParallelGC
-XX:ParallelGCThreads=<value>
Parallel Compacting GC-XX:+UseParallelOldGC
CMS GC-XX:+UseConcMarkSweepGC
-XX:UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=<value>
-XX:+UseCMSInitiatingOccupancyOnly
G1-XX:+UnlockExperimentalVMOptions
-XX:+UseG1GC
在JDK6中使用G1时,这两个选项必须同时设置

除了G1,其他GC类型都是通过每个选行列的第一行选项进行设置。通常最不会使用的是Serial GC,它是为client应用优化和设计的。

还有很多其他影响GC性能的选项,但不如上面这些对性能的影响明显。另外设置更多选项未必能优化GC的执行时间。

GC调优过程

GC调优过程与一般的性能改进流程很相似,下面会介绍我在GC调优过程中的流程。

1. 监控GC状态

首先需要监控GC状态信息以明确在GC操作过程中对系统的影响。具体方式可以回顾上一篇文章: Java 垃圾回收的监控

2. 分析监控数据并决定是否需要GC调优

然后通过GC操作状态,对监控结果进行分析,并判断是否有必要进行GC调优。如果分析结果显示GC耗时在0.1-0.3秒以内的话,一般不需要花费额外的时间做GC调优。然而, 如果GC耗时达到1-3秒甚至10秒以上,就需要立即对系统进行GC调优

但是如果你的应用分配了10GB的内存,且不能降低内存容量的话,其实是没办法进行GC调优的。这种情况下,你首先要去思考为什么需要分配这么大的内存。如果只给应用分配了1GB或者2GB内存,当有 OutOfMemeoryError发生时,你需要通过堆dump来分析验证内存溢出的原因并进行修复。

注释:
堆dump是把内存情况按一定格式输出到文件,可用于检查Java 内存中的对象和数据情况。可使用JDK中内置的 jmap命令创建堆dump文件。创建文件过程中,Java进程会中断,因此不要在正常运行时系统上做此操作。

3. 设置GC类型和内存大小

如果决定做GC调优,就需要考虑如何选择GC类型、如何设置内存大小。如果你有多台服务器,可通过为每台服务器设置不同的GC选项并对比不同的表现,这一步很重要。

4. 分析GC调优结果

设置GC选项后,至少要收集24小时的GC表现数据,然后就可以着手分析这些数据了。如果足够幸运,通过分析就刚好找到了最合适的GC选项。否则就需要分析GC日志,并分析内存的分配情况。然后通过不同的调整GC类型和内存大小来找到系统的最优选项。

5. 如果结果可接受,则对所有服务应用调优选项并停止调优

如果GC结果令人满意,就可以把相应的选项应用到所有服务器并停止GC调优。

下面的章节会详细介绍每个步骤中的详细过程。

监控GC状态并分析GC结果

监控Web应用(WAS: Web Application Server)GC运行状态的最好方式是使用 jstat命令。在 Java 垃圾回收的监控部分已经介绍了如何使用jstat命令,所以这里就直接介绍怎么样来校验结果数据。

下面的例子中列出了JVM未做GC调优时的数据:

$ jstat -gcutil 21719 1s
S0    S1    E    O    P    YGC    YGCT    FGC    FGCT GCT
48.66 0.00 48.10 49.70 77.45 3428 172.623 3 59.050 231.673
48.66 0.00 48.10 49.70 77.45 3428 172.623 3 59.050 231.673

看一下表中的YGC和YGCT,YGCT 除以 YGC算出平均单次YGC耗时为0.05秒。也就是说在新生代执行一次垃圾回收的平均耗时为50毫秒。通过这份结果,我们可以无须关注新生代的垃圾回收。

然后再看一下FGCT和FGC,FGCT除以FGC算出平均单次FGC耗时为19.68秒。也就是平均需要消耗19.68秒来执行一次Full GC。上面的结果(共3次Full GC)可能是每次Full GC都耗时19.68秒,也有可能是其中两次都只耗时1秒,而另外一次却消耗了58秒。然而不管哪种情况,都迫切需要进行GC调优。

当然也可以通过 jstat来校验结果,不过分析GC的最好方式是使用 -verbosegc选项来启动JVM。在前面的文章中我已经详细介绍了生成日志的方式以及如何进行分析。就分析 -verbosegc日志而言, HPJMeter是我最偏爱的工具,因为它简单易用。使用HPJMeter可以轻松获取GC执行时间的开销以及GC发生的频率。

如果GC执行时间满足以下判断条件,那么GC调优并没那么必须。

  • Minor GC执行迅速(50毫秒以内)

  • Minor GC执行不频繁(间隔10秒左右一次)

  • Full GC执行迅速(1秒以内)

  • Full GC执行不频繁(间隔10分钟左右一次)

括号内的值并非绝对,依据应用的服务状态会有不同。有些服务可能要求Full GC处理速度不能超过0.9秒,另外一些服务可能会宽松些。因此校验GC结果并根据具体的服务需要,决定是否要进行GC调优。

在校验GC状态时,不要只关心Minor GC和Full GC的耗时,也要 GC执行次数也同样重要。如果新生代太小,Minor GC就会频繁执行(甚至每间隔1秒就要执行一次)。另外,新生代太小导致转移到老年代的对象增多,也会引起Full GC的频繁执行。因此使用`-gccapacity`配合jstat命令,以检查内存空间的使用情况。

设置GC类型和内存大小

设置GC类型

Oracle JVM提供了5种GC类型,如果是低于JDK 7的版本,可以使用Parallel GC, Parallel Compacting GC, CMS GC。当然,到底选哪一个并没有统一的准则或标准。

所以 如何选择合适的GC类型?推荐方案是将这三种GC都应用到应用中进行对比。不过可以明确的是CMS GC肯定比Parallel GCs更快,即然这样只使用CMS GC便好。然而CMS GC也有出问题的时候,通常Full GC中使用CMS GC会执行更快,如果CMS GC的并发模式失败,则会出现比Parallel GCs慢的情况。

并发模式失败

我们来深入看一下并发模式失败的场景。

Parallel GC与CMS GC最大的区别在于压缩任务。压缩任务通过压缩内存使用来移除内存中的碎片空间,以清理两块已分配使用的内存空间中的间隙。

在Parallel GC中,只要执行Full GC便会进行内存压缩,因此耗时更长。不过Full GC之后,因为压缩的原故,可以分配连续的空间,所以内存的分配速度为更快一些。

与之相反,CMS GC的执行中并不会伴随内存压缩,因此GC速度会更快一些。然而,因此未做内存压缩, GC清理过程中释放的内存便会成为空闲空间。因为空间不连续,可能会导致在创建大对象时空间不足。例如,如果老年代尚有300M空闲,却不能为10MB的对象分配足够的连续空间。这时便会发生 并发模式失败的警告,并触发内存压缩。如果使用CMS GC,在内存压缩过程中可能会比Parallel GCs更为耗时,也可能会带来其他问题。关于"并发模式失败"更详细的介绍可以看Oracle 工程师的文章: 理解CMS GC 日志

结论就是,要为你的系统寻找合适的GC类型。

每个系统都有一个最适当的GC类型,所以你需要找到这个GC类型。如果你有6台服务器,建议你为每两组设置相同的选项,并通过 -verbosegc选项对结果进行分析和比较。

调整内存大小

下面先列出内存大小与GC执行次数、每次GC耗时之间的关系:

  • 大内存

    • 会降低GC执行次数

    • 相应的会增加GC执行耗时

  • 小内存

    • 会缩知单次GC耗时

    • 相应的会增加GC执行次数

当然,关于使用大内存还是小内存并没有唯一正确的答案。如果服务器资源足够且Full GC执行耗时能控制在1秒以内,使用10GB的内存也是可以的。但大多数时候如果设置内存为10GB,GC执行效果并不尽人意,执行一次Full GC可能要消耗10~30秒(具体时长也会根据对象大小情况而不同)。

既然如此, 如何正确设置内存大小。通常情况下,我会推荐500MB大小。这不是说你要把自己的WAS(Web Application Server)内存选项设置为 -Xms500-Xmx500m。基于当前未调优时的场景,检查Full GC之后内存大小变化。如果Full GC之后尚有300MB空间剩余,这样最好把内存设置到1GB(300MB(默认使用) + 500MB(老年代最小容量) + 200MB(空闲空间))。这意味着你应该才老年代至少设置500MB空间。如果你有3台服务器,可以分别设置1GB、1.5GB和2GB,并检查每台机器的执行结果。

理论上,根据内存大小不同单次执行GC速度应该是1GB > 1.5GB > 2GB,所以1GB的内存会中三个之中GC速度最快的。但并不能保证1GB的内存Full GC耗时1秒,2GB的内存Full GC耗时2秒。实际耗时与机器性能和对象大小也有关系。所以最好的度量方式是设置每种可能性并分析他们的监控结果。

有设置内存大小时,还需要设置另外一选项: NewRatioNewRatio是新生代与老年代的比值的倒数(即老年代与新生代的比值)。如果 XX:NewRatio=1,就是说新生代 : 老年代的比值为1:1。对于1GB内存,就是新生代与老年代各500MB。如果 NewRatio的值是2,则是新生代 : 老年代的值为1:2。因此比值设置的越大,老年代的空间就越大,相应的新生代空间会越小。

设置 NewRatio也不是一件重要的事,但可能会对整个GC性能带来严重影响。如果新生代太小,对象就会转移到老年代,引起频繁的Full GC,导致更多的耗时。

你可能简单的认为设置 NewRatio=1会带来最佳的效果,然而并非如此。把 NewRatio设置为2或3更容易带来好的GC表现。当然我也实际遇到过一些这样的例子。

完成GC调优的最快途径是什么?通过对比性能测试的结果是得到GC调优结果的最快途径。通过为每个服务器设置不同的选项并观察GC状态,最好能观察1到2天的数据。如果是通过性能测试来做GC调优的话,要为每个服务器准备相同的负载和业务操作。请求比例的分配也要与业务条件相一致。然而即便是专业的性能测试人员,准备精确的负载数据也并非易事,通常需要花费很大精力来做准备。所以更简捷的GC调优方式就是对业务应用准备GC选项,然后通过等待GC结果并进行分析,尽管可能需要更长的等待时间。

分析GC调优结果

在应用GC选项并设置 -verbosegc后,可以通过 tail命令检查日志是否按期望的方式正常输出。如果选项未精确的设置或者没有按期望输出,你所花费的时间都将白费。如果日志输出与期望相符,等待1到2天的运行后便可检查和分析结果。最简单的方式是把日志文件复制到本地PC,并使用 HPJMeter进行分析。

分析过程中主要关注以下数据,下面列表是按我自己定义的优先级列出的。其中决定GC选项的最重要的数据是Full GC执行时间。

  • Full GC(平均)耗时

  • Minor GC(平均)耗时

  • Full GC执行间隔

  • MinorGC执行间隔

  • Full GC整体耗时

  • Minor GC整体耗时

  • GC整体耗时

  • Full GC执行次数

  • Minor GC执行次数

如果足够幸运,你能恰好找到合适的GC选项,通常你并没这么幸运。执行GC调优时一定要格外小心,因为如果你试图一次就完成GC调优,得到的可能会是 OutOfMemoryError

调优案例

上面我们对于GC调优的讨论还仅是纸上谈兵,现在开始我们看一些具体的GC调优的案例。

案例1

这个例子是为服务S进行的GC优化。对于这个新上线的服务S,在执行Full GC时有些过于耗时。

先看一下 jstat -gcutil的结果:

S0 S1 E O P YGC YGCT FGC FGCT GCT
12.16 0.00 5.18 63.78 20.32 54 2.047 5 6.946 8.993

在开始进行调优时不用太关心 持久代空间的设置,相对而言YGC的数值更值得关注。

从上面的结果中我们可算出执行Minor GC和Full GC的平均时间上的开销,如下表:

表3:服务S执行Minor GC和Full GC的平均耗时

GC类型GC 执行次数GC执行时间平均耗时
Minor GC542.04737 ms
Full GC56.9461389 ms

对于Minor GC来说, 37 ms还不算坏,而Full GC的平均耗时 1.389 s对于系统来说在执行Full GC时可能会导致频繁的超时现象,例如DB超时设置为1 s的话就会发生超时。所以这个案例中的系统需要进行GC调优。

首先在开始GC调优之前先检查当前的内存设置。可以使用 jstat -gccapacity选项查看内存的使用情况。下面是服务S的检查结果:

NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC PGCMN PGCMX PGC PC YGC FGC
212992.0 212992.0 212992.0 21248.0 21248.0 170496.0 1884160.0 1884160.0 1884160.0 1884160.0 262144.0 262144.0 262144.0 262144.0 54 5

其中关键的数据如下:

  • 新生代使用:212, 992 KB(约208 MB)

  • 老年代使用:1,884,160 KB(约1.8 GB)

所以除去持久代之外的内存分配为2 GB,且新生代 : 老年代为 1:9 (即 NewRatio=9)。为了看到更详细的信息,对系统的三个不同实现均设置了 -verbosegc并分别设置了 NewRatio选项,除此之外未添加其他选项。

  • NewRatio = 2

  • NewRatio = 3

  • NewRatio = 4

一天之后检查GC时日志时幸运的发生,在设置 NewRatio之后尚未有Full GC发生。

发生了什么?因为大多数对象在创建之后不久就被销毁,所以新生代里的对象在移到老年代之前就被销毁掉了。

既然如此,就没必要再设置其他选项,只是选择好最佳的 NewRatio即可。 如何选取最佳NewRatio?只能逐个分析设置不同 NewRatio值时的Minor GC的平均耗时。

上面三个 NewRatio设置对应的Minor GC平均耗时如下:

  • NewRatio=2: 45ms

  • NewRatio=3: 34ms

  • NewRatio=4: 30ms

因为 NewRatio=4时Minor GC具有最小的耗时,所以就是我们选择的最佳设置,即便此时新生代的空间相对较小。应用此选项后,服务再也没有Full GC发生。

下面是系统重新设置过选项后,某天通过 jstat -gcutil查看到的结果:

S0 S1 E O P YGC YGCT FGC FGCT GCT
8.61 0.00 30.67 24.62 22.38 2424 30.219 0 0.000 30.219

你可能认为因为系统接收的请求太少以致于GC发生频率较低,然而在Minor GC执行了2,424次的情况下系统未发生Full GC。

案例2

下面介绍的是服务A的例子。我们在公司的应用性能管理平台(APM: Application Performance Manager)上发现服务A的JVM周期性的出现长时间的停顿(超过8秒未有响应)的现象。所以我们决定对其进行GC调优。经过排查我们发现此系统在执行Full GC时太过耗时,需要进行优化。

在着手优化之前,我们为系统加上了 -verbosegc选项,输出结果如下图:

GC调优之前的GC耗时
图1:GC调优之前的GC耗时

上图是HPJMeter自动分析结果后提供的系统GC随着JVM运行的耗时图。 X-轴是JVM从启动后的运行时间轴, Y-轴是每次GC的响应时间。其中绿色的是Full GC使用的CMS垃圾回收的耗时,蓝色的是Minor GC使用的Parallel Scavenge垃圾回收的耗时。

前面我说过CMS GC是最快的,但上图可看到有场景耗时竟达到15秒之多。 什么原因导致这种后果?回想一下我前面说过的:当内存压缩时CMS将会变慢。另外服务A设置了 -Xms1g-Xmx4g的选项,操作系统为其分配的内存为4 GB。

然后我把GC类型由GMS换成了Parallel GC,并把内存大小设置为2G, NewRatio设置为3。一段时间之后通过 jstat -gcutil查看到的结果如下:

S0 S1 E O P YGC YGCT FGC FGCT GCT
0.00 30.48 3.31 26.54 37.01 226 11.131 4 11.758 22.890

Full GC的速度提升了,与4GB内存时的15秒相比,现在平均每次只需要3秒。但3秒仍然不尽人意,所以我设计了以下六组选项:

  • -XX:+UseParallelGC -Xms1536m -Xmx1536m -XX:NewRatio=2

  • -XX:+UseParallelGC -Xms1536m -Xmx1536m -XX:NewRatio=3

  • -XX:+UseParallelGC -Xms1g -Xmx1g -XX:NewRatio=3

  • -XX:+UseParallelOldGC -Xms1536m -Xmx1536m -XX:NewRatio=2

  • -XX:+UseParallelOldGC -Xms1536m -Xmx1536m -XX:NewRatio=3

  • -XX:+UseParallelOldGC -Xms1g -Xmx1g -XX:NewRatio=3

哪一个会更快呢?结果显示内存越小,速度越快。下图是第六组选项的GC持续时长分布图,代表了最优的GC性能提升。图中看到最慢的为1.7秒,而平均值降低到1秒以内。

使用第六组选项后的GC耗时
图2:使用第六组选项后的GC耗时

因此我把服务A的GC选项调整为了第六组中的设置,然而每天夜里却连续发生了 OutOfMemoryError。个中艰辛不再细说,简而言之就是批量的数据处理任务导致了JVM内存泄露。到此为止,所有的问题都明了了。

如果只对GC日志做短时间的观察例把GC调优的结果应用到所有服务器上是一件非常危险的事情。一定要记住,如果GC调优能够顺利执行而无故障只有一条途径:像分析GC日志一样分析系统的每一个服务操作。

上面通过两个GC调优的案例演示了GC调优的具体处理过程。如我所述,案例中的GC选项可以不做调整的应用到那些具有相同CPU、操作系统和 JDK 版本以及执行相同功能的服务上去。然而不要把这些选项应用到你的系统上,因为他们未必适用。

总结

我执行GC调优一般基于经验而无需通过堆dump后对内存进行详细的分析,尽管精确的内存状态可能会带来更好的GC调优结果。在一般情景,如果内存负载较低时,通过分析内存对象可能效果更好,不过如果服务负载较高,内存空间使用较多时,更推荐基于经验来做GC调优。

我曾经在一些服务上对G1 GC做过性能测试,不过还没有全面使用。结果证明G1 GC执行速度比其他任何GC都要快,不过需要把JDK升级到 JDK 7 才能享受到G1带来的性能提升,另外G1的稳定性目前尚不能完全保证,没有人知道是否会带来严重的bug。所以大范围使用 G1 还尚待时日。

当 JDK 7 稳定以后(并不是说它当前不稳定),并且WAS针对JDK 7做过优化之后,G1也许会稳定的运行在服务器上,到那时也许就不再需要进行GC调优了。

更多GC调优的细节可以在 Slideshare上搜索相关材料。我最推荐的是Twitter 工程师 Attila Szegedi写的这篇 我在Twitter学到的关于JVM调优的一切,有时间可以学习一下。

作者:Sangmin Lee, 性能实验室高级工程师,NHN公司

从MKV中提取音频

$
0
0

如今,MKV已成为网上的电影、电视剧最常见的格式之一。从这些视频文件中提取出音频文件,我们可以很轻松地对其进行剪辑,分离出句子,制作成听写材料,来提升我们的听力。

网上视频格式除了MKV,还有avi、rm(包括rmvb)以及MP4,这些格式当然也有办法提取出音频,但并非本文的重点。MKV文件处理起来是最为方便的,我们只需要下载两个软件就行。

第一个叫mkvtoolnix,这是一套功能强大的MKV格式制作和处理的工具,支持将多种视频、音频、字幕等格式封装成MKV格式。

第二个叫gMKVExtractGUI,它是在mkvtoolnix上开发的,其实它只是给mkvtoolnix中的一个组件加了个图形界面。

若只论音频提取,用mkvtoolnix也能完成,不过舍得认为,gMKVExtractGUI用起来更为简单。

先安装好mkvtoolnix,然后运行gMKVExtractGUI(下载得到的是一个压缩包,你得先解压),我们会看到如下的界面:

2016-01-11_12-10-52

 

注意右上角的三个Browse按钮,通常我们只要点击第一个Browse按钮,选择MKV文件的位置就行。

第二个Browse按钮是指定输出文件夹……让它和输入文件夹一致就行,没必要动它。

至于第三个Browse按钮,只要你安装了mkvtoolnix,它会自动检索到。

当你选好MKV文件后,下方的信息窗口会显示出该文件所包含的轨道信息,来看一下:

  • Track1:注意后面的video标签,表示这是视频轨道;
  • Track2-3:注意后面的audio标签,这就是我们要找的音频轨道,并不是所有的MKV都有两个音频轨;
  • Track4-7:注意后面的subtitles标签,这是字幕轨道。没错,你也可以用gMKVExtractGUI来提取字幕,非常的方便;

下面的操作非常之简单,你只要选中想要导出的音频轨道(如图),然后点击Extract按钮,gMKVExtractGUI就会在输出目录下生成音频文件。

注意啊,生成的音频文件通常不会是我们常见的MP3,常见的是AC3和DTS格式,这些格式可以在多数播放器中播放,如果要转换成mp3格式,则需要另外的工具来帮忙。舍得推荐大家使用棒子开发的JetAudio来转换。

JetAudio是一款播放器,它内置了一个强大的音频转换功能,支持各种音频格式之间的转换,它的下载地址和具体的使用方法,请大家自己找度娘帮忙吧!

 

下载页面:

mkvtoolnix: https://mkvtoolnix.download/windows/releases/

gMKVExtractGUI: http://sourceforge.net/projects/gmkvextractgui/

 

本文版权归 舍得学苑所有,欢迎转载,转载请注明作者和出处。谢谢!
作者: 舍得
首发: 舍得新浪博客


 

Async Http Client 欺骗漏洞 (CVE-2013-7397)

$
0
0

发布日期:2015-06-25
更新日期:2015-06-25

受影响系统:

AsyncHttpClient AsyncHttpClient < 1.9.0

描述:


CVE(CAN) ID: CVE-2013-7397

Async Http Client是异步HTTP及WebSocket客户端Java库。

Async Http Client 1.9.0之前版本,会跳过了X.509证书验证,除非keyStore位置及trustStore位置均显式设置。中间人攻击者在使用典型AHC配置中显示任意证书,即可欺骗HTTP服务器。

<*来源:losar
  *>

建议:


厂商补丁:

AsyncHttpClient
---------------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

https://github.com/AsyncHttpClient/async-http-client

https://github.com/AsyncHttpClient/async-http-client/issues/352

https://github.com/AsyncHttpClient/async-http-client/issues/197

AsyncHttpClient 开源框架學習研究

$
0
0

转载请注明出处: http://blog.csdn.net/krislight 

OverView:

AsyncHttpClient庫 基於Apache的HttpClient框架,是一個異步的httpClient, 所有的http請求都在子線程中,但是callback執行的線程和創建這個callback的線程是同一個(也即主線程創建的callback那麼執行的時候也是在主線程中)

基本用法:  

AsyncHttpClient client = new AsyncHttpClient();
	client.get("http://www.google.com", new AsyncHttpResponseHandler() {
	          @Override
			public void onStart() {
				super.onStart();
                    //in MainThread, you can do some ui operation here like progressBar.  
			}
			@Override
			public void onFinish() {
                    // no matter success or failed this method is always invoke
				super.onFinish();
			}
			@Override
			public void onSuccess(String content) {
                   //success
			}
			@Override
			public void onFailure(Throwable error, String content) {
                  //failed
			}	
});

項目中建議定義成靜態工具類:                   

public class TwitterRestClient {
		  private static final String BASE_URL = "http://api.twitter.com/1/";
		  private static AsyncHttpClient client = new AsyncHttpClient();
		  public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
		      client.get(getAbsoluteUrl(url), params, responseHandler);
		  }
		  public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
		      client.post(getAbsoluteUrl(url), params, responseHandler);
		  }
		  private static String getAbsoluteUrl(String relativeUrl) {
		      return BASE_URL + relativeUrl;
		  }
		}

使用的时候:           

class TwitterRestClientUsage {
	    public void getPublicTimeline() throws JSONException {
	        TwitterRestClient.get("statuses/public_timeline.json", null, new JsonHttpResponseHandler() {
	            @Override
	            public void onSuccess(JSONArray timeline) {
	                // Pull out the first event on the public timeline
	                JSONObject firstEvent = timeline.get(0);
	                String tweetText = firstEvent.getString("text");

	                // Do something with the response
	                System.out.println(tweetText);
	            }
	        });
	    }
	}

保存Server端發送的Cookie:                     

AsyncHttpClient myClient = new AsyncHttpClient();
	PersistentCookieStore myCookieStore = new PersistentCookieStore(this);
	myClient.setCookieStore(myCookieStore);


如果想加入自己的Cookie:

 
 	BasicClientCookie newCookie = new BasicClientCookie("cookiesare", "awesome");
	newCookie.setVersion(1);
	newCookie.setDomain("mydomain.com");
	newCookie.setPath("/");
	myCookieStore.addCookie(newCookie);

帶參數的Http請求:

可以這樣構造參數:

RequestParams params = new RequestParams();
	params.put("key", "value");
	params.put("more", "data");

也可以構造單個參數:

 RequestParams params = new RequestParams("single", "value");

 還可以根據Map構造:

	HashMap<String, String> paramMap = new HashMap<String, String>();
	paramMap.put("key", "value");
	RequestParams params = new RequestParams(paramMap);

使用參數上傳文件:

1.傳入InputStream:

 
 InputStream myInputStream = blah;
RequestParams params = new RequestParams();
params.put("secret_passwords", myInputStream, "passwords.txt");

2.傳入File:

File myFile = new File("/path/to/file.png");
	RequestParams params = new RequestParams();
	try {
	    params.put("profile_picture", myFile);
	} catch(FileNotFoundException e) {}

3.傳入Byte數組:

	byte[] myByteArray = blah;
	RequestParams params = new RequestParams();
	params.put("soundtrack", new ByteArrayInputStream(myByteArray), "she-wolf.mp3");

下載二進制形式的數據(如圖片,文件等)使用BinaryHttpResponseHandler:

 AsyncHttpClient client = new AsyncHttpClient();
String[] allowedContentTypes = new String[] { "image/png", "image/jpeg" };
client.get("http://example.com/file.png", new BinaryHttpResponseHandler(allowedContentTypes) {
	    @Override
	    public void onSuccess(byte[] fileData) {
	        // Do something with the file
	    }
	});

基本的http授權驗證:

AsyncHttpClient client = new AsyncHttpClient();
	client.setBasicAuth("username","password", new AuthScope("example.com", 80, AuthScope.ANY_REALM));
	client.get("http://example.com");

使用https安全連接:

AsyncHttpClient client = new AsyncHttpClient();
	SSLSocketFactory sf = createSSLSocketFactory();
		 if(sf != null){
			client.setSSLSocketFactory(sf);
		 }
		HttpProtocolParams.setUseExpectContinue(client.getHttpClient().getParams(), false);
		return client;


转载请注明出处:  http://blog.csdn.net/krislight

createSSLSocketFactory方法如下:

public static SSLSocketFactory createSSLSocketFactory(){
		MySSLSocketFactory sf = null;
		try {
			KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
			trustStore.load(null, null);
			sf = new MySSLSocketFactory(trustStore);
			sf.setHostnameVerifier(MySSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return sf;
	}

其中MySSLSocketFactory定義

public class MySSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
    	injectHostname(socket, host);
        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
    
    private void injectHostname(Socket socket, String host) {
        try {
            Field field = InetAddress.class.getDeclaredField("hostName");
            field.setAccessible(true);
            field.set(socket.getInetAddress(), host);
        } catch (Exception ignored) {
        }
    }
}


             
作者:u011176244 发表于2014-2-23 15:04:37 原文链接
阅读:83 评论:0 查看评论

WebSocket实现多屏互动的分析及方案

$
0
0

多屏互动事实上是一个比较宽泛的概念,通俗来讲就是用户在不同的终端上通过有线、无线的连接方式进行通信,可进行多媒体(音频,视频,图片)内容的传输,解析,展示,控制等一系列操作。而随着WebSocket协议的诞生,不同端之间的网页互连也变得流行起来,这种基于WebSocket协议实现多屏互动在运营活动上的使用也使得运营页面的形式也变得更加多样和有趣。

本文不会去探讨WebSocket协议的详情,想了解的可以点击 https://tools.ietf.org/html/rfc6455查看协议文档。

在了解Websocket技术的基础上,本文通过动手实践一个多屏互动的小游戏来介绍整个流程的分析和探讨在哪些环节进行运营扩展。

目前业界对于该技术运用已经有很多成熟的案例,这些案例呈现的效果无一不是狂拽酷炫。先看看下面的一个案例。

http://stage.moneplus.cn/ice/

 

上面的案例是动壹科技开发的“多屏互动之冰川时代”互动小游戏,该活动在数据通信上采用了WebSocket。手机扫描跟PC端网页连接以后,监听手机的陀螺仪并将该动作拟物化反馈到PC网页上,主要是用手机来模拟水杯的倾倒动作,然后冰块从页面顶部掉落,整个操作非常流畅并且效果也很赞。

另外,互娱的同学使用WebSocket也开发了一个比较赞的活动运营页:营救孙悟空。

http://zt.qq.com/act/hdz/index.htm

用户通过扫描二维码跟PC网页连接,通过监听用户在手机上的“点击”、“滑动”等交互事件,来渲染PC网页上的内容,让用户大呼过瘾。

类似使用多屏互动方式来做运营的还有很多,就不一一列举,那我们将这些运营活动进行总结,发现他们都是共通的,使用端对端双工通信技术并基于这个基础去玩一些运营花样,吸引用户以达到品牌宣传、活动推广的目的。

既然多屏互动给我们的运营带来如此多的惊喜,下面就详细看看如何来实现多屏互动并且较快地应用到实践中。

场景抽象

拟定一个的游戏闭环场景:首先有若干玩家,然后有为玩家们划定的特殊区域(暂且称之为房间),玩家们在房间里面按照特定的游戏规则进行游戏。如下图所示,N个玩家通过长连接的技术接入到房间中,游戏过程中房间会即时公示游戏进度及相关信息,游戏过程中、结束后会由房间向每一位玩家广播消息反馈游戏相关数据。

通过对上述场景的认知,具象到端(PC端、手机端)上的话就得提供2种类型的多个端。一种类型的端用来落地“房间”,这种类型的“端”需要承载黑板(设计模式的一种)的角色,在该类型的端上要呈现公告类信息,比如“房间”二维码、玩家状态、游戏结果、游戏规则等,通常是PC、TV等大屏幕且展示性较好的设备。另一种类型的端用来落地”玩家“,它们主要是接受”玩家“的交互信息,将这些交互行为映射成游戏数据发送给”房间”,然后在端上呈现提供给“玩家”的一些信息如操作提示、结果提示等,通常是手机、智能watch等设备。

数据结构确定

针对上面的场景闭环需要设计对应的数据结构来进行抽象,分别为用户(User)类、房间(Room)类。

1、玩家的属性抽象如下:

 

对应user.js的代码

function User(param){
	//用户名
	this.Name = param.Name || '';
	//用户连接的状态
	/*
		0 : 用户未连接
		1 : 用户已连接
	*/
	this.Status = param.Status || 0;
	//用户昵称
	this.Nick = param.Nick || '匿名';
}
exports.create = function(param){
	//返回一个用户的示例
	return new User(param);
};

2、房间的属性抽象如下:

 

room.js文件内容

function Room(param){
	//房间相关的参数
	var defaults = {
		//房间最大人数
		count : 2
	};

	//将传递过来的参数进行合并
	for(var p in param){
		if(param.p){
			defaults.p = param.p;
		}
	}

	//房间的id
	this.RoomID = param.RoomID || '';
	//房间的成员列表
	this.Users = [];
	//房间最大成员数
	this.Max = defaults.count;
}
Room.prototype = {
	addUser : function(user){
		var _this = this;
		if(_this.Users.length >= _this.Max){
			//房间已经满员,直接返回
			return 0;
		}else{
			//添加用户,返回当前用户数目
			_this.Users.push(user);
			return _this.Users.length;
		}
	},
	removeUser : function(user){
		var _this = this;
		var _users = _this.Users;
		var _count = _users.length;
		for(var i = 0;i < _count;i++){
			if(_users[i].Name === user.Name){
				_users.splice(i,1);
				return;
			}
		}
	}
};
exports.createRoom = function(param){
	return new Room(param);
};

数据结构设计完成以后,需要考虑系统的构建了,下面给一个简单的系统时序图

 

这其中会涉及到几个node模块的使用

1、网站的搭建使用node express,模板直接使用html即可,因为不涉及到复杂的数据展示,如有需要可酌情选择不同的引擎,如ejs、jade等;

2、qrcode-npm模块用以生成相应的二维码;

3、node-uuid模块生成房间、用户唯一标识串;

4、socket.io模块来处理长连接。

下面来详细说明一下基于socket的websocket协议通信与本项目结合的部分,即在整个闭环中涉及到的事件交互及处理。

 

具体代码见附件。

通过我们对场景的分析及架构的分析,整个技术实现的基础门槛不是太高,但是整个给运营活动带来的趣味性和用户的参与感是大大增强。

如下图所示:

 

通信黑盒里面的技术细节我们已经跑通,那么我们就可以和设计师们一起对“用户页面”、“面板页面”进行运营的思考,而这些对于我们设计师来说也是可以大展拳脚的舞台。

  • “用户页面”上可以去思考如何使用手机的硬件接口(陀螺仪、麦克风、触屏等)使人机交互更加符合整个场景的特点,提升界面操作性、趣味性,力图使用户更容易玩、更想玩、更想传播;
  • “面板页面”上可以适当做一些运行环境限制,专注于产品品牌地突出、广告、活动推广等。

最后,献上本人在尝试整个技术过程做的一个小游戏,游戏本身用于教学示例,基本上能够覆盖整个场景的闭环,但在细节上还待继续打磨,有需要的同学可以直接在该源码的基础之上进行相关业务、动效、交互等的扩展。

demo网址: http://115.159.36.96:8000/

 

参考网址:

https://tools.ietf.org/html/rfc6455

http://expressjs.com/

http://socket.io/docs/

https://github.com/broofa/node-uuid

https://github.com/soldair/node-qrcode

http://baike.baidu.com/view/7058959.htm

连锁百货企业数据分析系统建设方案

$
0
0

连锁百货企业数据分析系统建设方案

数据系统建设方案

 

FineReport数据系统的总体流程为:整合和获取数据,将数据应用于报表的开发,将开发完的报表进行逻辑展示处理和部署,最后呈现给使用者使用。

开发报表的过程中,必须结合企业流程和企业内部的系统数据,进行统一搭建,最终要求开发出一个结合了各个系统数据的报表决策平台。开发过程中坚持“契合需求,方便高效”的原则,为企业员工、管理者以及决策者提供一个实用、方便、高效的工具。

 

1.1方案概述

 

本章将按照建设目标,从业务展示对象和BI分析对象两部分对整个数据系统进行阐述, 包括门店业务主题、库存主题、财务主题、人事主题、客户主题等。围绕需要哪些数据、如何整合数据、从哪些维度展示和分析、需要什么交互条件等主要问题。

wKiom1aXEwaxQRVrAAVzpTKYZpk918.png 

1.2业务展示对象

业务展示类报表主要面向企业各门店的员工以及管理者,可以有效减轻企业员工及管理者在数据录入、处理上的工作量,优化并流畅各门店的运营。

1.2.1门店业务主题

门店是连锁行业的基本组成单元,其重要性不言而喻。专业、系统及标准化的门店管理是连锁企业持续赢利、发展的根基,是门店竞争力的核心禀赋。所以针对各门店的业务报表也是其它报表以及分析工具的基础。

 

1.2.1.1门店付款填报单

 

根据调研,企业各门店的收入款项不仅需要在Hairdes System中录入,而且还需要填写“XX中心XX月工作汇总表”中的多个sheet。这样导致查询历史数据非常麻烦、不利于数据的存档规整、制作成本太高,浪费有效人力资源等很多弊端。

FineReport支持多源展示,多源填报功能,一张填报单的数据可以应用于“门店业务月报”、“收入明细表”、“员工绩效考核表”等所有报表,达到“一次填报,随意取用”的效果。轻松解决以上弊端。

 

信息部门只需根据企业需要统计的付款项目,设计一个填报表单,就可以轻松解决填报烦、查询难、分析复杂等问题。

wKiom1aXEyiw1XqZAAAy8Ujaw2U798.png

 

填报项目包括:

 付款编号(自动填报)

 付款时间(自动填报)

 客户名称

 会员ID

 付款数额

 付款方式(下拉框)

 咨询主任(自动填报/下拉框)

 造型师(自动填报/下拉框)

 店长(自动填报)

 门店(自动填报)

 付款项目(下拉框)

 ……

 

填报的数据存入统一的数据库,企业根据自己关心的数据项目,利用Finereport,只需拖拽等简单操作,就能轻松制作“门店业务月报”、“收入明细表”、“员工绩效考核表”等报表。

 

1.2.1.2门店业务月(年 / 周)报

 

企业根据自己的业务需求,对各门店的业务进行统计

统计层次可包括:

   发片发套

   洗发染发

   护理用品

   客户数量

   会员数量

   ……

 

统计内容可包括:

   销售金额

   上月环比

   占比

   排名

wKioL1aXE6Oy98q6AAEFFm0WnsE651.png   ……

 

 

当业务进一步扩大,门店增多时,为方便统计查询,还可以根据具体需求设定参数

可选参数包括:

   地区

   城市

   门店

   日期

   产品类型

   ……

 

FineReport提供包括“文本控件”“下拉数控件”“下拉复选框控件”“日期控件”在内的18种参数控件,并且可以根据需求设定下拉框参数联动、复选框参数联动、动态列查询、模糊查询等多种查询方式,完全满足企业的个性化需求。

wKioL1aXE7rgxX2HAABJaa73cB8981.png

wKioL1aXFEnANCJJAABFugBt2ts037.png

报表权限:

当数据涉及权限时,可以对不同模版,模版的不同行、列设定权限参数(FR的权限可以具体到每个单元格),工作人员只能看到自己权限范围的内容。

wKiom1aXFASAXHvYAABoIxZy5SQ816.png

(江苏的门店只能看到江苏地区的销售人员)

wKioL1aXFFiTH9uSAAEhXLdfFMY184.png

 

数据钻取:

当需要查看门店的详细信息时,可设置数据钻取。

FR支持包括“多维数据钻取”,“无限层次钻取”,“不浏览模版直接导出”等多种钻取方式。

wKiom1aXFEbBil0gAANsOs2AmEg700.png(点击具体门店,可钻取该门店的收入明细表、咨询记录表、员工考勤表……)

 

1.2.1.3门店收入明细表 / 咨询记录表:

 

XX店XX月收入明细表:

  wKioL1aXFI2gsFJ7AAClK9tMS0g702.png

 

XX店XX月咨询记录表:

wKiom1aXFIORAlHnAACRrQ3jcbs108.png

1.2.2 库存主题

在任何企业的运营管理中,库存管理永远是一个重要的主题。

库存过高将占用企业运转资金增加企业负担并有报废贬值风险。
库存过低无法满足订单的灵活性,订单交货周期将加长,降低企业竞争力。
所有企业都希望库存是零或接近零。

因此企业必须对库存进行实时的监控和管理。对于库存的展示及分析,必须是整体而且细致的,需要同时掌握库存静态数据、动态变化和价值结构。

 

 

1.2.2.1发片库存表

 

wKioL1aXFPuCblQOAACaFh_442s815.png 

1.2.2.2辅助产品库存表

 

wKioL1aXFQax3_qZAADHBxAhXPY617.png 

 

1.2.3财务主题

 

在企业内部的管理及业务营运过程中,除了最基本的进、销、存三个基元,财务主题更是最直接反应企业的营运状况。随着企业的不断发展,其传统的 Excel 制作财务报表方式已经 进入瓶颈,表现在如下几点:

1) Excel 直接操作数据的方式受人为因素影响过大

财务数据反映的是企业最基本的财务运营状态,一个小的数据出错往往对企业照成不可估量的损失。

2) 耗费大量人力财力和时间

由于 Excel 操作方式零散、复杂的特点,使得往往简单的计算要耗费掉财务人员无数的时间和精力。

3) 重复工作量大 

企业的发展要求财务人员每个周期内需要出来不同指标的数据,随着企业的不断发展, 该周期不断被缩小,造成财务人员每天在耗费大量的精力去做重复的工作。

 

FineReport 采用系统计算的方式,将财务报表的各项指标通过逻辑算法纳入系统中,减少财务人员的重复工作量,避免出现人工的数据错误,从最大程度上,减少财务人员的负担,增加企业财务数据处理效率。

财务主题包含企业营运的各个方面,渗透在本文档所写的所有主题中,因此本节仅描述一些财务方面特有的几个模板例子,展示一些常用的财务报表。

 

1) 增值税明细账

将增值税的各项指标展示在web报表页面,并通过设定好的算法由系统计算出增值税明细。

wKiom1aXFRDgLNZbAAEAQO6hvcM992.png 

1) 总分类账

通过控件参数的形式,从数据库中调出某月份的总分类账,减少财务人员的重复工作量,所见即所得。

wKioL1aXFVGQPgdtAACYqrTipGg858.png 

3) 明细分类账

在总分类账的基础上,细化分类账每日内容,以 web形式展现出来,提高使用效率。

wKiom1aXFUvw-PtNAACUKzGZ8R8854.png

 

4) 科目余额报表

以月份和门店或销售点为基准,输出每月科目余额汇总,并由系统自动展示上月情况,方便数据对比。

wKioL1aXFbfA5IV4AABzFhfof_4668.png 

5) 付款凭证

以付款凭证号为条件,由系统直接调出数据库中所存数据,并按照标准格式输出,方便财务人员随时调用,并可一键输出  Excel,word,PDF 等办公格式。

wKioL1aXFcnD86iHAACdpPd3WY4802.png 

 

6) 记帐凭证

通过输入门店或销售点号、月份和凭证总号,调出记账凭证,减轻财务人员不断的 操作大量数据的工作负担。

wKiom1aXFajxLB0bAACAfkIyNCI637.png 

 

 

1.2.4人事主题

随着企业人员的不断扩大,如何合理搭建完善的人事制度、调整人力资源结构、规划企业员工职业发展等问题对企业的长远发展将产生巨大的影响。

利用FineReport强大功能,可以轻松制作多项目、交互的人事报表。

 

 

1.2.4.1员工基本信息表

 

FineReport操作界面:

wKiom1aXFc-R0TXyAABnvwrlvE4470.png 

 

wKiom1aXFfKDjFf2AAEGeITzpIk404.pngWeb浏览器展示界面:

 

 

1.2.4.2人事变更月报

 

人事变动月报涵盖维度包括:

 招聘相关—招聘职位

 招聘相关—招聘人数

 招聘相关—应聘人数

 招聘相关—报道人数

 招聘相关—起讫时间

 人员流动相关—流动类型

 人员流动相关—试用期

 人员流动相关—时间范围

 人员流动相关—合计人数

出勤考察状况可供选择的条件为:月份

 

展示效果如下:

wKioL1aXFk2BjWAsAAGFJvZb2B4625.png 

1.2.4.3员工考勤表

 

基本员工考勤表:

wKiom1aXFiySBQKTAACUpeULV8M987.png 

 

 

1.2.4.4员工薪资表

 

“员工薪资表”可以直接抽取数据库数据,通过公式自动计算,免除了多次填报计算的麻烦。

 

wKiom1aXFm7DJ98QAACMSLpiSoY178.png

wKioL1aXFveinBxgAABPag5Bc38153.png 

1.2.4.5店总绩效考核表

企业可以根据自己的店总或高管考核标准,使用FineReport,轻松制作KPI考核表。

 

分店总经理KPI考核表:

wKioL1aXFtnDCUqgAAPdUq1TeBc929.png 

参考维度:

 财务层面

 客户层面

 内部运营层面

 学习成长层面

 ……

 

 

1.3 BI分析对象

 

FineReport 不仅是一款高效的数据展示工具,而且是一款高端的数据分析工具。FineReport 数据系统通过集成企业门户平台、规范企业信息资源,为企业提供了良好的信息获取渠道,帮助企业从不同维度把握企业现状,并且通过高端的分析工具,辅助决策者合理预测企业发展。

 

决策中心——CEO桌面

 

wKiom1aXFvjBusknAAFgrasbdt8379.png

 

 

 

 

1.3.1销售分析

 

销售分析结构图(仅供参考):

 

wKiom1aXF1CgMxtAAAa7M3ifYss131.png 

 

 

1.3.1.1销售总体概况

wKioL1aXF5zxWdHXAAK_n6463G0614.png 

1.3.1.2时间维度统计销售

 

wKiom1aXF5STshjXAAE4h_WZ1sk810.png

1.3.1.3地区维度统计销售

 

 

wKiom1aXF9Pj9qUeAAD5JLNk5io279.png1.3.1.4具体门店销售情况

wKiom1aXF_HR2iTkAAJhqnSRRmk595.png

 

1.3.2财务分析

财务分析结构图(仅供参考):

 

 

wKioL1aXGFvweJ-IAAZcE3eVG5g688.png 

1.3.2.1财务分析首界面

wKioL1aXGG6gXo_FAAFbE_4A7bA721.png

1.3.2.2财务分析——盈利能力分析

wKiom1aXGF6yuFfTAAgCNU4-s1A117.png

 

1.3.2.3标准收益分析

wKioL1aXGKmwYSfUAAJSay2b_qo263.png

 

1.3.3 人事分析

 

人事分析结构(仅供参考):

 

wKiom1aXGJmzVxMqAAGyCxS-9rg106.png

1.3.3.1各部门年龄分析

 

FineReport操作界面:

wKiom1aXGNHz2daVAACno6l3KJE891.png 

 

Web浏览器展示界面:

wKiom1aXGN7z57xIAADqEzBSXeY355.png 

1.3.3.2各部门员工考勤分析

 

动态折叠树分析查看各部门员工考勤:

A:

wKiom1aXGO3x1Ga6AABiNvfIi9s101.png 

 

B:

wKiom1aXGPzgCyCLAABlJjKKmzk210.png 

 

C:

wKiom1aXGRPSTFHbAACYVjfB4p8340.png

1.3.3.3各部门员工学历/工资分析

 

wKioL1aXGXTyf4ueAAVQy4Rd3Oo092.png 

 

1.3.3.4优秀销售员分析

 

wKiom1aXGVOzxoZRAADIkokTVR4784.png 

 

1.3.4 客户分析

 

分析纬度:

 客户年龄结构分析

 性别分析

 会员/非会员

 消费区间分析

 消费结构分析

 ……

 

客户年龄结构分析:

wKiom1aXGZiBFaeYAABeBB1Vvzk701.png 

 

客户性别分析:

 

wKioL1aXGdfDeOMWAAA1cgi-Xhk913.png 

 

 

 

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




HTML性能优化技巧

$
0
0

如何提升Web页面的性能,很多开发人员从多个方面来下手如JavaScript、图像优化、服务器配置,文件压缩或是调整CSS。

很显然HTML 已经达到了一个瓶颈,尽管它是开发Web 界面必备的核心语言。HTML页面的负载也是越来越重。大多数页面平均需要40K的空间,像一些大型网站会包含数以千计的HTML 元素,页面Size会更大。

如何有效的降低HTML 代码的复杂度和页面元素的数量,本文主要解决了这个问题,从多个方面介绍了如何编写简练,清晰的HTML 代码,能够使得页面加载更为迅速,且能在多种设备中运行良好。

 

在设计和开发过程中需要遵循以下原则:

  • 结构分离:使用HTML 增加结构,而不是样式内容;
  • 保持整洁:为工作流添加代码验证工具;使用工具或样式向导维护代码结构和格式
  • 学习新语言:获取元素结构和语义标记。
  • 确保可访问: 使用ARIA 属性和Fallback 属性等
  • 测试: 使网站在多种设备中能够良好运行,可使用emulators和性能工具。

Sample HTML document with guidelines

HTML,CSS 和JavaScript三者的关系

HTML 是用于调整页面结构和内容的标记语言。HTML 不能用于修饰样式内容,也不能在头标签中输入文本内容,使代码变得冗长和复杂,相反使用CSS 来修饰布局元素和外观比较合适。HTML元素默认的外观是由浏览器默认的样式表定义的,如在Chrome中h1标签元素会渲染成32px的Times 粗体。

三条通用设计规则:

  1. 使用HTML 来构造页面结构,CSS修饰页面呈现,JavaScript实现页面功能。CSS ZenGarden 很好地展示了行为分离。
  2. 如果能用CSS或JavaScript实现就少用HTML代码。
  3. 将CSS和JavaScript文件与HTML 分开存放。这可有助于缓存和调试。

 

文档结构方面也可以做优化,如下:

  • 使用HTML5 文档类型,以下是空文件:
<!DOCTYPE html><html><head><title>Recipes: pesto</title></head><body><h1>Pesto</h1><p>Pesto is good!</p></body></html>

 

  • 在文档起始位置引用CSS文件,如下:
<head><title>My pesto recipe</title><link rel="stylesheet" href="/css/global.css"><link rel="stylesheet" href="css/local.css"></head>

 

使用这两种方法,浏览器会在解析HTML代码之前将CSS信息准备好。因此有助于提升页面加载性能。

在页面底部body结束标签之前输入JavaScript代码,这样有助于提升页面加载的速度,因为浏览器在解析JavaScript代码之前将页面加载完成,使用JavaScript会对页面元素产生积极的影响。

<body>

  ...

  <script src="/js/global.js"><script src="js/local.js"></body>

使用Defer和async属性,脚本元素具有async 属性无法保证会按顺序执行。

可在JavaScript代码中添加Handlers。千万别加到HTML内联代码中,比如下面的代码则容易导致错误且不易于维护:

index.html:

<head>
  ...<script src="js/local.js"></head><body onload="init()">

  ...

  <button onclick="handleFoo()">Foo</button>

  ...

</body>

 

下面的写法比较好:

index.html:

<head>

  ...

</head><body>

  ...

  <button id="foo">Foo</button>

  ...

  <script src="js/local.js"></body>

js/local.js:

init();
var fooButton =
    document.querySelector('#foo');
fooButton.onclick = handleFoo();

验证

优化网页的一种方法就是浏览器可处理非法的HTML 代码。合法的HTML代码很容易调试,且占内存少,耗费资源少,易于解析和渲染运行起来更快。非法的HTML代码让实现响应式设计变得异常艰难。

当使用模板时,合法的HTML代码显得异常重要,经常会发生模板单独运行良好,当与其他模块集成时就报各种各样的错误,因此一定要保证HTML代码的质量,可采取以下措施:

  • 在工作流中添加验证功能:使用验证插件如HTMLHint或SublineLinter帮助你检测代码错误。
  • 使用HTML5文档类型
  • 确保HTML的层次结构易于维护,要避免元素嵌套处于左开状态。
  • 保证添加各元素的结束标签。
  • 删除不必要的代码 ;没有必要为自关闭的元素添加结束标签;Boolean 属性不需要赋值,如果存在则为True;
<video src="foo.webm" autoplay controls>

代码格式

格式一致性使得HTML代码易于阅读,理解,优化,调试。

语义标记

语义指意义相关的事物,HTML 可从页面内容中看出语义:元素和属性的命名一定程度上表达了内容的角色和功能。HTML5 引入了新的语义元素,如<header>,<footer>及<nav>。

选择合适的元素来编写代码可保证代码的易读性:

  • 使用<h1>(<h2>,<h3>…)表示标题,<ul>或<ol>实现列表
  • 注意使用<article> 标签之前应添加<h1>标签;
  • 选择合适的HTML5语义元素如<header>,<footer>,<nav>,<aside>;
  • 使用<p>描述Body 文本,HTML5 语义元素可以形成内容,反之不成立。
  • 使用<em>和<strong>标签替代<i>和<b>标签。
  • 使用<label>元素,输入类型,占位符及其他属性来强制验证。
  • 将文本和元素混合,并作为另一元素的子元素,会导致布局错误,

例如:

<div>Name: <input type="text" id="name"></div>
换种写法会更好:
   1:  <div>
   2:    <label for="name">Name:</label><input type="text" id="name">
   3:  </div>
 

布局

要提高HTML代码的性能,要遵循HTML 代码以实现功能和为目标,而不是样式。

  • 使用<p>元素修饰文本,而不是布局;默认<p>是自动提供边缘,而且其他样式也是浏览器默认提供的。
  • 避免使用<br>分行,可以使用block元素或CSS显示属性来代替。
  • 避免使用<hr>来添加水平线,可使用CSS的border-bottom 来代替。
  • 不到关键时刻不要使用div标签。
  • 尽量少用Tables来布局。
  • 可以多使用Flex Box
  • 使用CSS 来调整边距等。

CSS

虽然本文讲解的是如何优化HTML,下面介绍了一些使用css的基本技能:

  • 避免内联css
  • 最多使用ID类 一次
  • 当涉及多个元素时,可使用Class来实现。

以上就是本文介绍的优化HTML代码的技巧,一个高质量高性能的网站,往往取决于对细节的处理,因此我们在日常开发中,能够考虑到用户体验,后期维护等方面,则会产生更高效的开发。

http://powertoolsteam.iteye.com/blog/2270388



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



干货推荐|数据可视化的五个步骤

$
0
0

5gebuzou

数据被称作是最新的商业原材料「21世纪的石油」。商业领域、研究领域、技术发展领域使用的数据总量非常巨大,并持续增长。就Elsevier而言,每年从ScienceDirect下载的文章有7亿篇,Scopus上的机构档案有8万个、研究人员档案有 1 千 3 百万,Mendeley上的研究人员档案有 3 百万。对于用户来说,从这个数据海洋中抓到关键信息越来越难。

许多先进的可视化方式(如:网络图、3D 建模、堆叠地图)被用于特定用途,例如 3D 医疗影像、模拟城市交通、救灾监督。但无论一个可视化项目有多复杂,可视化的目的是帮助读者识别所分析的数据中的一种模式或趋势,而不是仅仅给他们提供冗长的描述,诸如:“ 2000 年 A 的利润比 B 高出 2.9 % ,尽管 2001 年 A 的利润增长了 25 % ,但 2001 年利润比 B 低 3.5 % ”。出色的可视化项目应该总结信息,并把信息组织起来,让读者的注意力集中于关键点。

对于 Elsevier’s Analytical Services 的项目而言,我们一直在寻找提升数据分析和可视化的方式。例如,在我们对于研究表现的分析中有大量关于研究合作的数据;我们为 Science Europe 提供的报告(Comparative Benchmarking of European and US Research Collaboration and Researcher Mobility) 包含跨州合作以及国际合作的数据,这些数据不适合直接用二维表和X-Y图展示。

为了探索数据背后的故事,我们使用了网络关系图来识别国家间的合作,并了解每个合作关系的影响。

本文提供一份包含五个步骤的数据可视化指南,为想用表格、图形来传播观察结果、解读分析结果的人士提供帮助。要记住,建立好的可视化项目是一个反复迭代的过程。

第1步-明确问题

开始创建一个可视化项目时,第一步是明确要回答的问题,又或者试着回答下面的问题“这个可视化项目会怎样帮助读者?”

3条数据记录

表 1–数据集中的三条记录

较差的直方图

图1-槽糕的可视化项目并不澄清事实,而是引人困惑。此图中包含太多变量

清晰的问题可以有助于避免数据可视化的一个常见毛病:把不相干的事物放在一起比较。假设我们有这样一个数据集(见表 1 ),其中包含一个机构的作者总数、出版物总数、引用总数和它们特定一年的增长率。

图1是一个糟糕的可视化案例,所有的变量都被包含在一张表格中。在同一张图中绘制出不同类型的多个变量,通常不是个好主意。

注意力分散的读者会被诱导着去比较不相干的变量。

比如,观察出所有机构的作者总数都少于出版物总数,这没有任何意义,又或者发现 Athena University、Bravo University、Delta Institution 三个研究机构的出版物总数依次增长,也没有意义。拥挤的图表难以阅读、难以处理。在有多个 Y 轴时就是如此,哪个变量对应哪个轴通常不清晰。简而言之,槽糕的可视化项目并不澄清事实而是引人困惑。

第2步-从基本的可视化着手

确定可视化项目的目标后,下一步是建立一个基本的图形。它可能是饼图、线图、流程图、散点图、表面图、地图、网络图等等,取决于手头的数据是什么样子。在明确图表该传达的核心信息时,需要明确以下几件事:

  1. 我们试图绘制什么变量?
  2. X 轴和轴代表什么?
  3. 数据点的大小有什么含义吗?
  4. 颜色有什么含义吗?
  5. 我们试图确定与时间有关趋势,还是变量之间的关系?

有些人使用不同类型的图表实现相同目标,但并不推荐这样做。不同类型的数据各自有其最适合的图表类型。

比如,线形图最适合表现与时间有关的趋势,亦或是两个变量的潜在关系。当数据集中的数据点过多时,使用散点图进行可视化会比较容易。

此外,直方图展示数据的分布。直方图的形状可能会根据不同组距改变,见图 2 。(在绘制直方图时,本质是在绘制柱状图来展示特定范围内有多少数据点。这个范围叫做组距。)

直方图

图2-当组距变化,直方图的形状也发生变化。

组距太窄会导致起伏过多,让读者只盯着树木却看不到整个森林。此外,你会发现,在完成下一个步骤以后,你可能会想要修改或更换图表类型。

第3步-确定最能提供信息指标

假设我们有另一个关于某研究机构出版物数量的数据库(见表 2 )。可视化过程中最关键的步骤是充分了解数据库以及每个变量的含义。从表格中可以看出,在 A 领域(Subject A),此机构出版了 633 篇文章,占此机构全部文章的 39% ;相同时间内全球此领域共出版了 27738 篇文章,占全球总量的 44% 。 注意,B 列中的百分比累计超过 100% ,因为有些文章被标记为属于多个领域。

在这个例子中,我们想了解此机构在各个领域发表了多少文章。出版数量是一个有用的指标,不仅如此,与下面这些指标对照会呈现出更多信息:

  • 此领域的研究成果总量( B 列)
  • 此领域的全球活跃程度

由此,我们可以确定一个相对活跃指标,1.0 代表全球平均活跃程度。高于 1.0 代表高于全球水平,低于 1.0 代表低于全球水平。用 B 列的数据除以 D 列,得到这个新的指标,见表 2 。

数据库

表2-用B列的数据除以D列,得到新的指标:相对活跃程度(E栏)。

第4步-选择正确的图表类型

现在我们可以用雷达图来比较相对活跃指数,并着重观察指数最高/最低的研究领域。例如,此机构在 G 领域的相对活跃指数最高( 1.8 ),但是,此领域的全球总量远远小于其他领域(见图 3 )。雷达图的另一个局限是,它暗示各轴之间存在关系,而在本案例中这关系并不存在(各领域并不相互关联)。

雷达图

图3-相对活跃指数雷达图

数据的规范化(如本例中的相对活跃指数)是一个很常见也很有效的数据转换方法,但需要基于帮助读者得出正确结论的目的使用。如在此例中,仅仅发现目标机构对某个小领域非常重视没太大意义。

我们可以把出版量和活跃程度在同一个图表中展示,以理解各领域的活跃程度。使用图 4 的玫瑰图,各块的面积表示文章数量,半径长短表示相对活跃指数。注意在此例中,半径轴是二次的(而图 3 中是典型线性的)。图中可以看出,B 领域十分突出,拥有最大的数量(由面积表示)和最高的相对活跃程度(由半径长度表示)。

玫瑰图

图4-玫瑰图。此图中各块面积表示文章数量,半径长短表示相对活跃指数(E列)。

第5步-将注意力引向关键信息

用肉眼衡量半径长度可能并不容易。由于在本例中,相对活跃指数的 1.0 代表此领域的全球活跃程度,我们可以通过给出 1.0 的参照值来引导读者,见图 5 。这样很容易看出哪些领域的半径超出参考线。

活跃指数的玫瑰图

图5-带有相对活跃指数参考线的玫瑰图

我们还可以使用颜色帮助读者识别出版物最多的领域。如图例所示,一块的颜色深浅由出版物数量决定。为了便于识别,我们还可以把各领域名称作为标签(见图 6 )。

颜色差异的玫瑰图

图6-玫瑰图中的颜色深浅代表出版物数量(颜色越亮,出版物越多)

结论

数据可视化的方法有很多。新的工具和图表类型不断出现,每种都试图创造出比之前更有吸引力、更有利于传播信息的图表。我们的建议是记住以下原则:可视化项目应该去总结关键信息并使之更清晰直白,而不应该令人困惑,或用大量的信息让读者的大脑超载。

 

原作者:Georgin Lau and Lei Pan

翻译:王鹏宇

via:Datartisan数据工匠

原文地址:http://www.36dsj.com/archives/39986


人人都是产品经理微信公众号:woshipm,随时随地,学产品、学运营,听讲座。

Java 内存结构与垃圾回收备忘

$
0
0

原文地址: https://dzone.com/articles/java-memory-architecture-model-garbage-collection

 

研究Java垃圾回收机制,看到一篇好文,先转载,做深入研究

 

下图展示了 Java 堆内存模型,以及运行在 Java 虚拟机中任意 Java 应用的 PermGen (内存永久保存区域),下面的比率展示了 JVM 各代类型允许的内存大小分配情况,所有的数据均适用于 Java 1.7 及以下版本。该图也被称为 Java 内存模型的“管理区(Managed Area)”。

Java 内存结构(Java 内存模型)

Java 内存结构备忘录

除此之外,还有一块堆栈区(Stack Area),可通过 -Xss 选项进行配置。该区域存储了所有线程的堆引用、本地引用、程序计数器寄存器、代码缓存以及本地变量。该区域也称为内存模型的本地区(Native Area)。

Java 内存模型(结构)的管理区

[Young Generation/Nursery] 伊甸园区(Eden Space)

所有新对象都首先在 Eden Space 创建。一旦该区达到由 JVM 设定的任意阈值,新生代垃圾回收机制(Minor GC)就会启动。它会首先清除所有的非引用对象,并将引用对象从 'eden' 与 'from' 区移至 'to' 幸存者区。垃圾回收一结束,'from' 与 'to' 的角色(名字)就会对换。

[Young Generation/Nursery] 幸存者 1 区 (From)

这是幸存者区的一部分。或者视为幸存者区中的一个角色。这儿就是之前垃圾回收中的 'to' 角色。

[Young Generation/Nursery] 幸存者 2 区 (To)

这也是幸存者区的一部分。也可以视为幸存者区中的一个角色。垃圾回收过程中的所有引用对象都会从 'from' 与 'eden' 区移至此处。

[Old Generation] 年老代区(Tenured)

根据阈值限定的不同,对象们会从 'to' 幸存者区移至年老代区。你可以使用  -XX:+PrintTenuringDistribution 检查阈值,该指令会按照年龄显示对象(占用的字节空间)。年龄是指对象在幸存者区内移动的次数。

其他重要的标记还有  -XX:InitialTenuringThreshold-XX:MaxTenuringThreshold 与  -XX:TargetSurvivorRatio ,这些标记能帮你实现最佳的年老代区与幸存者区使用方案。

通过设置  -XX:InitialTenuringThreshold 与  -XX:MaxTenuringThreshold,可以指定年龄的最初值与最大值,而幸存者区 (To) 的使用率则由  -XX:+NeverTenure 与  -XX:+AlwaysTenure 决定。前者是指永远不将对象存储到年老代区,而后者恰恰相反,总是将对象存储到年老代区。

此处进行的垃圾回收是年老代垃圾回收(Major GC)。当堆空间已满或者年老代区占满时,就会触发 Major GC。此时,通常会由一个“停止一切(Stop-the-World)”事件或线程执行垃圾回收。此外,还有另一种称为全垃圾回收(Full GC)的垃圾回收机制,会涉及诸如永久内存区域。

与整体堆内存相关的另两个重要且有趣的标记是  -XX:SurvivorRatio 与  -XX:NewRatio,前者指定伊甸园区相对幸存者区的比率,后者指定年老代区相对新生代区的比率。

[Permanent Generation] 永久代区(Permgen space)

永久代区(Permgen)用于存储以下信息:常量池 (内存池),字段与方法数据及代码。

垃圾回收算法

串行 GC(Serial GC) (-XX:UseSerialGC): 针对年轻代与年老代的垃圾回收

该算法使用简单的“标记-清扫-压缩(mark-sweep-compact)”循环清理年轻代与年老代,适合内存占用较低、CPU 使用量较少的客户端系统。

并行 GC(Parallel GC) (-XX:UseParallelGC): 针对年轻代与年老代的垃圾回收

该算法使用 N 个线程(N 的值可以通过  * -XX:ParallelGCThreads=N* 设定,N 同时代表垃圾回收占用的 CPU 内核数)。其中,年轻代垃圾回收会使用 N 个线程,而年老代只用一个线程。

并行 Old GC (-XX:UseParallelOldGC): 针对年轻代与年老代的垃圾回收

该算法对年轻代与年老代均使用 N 个线程,其他方面与并行 GC 完全一致。

并发 Mark and Sweep GC (-XX:ConcMarkSweepGC): 针对年老代的垃圾回收

顾名思义,CMS GC 会最小化垃圾回收所需的停顿时间。该算法最适于创建高响应度的应用,且只作用于年老代。它会创建多条垃圾回收的线程,与应用线程同时工作。垃圾回收的线程数量可以使用  -XX:ParallelCMSThreads=n 标记指定。

G1 GC (-XX:UseG1GC): 针对年轻代与年老代的垃圾回收 (将堆内存等分为大小相同的区块)

这是一种并行、并发、不断压缩的低停顿垃圾回收器。G1 是在 Java 7 中引入以取代 CMS GC 的,它会先将堆内存分为多个大小相等的区块,继而执行垃圾回收。通常,从活动数据最少的区块开始,因此以垃圾为先。

最常见的内存溢出问题

所有 Java 程序员都应该知道的最常见的内存溢出问题:

  • Exception in thread "main": java.lang.OutOfMemoryError: Java heap space( Java 堆内存)。这并不一定意味着内存泄露,也可能是分配的堆内存空间太小。此外,在运行时间较长的应用中,也可能是因为一个无意识的引用被指向堆对象(内存泄 露)。即便是应用本身调用的 APIs,也可能保存着指向无依据对象的引用。而且,在大量使用终结器的应用中,对象们有时可能正排在终结队列中。当这样的应用创建高优先级的线程时,会 导致越来越多的对象排在终结队列中,最终导致内存溢出。

  • Exception in thread "main": java.lang.OutOfMemoryError: PermGen space(永久存储空间)。如果加载了很多类与方法,或者创建了很多字符串常量,特别是使用 intern() 方法进行创建(从 JDK 7 开始,interned 字符串就不再存储在 PermGen 中),这类错误就会出现。当出现这类错误时,打印的堆栈跟踪附近可能会出现如下文本:ClassLoader.defineClass。

  • Exception in thread "main": java.lang.OutOfMemoryError: Requested array size exceeds VM limit (请求的数组大小超出 VM 限制)。当请求的数组大小超过可用的堆空间时,这类报错就会出现。这类错误通常归咎于编程错误,在运行时请求了极大的数组大小。
  • Exception in thread "main": java.lang.OutOfMemoryError:  request <s> bytes for <r>, 交换空间溢出?这是内存泄露最常见的根源。通常,当操作系统没有足够的交换空间,或另一个进程占用了系统中的所有可用内存,就会导致内存泄露。简而言之, 由于空间用尽,堆内存无法提供所请求的空间大小。该信息中的 's' 代表失败的请求所需的内存大小(以字节为单位),而 'r' 代表内存请求的原因。在大多数情况下,此处的 'r' 是报告分配失败的源模块,有时也会是具体的原因。

  • Exception in thread "main": java.lang.OutOfMemoryError: (Native method)(<原因><堆栈跟踪><本地方法>)。该报错意味着一个本地方法遇到内存分配失败。问题的根源在于 Java Native Interface(Java 本地接口) 中存在的错误,而非 JVM 中运行的代码错误。若是本地代码不检查内存分配错误,应由会直接崩溃,而不会出现内存溢出。

内存泄露的定义

你可以将内存泄露看做一种疾病,而内存溢出错误为一种征兆。但不是所有的内存溢出错误都意味着内存泄露,不是所有的内存泄露都以内存溢出为征兆。

维基百科的定义:在计算机科学中,内存泄露是一种以如下方式发生的资源泄露——计算机程序错误地分配内存,导致不再需要的内存得不到释放。在面向对象的编程语言中,一个对象若存储在内存中,却无法由运行的代码获取,即为内存泄露。

Java 中常用的内存泄露定义

当不再需要的对象引用仍旧多余地予以保存,即为内存泄露。

在 Java 中,内存泄露是指对象已不再使用,但垃圾回收未能将他们视做不使用对象予以回收。

当程序不再使用某个对象,但在一些无法触及的位置该对象仍旧被引用,即为内存泄露。也因此,垃圾回收器无法删除它。该对象占用的内存空间无法释放,程序所需的总内存就会增加。久而久之,应用的性能就会下降,JVM 可能会耗尽所有内存。

在某种程度上,当无法再给年老区分配内存时,内存泄露就会发生。

内存泄露最常见的一些情况: - ThreadLocal 变量 - 循环与复杂的双向引用 - JNI 内存泄露 - 可变的静态域(最为常见)

我建议结合使用 Visual VM 与 JDK,对内存泄露问题进行调试。

常见的内存泄露调试方法

  1. NetBeans 分析器
  2. 使用 jhat Utility
  3. 创建 Heap Dump
  4. 获取当下运行进程的堆内存柱状图
  5. 获取内存溢出错误的堆内存柱状图
  6. 监控在等待终结的对象数量
  7. 第三方内存调试器

调试内存泄露问题的常用策略或步骤:

  • 确认征兆
  • 启用详细的垃圾回收机制(verbose GC)
  • 启用性能分析
  • 分析堆栈跟踪


已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



2015年,Facebook排名前5的开源项目

$
0
0

本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2016/01/facebook-open-source-projects


Facebook坚信开源的力量。当社区集合起来编写代码时,其好处是不可估量的。有人能指出问题所在,同时解决方案也会很快跟进。借助于社区的力量,大家可以一同解决所面临的挑战,这也会不断加速创新的过程,同时社区会突破既有技术的限制。当然了,成功的项目依赖于强大且富有合作精神的社区。在新的一年开始之际,我们一起来盘点一下Facebook在2015年排名前5的开源项目,度量指标则是根据社区活跃度与影响力来决定的。

HipHop Virtual Machine(HHVM)

HHVM是虚拟机与Web服务器,它于2013年开源,其基础则是2010年所发布的HPHPc编译器。在过去的一年当中,我们看到了该项目的提交量增加了29%,派生数量增加了30%。HHVM常常用作独立的服务器,用于替代Apache与mod_php,旨在执行使用Hack与PHP所编写的程序。它使用了即时编译方法来实现超高的性能,同时又保持了PHP开发者所习惯的灵活性。在过去的一年中,HHVM项目取得了长足的进步:

  • 默认情况下可以使用新的Async特性,包括AsyncMySQL与MCRouter(memcached)支持
  • 12月份在PHP 7发布时宣布对所有主要的PHP 7特性提供支持,同时又发布了用户文档
  • Box宣布将HHVM作为其PHP代码基的执行引擎
  • Etsy在4月份迁移到了HHVM,这有助于帮助公司解决构建移动产品时所面临的各种挑战

React

Facebook在2013年5月开源了React,在过去的一年中,社区的协作关系变得越来越强大了,提交量增加了75%,派生数增加了198%。React是Facebook开发的用于构建用户界面的JavaScript库,现已为很多公司所用,因为它采用了一种不同的方式来构建应用:借助于React,我们可以将应用分解为彼此解耦的独立组件,这样就可以独立维护并迭代各种组件了。2015年,React有两个主要的发布,同时还发布了React Native,并且发布了新的开发者工具。现在已经有越来越多的公司(包括Netflix与WordPress)开始使用React构建自己的产品了。

Presto

Presto是我们开发的一款分布式SQL引擎,主要用于针对各种大小的数据源(从GB到PB)来运行交互式分析查询。我们创建Presto的主要目的在于帮助我们更快地分析数据,因为我们的数据量一直在持续增长,产品周期的节奏也变得越来越快。自从2013年11月开源了Presto后,我们看到它呈现出爆发性增长,使用它的人也越来越多。在过去的一年中,其提交数增加了48%,派生数增加了99%。诸如Airbnb、Dropbox以及Netflix等公司都将Presto作为自己的交互式查询引擎。我们还看到了Presto的使用量在全球范围内的持续增长,这包括来自于日本的社交媒体游戏开发公司Gree,以及来自于中国的电子商务公司京东。

2015年,Teradata宣布了加入Presto社区的计划,将专注于增强其企业级特性并为之提供支持。这也从一个侧面说明了社区相信Presto有能力成为数据基础设施栈的一个重要组成部分。此外,Amazon Web Services(AWS)在其EMR服务中对Presto提供了一流的支持,很多产品用户,包括Nasdaq与领先的商业智能工具厂商MicroStrategy都开始支持Presto,其中MicroStrategy还在其旗舰产品MicroStrategy 10中对其提供了支持。

RocksDB

我们在2013年11月开源了RocksDB,这是一款嵌入式、持久化的键值存储,能够实现快速的存储。过去一年中,除了令人印象深刻的52%的提交数增加与57%的派生数增加外,这个项目在开源社区如此流行的原因在于这款嵌入式数据库能够对由于网络延迟等原因造成的慢查询响应时间起到消除的作用,它非常灵活,完全可以针对各种新兴的硬件发展趋势进行定制。RocksDB在LinkedIn与Yahoo等公司中承担了关键的服务。对于我们来说,这一年的主要关注点在于将RocksDB存储引擎带到通用数据库领域当中,从MongoDB开始。类似于Teradata对Presto的商业支持,这一年RocksDB的另一个里程碑是Percona的数据性能专家宣布对其提供企业级支持。

React Native

React Native是我们最新的一个开源项目,并且于2015年3月开源。借助于React Native,工程师可以使用与React相同的方式和工具来快速构建针对于移动设备的原生应用。除了在内部开发这些工具外,Facebook还联合了开源社区一同改进开发者的体验。2015年,React Native成为了Facebook第2个最为流行的开源项目,其在GitHub上有超过23,000个粉丝。它在Facebook内部用于构建iOS与Android平台的Facebook Ads App,结果就是85%的代码得到了重用,其核心竞争力则是JavaScript。React Native为移动开发所带来的范式转移使得它成为了年度的一个最大亮点。

值得一提的是,约有3,400名开发者为Facebook开源的那些项目贡献出了自己的力量,他们当中的大多数人都不是Facebook员工。一个开源项目的外部贡献者数量是衡量这个开源社区流行度的一个重要指标,Facebook创造了最为流行的开源代码。2015年,约有2,500名外部开发者为Facebook的开源项目贡献了力量,这个数字在2014年则是1,000。开源软件正变得越来越重要,这不仅在互联网巨头和初创企业中是这样,在传统企业中亦如此。诸如Walmart、Target与Booz Allen Hamilton等公司都有官方的GitHub账号,上面有很多仓库以及活跃的贡献者团队。参与开源社区不仅需要更加关注于问题或是免费获取代码(得到免费的开源代码是很容易的事情,但要想将其为特定的场景所用则不是那么轻松的事情),而且还是一种行之有效的人才遴选方式。Facebook现在在GitHub上有330多个开源项目仓库。社区的成长与参与度是非常重要的。2015年,Facebook的公开项目得到了50,000多次提交,2014年这个数字则是28,000。总的星数为318,000,2014年这个数字则是135,000,超过了一倍多。与之类似,2015年总的派生数是53,000,相比于2014年来说增加了127%。

总体来说,我们依然还有很多工作要做,不过我们对以社区方式来完成所有这些工作感到由衷的自豪。这里也感谢在这些项目上花费了巨大心力的每一个人,正是你们的帮助才有了我们璀璨的一年!2016年,我们还会继续同其他开发者协作来全力支持这些项目,我们也期待能与社区有着更为紧密的合作关系。

作者:ricohzhanglong 发表于2016/1/16 1:31:27 原文链接
阅读:177 评论:0 查看评论

Docker应用场景

$
0
0

See; http://www.cnblogs.com/zz123/p/4080219.html


  • Flynn:一个使用go语言编写的开源PaaS平台,目标是简化分布式环境中应用的部署和维护,可以通过git push命令,将应用部署到Docker,从而省去复杂的配置和操作。
  • CoreOS:一种新的架构体系重新设计的Linux发型版,可以运行在既有的硬件活着云服务器上。CoreOS不提供类似yum或apt的包管理工具,用户不需要在CoreOS中安装软件,而是让程序都在Docker容器中运行。
  • Fig:是一个基于Docker的用于快速搭建开发环境的工具,目前Fig团队已经加入Docker公司。
  • Kubernets:来自Google的容器集群管理工具,支持跨平台。目前已经得到微软,IBM,红帽,CoreOS等公司的支持。
  • Boot2Docker:专为Docker设计的轻量级Linux发型包,解决Windows或OS X用户不能安装Docker的问题。
   什么是Docker。Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、相互隔离的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、OpenStack 集群和其他的基础应用平台。 
   Docker应用场景
  • web应用的自动化打包和发布。
  • 自动化测试和持续集成,发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的OpenShift或Cloud Foundry平台来搭建自己的PaaS环境等。
本文主要介绍docker在大数据方面的应用,经过一段时间的研究和实际操作,提出了Hadoop on Docker架构。大概思路就是将硬件(或云服务器)通过Docker搭建成为一个“超级服务器”,这里的超级是指,拥有足够的CPU,内存,并且提供7*24小时不宕机服务(除非同一时间所有物理主机全宕机)。每个Docker容器作为超级服务器资源的一个实例,可以根据需求动态增加实例,以满足计算性能要求。下图是整个Hadoop on Docker的架构
从上自下,依次为:
  • Zookeeper:协调集群中物理主机之间的同步,包括维护一张每个服务器上运行着的容器名单,所有服务器上Docker容器的ip域名映射表(动态更新),Docker容器配置。
  • Server:上面运行着很多docker容器,每个容器运行着特定功能的服务。把应用打包到容器中运行的好处是,应用间是相互隔离的,一个容器宕掉不会影响主机上及其他容器,并且在创建容器的时候可以定制不同的资源(CPU,内存等)。
  • FS:外部文件系统有两个作用:
      1. 将datanode容器挂载到外部文件存储系统中,可以通过增加外部文件系统的磁盘大小来提高hdfs存储能力。
      2. 将所有配置文件存放在公共文件系统中,可以方便整个系统的配置管理,减少重复操作。
  • Yarn:资源管理系统,最终的目标是可以将不同的集群容器(storm,spark等)放在同一个yarn系统中,通过yarn的调度来为不同集群分配不同资源。
有人会有疑问:如今服务器已经很廉价,完全可以在不同服务器上运行不同服务,没必要使用docker。
如果硬件服务器对你来说确实是廉价的,以至于搭建100个节点的hadoop集群,大多数情况下运行mapreduce job的节点书不超过10个,剩余90台服务器常年处于休息状态,对你来说也无关紧要的话,我无话可说。抛开硬件成本不说,docker容器的隔离机制也是集群部署中的一大亮点!
本文的目的是通过docker容器,使用更少的硬件资源来运行同样的job,容器相对于服务器来说是更细粒度的资源。同时由于容器的隔离机制,一个容器发生故障并不影响到其他容器及宿主主机。此外这种架构还解决了单点故障问题,每台服务器运行着相同的docker镜像,通过定时向zookeeper发送心跳,来监控所有容器的健康状态,心跳是一份包含该服务器上所有运行着的容器的名单。那么有可能发生两种突发情况:
  • docker容器挂掉
  • 宿主主机宕机
对于第一种情况,由于心跳包含所有运行着容器的名单,当服务器某个容器挂掉,比如mysql意外终止,zookeeper通过两次心跳对比,发现缺少mysql,于是启动应急措施,重启该服务器的mysql容器。如果宿主主机宕机,zookeeper在一段时间内未接受该服务器的心跳,发现宕机,然后在其余剩下的服务器中重启上一次心跳名单中运行着的容器,如图所示
整个系统的实现还有一个前提,就是使不同宿主主机上的docker容器能够通信,可以参见 这篇
最终的目的是使整个架构看起来像在一台超级服务器(cpu,内存足够大,并且永不宕机)上运行hadoop。
Viewing all 11805 articles
Browse latest View live