ShutdownHook-优雅关闭

需求:
1.在应用启动的时候将应用的信息注册到zk
(下游会判断zk中是否存在应用信息,需要等待应用完全加载成功再写入到zk)
2.应用完全关闭之前将应用信息从zk删除。
(如果下游判断zk在应用关闭之后还存在,仍然会请求,但不会有响应,所以需要在应用完全关闭之前将zk中应用的信息摘除)

解决:
在spring的环境下
1.
注册的服务类实现ApplicationListener,重写onApplicationEvent,Thead.sleep(waitTime);
2.两种方法
    a.使用tomcat的listener,但是需要在每个应用的web.xml中都添加配置,耦合性太强
    b.使用shutdownHook
        JDK提供了Java.Runtime.addShutdownHook(Thread hook)方法,可以注册一个JVM关闭的钩子,这个钩子可以在一下几种场景中被调用:
        程序正常退出
        使用System.exit()
        终端使用Ctrl+C触发的中断
        系统关闭
        OutOfMemory宕机
        使用Kill pid命令干掉进程(注:在使用kill -9 pid时,是不会被调用的)

        ApplicationShutdownHooks里有一个IdentityHashMap存放钩子线程的map,
        其初始化的时候会往Shutdown的hooks线程组放一个执行IdentityHashMap钩子map的线程。
        当JVM关闭的时候会执行Shutdown的exit,触发Shutdown的hooks,触发钩子线程组。


code:
public void onApplicationEvent(ApplicationEvent event) {
        int delay = 5000;
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            unRegister();
        }, "unRegisterThread"));
        new Thread(() -> {
            try {
                Thread.sleep(delay);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            register();
        }, "registerDelayThread").start();
}

websockettttttt

websocket是什么

WebSocket是H5提供的一种基于TCP链接进行full-duplex(全双工)通信的协议。
http协议需要三次握手,一次request对应一次reponse,只能通过客户端主动向服务端发送请求。
Websocket是一次握手,然后建立一个通道,持续通信。客户端可以向服务端请求,而且服务端也可以主动向客户端发送信息。
当然也可以通过类似ajax轮询之类的方式做到类似的功能,但是比较被动,和一条懒狗是的,得戳一下才能挪几步,很耗费精力(资源)。
websocket可是真正的双向通信。

应用场景

1.社交订阅
2.多玩家游戏     
3.协同编辑/编程
4.点击流数据         
5.股票基金报价
6.体育实况更新
7.多媒体聊天
8.基于位置的应用
9.在线教育

具体的

我就写了一下, 基于spring-websockt的,当然直接用tomcat8自带的tomcat-websocket.jar也成 。这里不得不说下websocket当下最火的应用
场景,弹幕,我就直接去b站了。
基于websockt聊天室

a.直播

上图有这么几个参数需要搞一哈
Request Headers
Connection: Upgrade #表示当前的连接方式是升级版的,普通的http一般是keep-alive长连接方式
Upgrade: websocket  #升级版的叫做websocket
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== #这是浏览器随机生成的base64之后的值,作为一个有身份的链接
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

Response  Headers
Sec-WebSocket-Accept    #这个是Sec-WebSocket-Key加密后的一串    
上图WebSocket通信的Time一直是pending。
frames就是具体通道

b.非直播

先把以前包括时间点,屏幕位置的弹幕信息拉下来,
当然还有一个websocket通道来收集新的弹幕。

性能管理工具pingpoint

最近没什么事,研究了一下pingpoint,供以后参考。
这是一个能够管理大型分布式应用的性能管理工具,通过追踪分布式的事务会话,提供分析整体架构中容器之间的交互的解决方案。
优点是侵入少,通过几行代码就能安装监控引擎,对应用最低只有3%的影响。
pingpoint地址:https://github.com/naver/pinpoint

整体架构

准备 (一定要注意版本搭配)

centOS虚拟机3台,2台2G,1台4G(关掉防火墙的)
jdk 1.8
tomcat 8
HBase 1.2.6
Pingpoint Collector 1.6.2
Pingpoint Web   1.6.2
Pingpoint Agent 1.6.2
zookeeper 3.4.9

1.启动zookeeper

三台虚机地址
192.168.247.128
192.168.247.129
192.168.247.130
每台都布置了zk

2.配置hbase

hbase存储收集的信息,一般也要分布式的集群,我这里就启动一台

修改hbase-env.sh

配置自己的jdk的地址
export JAVA_HOME=/usr/local/jdk1.8.0_101
用自个的,不用hbase管理zk
export HBASE_MANAGES_ZK=false

修改hbase-site.xml

一般hbase要用hdfs做数据落地
配置zookeeper地址
配置hbase为分布式的
配置zookeeper数据存放路径
面是我自己的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<property>
<name>hbase.rootdir</name>
<value>hdfs://data1:9000/hbase</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>192.168.247.128,192.168.247.129,192.168.247.130</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/usr/local/zookeeper-3.4.9/data/</value>
</property>

在hbase目录执行

./bin/start-hbase.sh
可能会要输入password验明正身,在zookeeper的bin目录下用zkCli.sh去看路径多了一个hbase的znode节点。
[root@server3 hbase-1.2.6]# jps
13555 HMaster       
10794 QuorumPeerMain
13659 HRegionServer
18203 Jps
然后需要初始化pingpoint的数据格式文件hbase-create.hbase,这个文件在下载网页的source code.zip解压完的hbase->scripts文件下面
然后执行
./hbase-1.2.6/bin/hbase shell hbase-create.hbase
hbaes提供了界面化的工具,hbase部署的ip:端口 192.168.247.130:16010

3.配置web,collector,agent

tomcat的tar包解压,记得修改conf.server.xml的端口号。
把pinpoint-web-1.6.2.war解压放在tomcat_web/webapps/ROOT,然后启动,地址192.168.247.130:38080
把pinpoint-collector-1.6.2.war解压在tomcat_collector/webapps/ROOT,然后启动
把pinpoint-agent-1.6.2.tar.gz解压到/usr/local/pinpoint-agent-1.6.2
需要监控的程序,比如tomcat
修改bin/catalina.sh
在头上加
CATALINA_OPTS="$CATALINA_OPTS -javaagent:/usr/local/pinpoint-agent-1.6.2/pinpoint-bootstrap-1.6.2.jar"
CATALINA_OPTS="$CATALINA_OPTS -Dpinpoint.agentId=ppserverOne"
CATALINA_OPTS="$CATALINA_OPTS -Dpinpoint.applicationName=server"
访问一下测试程序

4.监控

打开tomcat_web的地址192.168.247.130:38080
主页面
server状态

base64编解码


import java.util.Base64;

/**
 * Description
 * Created by vinc on 2017/9/6.
 * base64 编解码
 *
 * 编码
 * 将每个字节补为8位的2进制,3个字节为1组
 * 每组6位,转化为10进制到基本字符表toBase64URL中找对应字符
 * 不是3的倍数补成3的倍数填充1或2个0字节,转成10进制找对应字符
 *
 * 解码就是掉个个
 */
public class Base64Application {
    private static final char[] toBase64URL = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
    };

    public static void main(String[] args) {
        String org = "degxgdew";
        System.out.println("org:" + org);
        System.out.println();
        byte[] encode1 = Base64.getEncoder().encode(org.getBytes());
        System.out.println(new String(encode1));
        byte[] decode1 = Base64.getDecoder().decode(new String(encode1));
        System.out.println(new String(decode1));
        System.out.println();
        String encode = mbase64Code(org);
        System.out.println(encode);
        String decode = mbase64Decode(encode);
        System.out.println(decode);
    }

    //base64解码
    private static String mbase64Decode(String encode) {
        encode = encode.replaceAll("=", "");
        char[] chars = encode.toCharArray();
        StringBuilder deStr = new StringBuilder();
        f1:
        for (int i = 0; i < chars.length; i++) {
            for (int j = 0; j < toBase64URL.length; j++) {
                if (toBase64URL[j] == chars[i]) {
                    String indexStr = Integer.toBinaryString(j);
                    int length = indexStr.length();
                    for (int k = 0; k < 6 - length; k++) {
                        indexStr = "0" + indexStr;
                    }
                    deStr.append(indexStr);
                    continue f1;
                }
            }
        }
        StringBuilder result = new StringBuilder();
        int index = 0;
        for (int i = 1; i <= deStr.length() / 8; i++) {
            result.append((char) Integer.valueOf(deStr.substring(index, i * 8), 2).intValue());
            index += 8;
        }
        return result.toString();
    }

    //base64编码
    private static String mbase64Code(String abc) {
        byte[] bytes = abc.getBytes();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String bitStr = Integer.toBinaryString(bytes[i]);
            int len = bitStr.length();
            for (int j = 0; j < 8 - len; j++) {
                bitStr = "0" + bitStr;
            }
            sb.append(bitStr);
        }
        while (sb.length() % 3 != 0) {
            sb.append("0");
        }
        StringBuilder result = new StringBuilder();
        for (int j = 0; j < sb.length() / 6; j++) {
            result.append(toBase64URL[Integer.parseInt(sb.substring(j * 6, (j + 1) * 6), 2)]);
        }
        int leng = abc.length() % 3;
        for (int i = 0; i < 3 - leng % 3; i++) {
            result.append("=");
        }
        return result.toString();
    }
}

nginx简易使用


1.安装依赖的包

yum -y install pcre-devel openssl openssl-devel
pcre-devel (PCRE库是一组使用与Perl 5相同的语法和语义来实现正则表达式模式匹配的函数。)
openssl(OpenSSL是一个开源项目,为传输层安全(TLS)和安全套接字层(SSL)协议提供了强大的商业级和全功能工具包。 它也是通用加密库。)
openssl-devel(OpenSSL是支持加密技术的工具包。 openssl-devel包包含开发支持各种加密算法和协议的应用程序所需的包含文件。)

2.安装nginx

第一步:从http://nginx.org/download/上下载相应的版本
(或者wget http://nginx.org/download/nginx-1.12.0.tar.gz直接在Linux上用命令下载)
第二步:解压 tar -zxvf nginx-1.12.0.tar.gz 到指定喜欢的目录
第三步:设置一下配置信息 ./configure --prefix=/usr/local/nginx ,这样一些配置文件,日志,执行文件都放到/usr/local/nginx下
第四步:
make 编译 (make的过程是把各种语言写的源码文件,变成可执行文件和各种库文件)
make install 安装 (make install是把这些编译出来的可执行文件和库文件复制到合适的地方)

cd到/usr/local/nginx/ 目录 /sbin/nginx 就能够启动了
默认的访问端口是80,访问ip会出现Welcome to nginx的字样,安装成功了,但是没什么用。
conf目录底下的nginx.conf才是关键。

3.nginx.conf

http {
    //包括的接受类型
    include       mime.types;
    default_type  application/octet-stream;
    //日志的格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    //日志地址
    #access_log  logs/access.log  main;
    sendfile        on;
    #tcp_nopush     on;
    #keepalive_timeout  0;
    //长连接超时时间
    keepalive_timeout  65;
    #gzip  on;
   //重点配置
    server {
    //默认向外暴露的端口
        listen       80;
    //暴露的域名
        server_name  localhost;
    //默认编码
        charset utf-8;
        #access_log  logs/host.access.log  main;
    //配置静态资源
        location / {
            root     /nh/appdir/html/fe_cms/ad_operator/;
            index   /index.html;
     #error_page 404 /syserror/404.html; //地址“/”下错误跳转的页面
            #access_log off;  //可配置是否不记录日志
        }
    //配置接口,容器的访问地址
        location /operator {
             proxy_pass http://127.0.0.1:8080;
        }
    location ~ \.(gif|jpg|png)$ {
            root /data/images;
    }
    //全局404错误页面
    error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #全局错误
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   html;
    }
    }
    //如果有多个配置 加载vhosts路径下的所有conf
    include vhosts/*.conf;
}

配置完 nginx -s reload 重启,效果就有了。
nginx -s stop  快速的关闭
nginx -s quit   滑溜的关闭
nginx -s reload  重新加载配置文件
nginx -s reopen   重启log文件
mine.types
当web服务器收到静态的资源文件请求时,依据请求文件的后缀名在服务器的MIME配置文件中找到对应的MIME Type,
再根据MIME Type设置HTTP Response的Content-Type,然后浏览器根据Content-Type的值处理文件。

3.反向代理

upstream c-ads {
    #ip_hash;
    server 192.168.247.128:8080    weight=10 max_fails=3 fail_timeout=10;
    server 192.168.247.129:8080    weight=10 max_fails=3 fail_timeout=10;
}
server {
    listen      80;
    server_name 192.168.247.129;
    location / {
        #include proxy.conf;
        proxy_pass http://c-ads;
    }
}
负载均衡的策略
nginx 的 upstream目前支持 4 种方式的分配 :
1)轮询(默认) 
      每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。 
2)weight 
      指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 
2)ip_hash 
      每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。  
3)fair(第三方) 
      按后端服务器的响应时间来分配请求,响应时间短的优先分配。  
4)url_hash(第三方)

jenkins简易使用


1.从官网下载stable版本的war包。(此处版本使用2.46.3)
2.部署到tomcat,启动。
3.根据提示步骤进行填写选择配置。
4.确保安装了jdk,maven,安装git。
    系统管理->Global Tool Configuration
    下面有JDK,GIT,MAVEN,ANTZ的配置,把自己安装的路径配到相应位置。
5.进入主页面,新建->填入项目名,选择构建自由风格的软件项目
源码管理
    1).源码管理
    选择git,填入自己的仓库地址
    下面有一个Credentials需要填入证书
    我试了两种方式
        a.Username and password ,然后填入自己git的账号密码
        b.Secret file 选择配置在git公钥的路径, 或者选择Secret text 直接填入公钥
    选择要构建的分支
2).构建
添加构建
    Invoke-top-level Maven targets
    Maven Version选择第四步配置的maven的名称
    Goals填入maven构建语句,比如
        clean package -Dmaven.test.skip=true
    当然后面一大段参数根据实际的需求
Execute shell
    shell脚本可以把需要的包摘出来,放到部署环境,或者直接启动容器
    之类的操作
3).构建后操作
    Archive the artifacts
    用于存档的文件  **/*.war,**/*.tar.gz
4).立即构建
    跟踪console日志,一般打完的包会在/root/,jenkins/workspace。

SocketTimeOut引发的问题


最近工作的时候和上游对接广告,出现一些超时的问题。

总的请求时间= 网络传输时间 + 服务器响应时间
服务器总的响应时间 可以通过 nginx的request_time 来统计,即nginx处理请求的时间
网络传输时间可以使用 ping 或者 ab 命令进行验证。

压力测试命令 ab

Usage: ab [options] [http[s]://]hostname[:port]/path
Options are:
    -n requests     Number of requests to perform              //总请求数
    -c concurrency  Number of multiple requests to make    //每次请求的并发数
    -t timelimit    Seconds to max. wait for responses        //最大等待响应时间
    -b windowsize   Size of TCP send/receive buffer, in bytes    //TCP传输接收的缓冲区大小
    -p postfile     File containing data to POST. Remember also to set -T    //POST请求
    -u putfile      File containing data to PUT. Remember also to set -T     //GET请求
    -T content-type Content-type header for POSTing, eg.    //设置contentType
                    'application/x-www-form-urlencoded'
                    Default is 'text/plain'
    -v verbosity    How much troubleshooting info to print        //详细输出
    -w              Print out results in HTML tables                //打印HTML样式的结果
    -i              Use HEAD instead of GET                    //HEAD代替GET
    -x attributes   String to insert as table attributes            //设置html table的属性
    -y attributes   String to insert as tr attributes            //设置html tr属性
    -z attributes   String to insert as td or th attributes        //设置html td th 属性
    -C attribute    Add cookie, eg. 'Apache=1234. (repeatable)    //添加请求的cookie
    -H attribute    Add Arbitrary header line, eg. 'Accept-Encoding: gzip'    //添加请求 header
                    Inserted after all normal header lines. (repeatable)
    -A attribute    Add Basic WWW Authentication, the attributes    //添加身份认证
                    are a colon separated username and password.
    -P attribute    Add Basic Proxy Authentication, the attributes    //添加代理认证
                    are a colon separated username and password.
    -X proxy:port   Proxyserver and port number to use            //使用代理
    -V              Print version number and exit                    //ab 版本
    -k              Use HTTP KeepAlive feature                    //使用长连接(并发和总请求数相同不会触发长连接)
    -d              Do not show percentiles served table.
    -S              Do not show confidence estimators and warnings.
    -g filename     Output collected data to gnuplot format file.        //输出到指定文件
    -e filename     Output CSV file with percentages served        //输出到CSV文件
    -r              Don't exit on socket receive errors.                //不因为接受错误退出
    -h              Display usage information (this message)
    -Z ciphersuite  Specify SSL/TLS cipher suite (See openssl ciphers)    //指定SSL/TLS认证
    -f protocol     Specify SSL/TLS protocol (SSL3, TLS1, or ALL)        //指定SSL/TLS协议

总请求1000次,并发10,保持长连接,请求上游的地址。和真实线上的环境差不多。
aixuw@uy01-07:~$ ab  -n 1000 -c  10 -v -k  http://adapi.xxxx.com:7702/time
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking adapi.xxxx.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        nginx/1.9.12
Server Hostname:        adapi.xxxx.com
Server Port:            7702

Document Path:          /time
Document Length:        26 bytes

Concurrency Level:      10                //并发
Time taken for tests:   5.967 seconds        //测试总用时
Complete requests:      1000                //完成的请求
Failed requests:        0
Write errors:           0
Total transferred:      209000 bytes
HTML transferred:       26000 bytes
Requests per second:    167.59 [#/sec] (mean)
Time per request:       59.670 [ms] (mean)    //平均每次请求时间
Time per request:       5.967 [ms] (mean, across all concurrent requests)  //并发平均每个请求时间
Transfer rate:          34.21 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       26   30  31.5     29    1025
Processing:    26   29   1.8     29      40
Waiting:       26   29   1.8     29      40
Total:         53   59  31.6     57    1053

Percentage of the requests served within a certain time (ms)
  50%     57
  66%     59
  75%     60
  80%     61
  90%     63
  95%     66
  98%     68
  99%     70
 100%   1053 (longest request)

据上游反应服务器的响应时间也就是nginx处理请求时间在200到250ms以内加上网络传输时间超过了我们设置的250ms超时时间。
 最后我们这边将超时时间改为300ms,超时率下降。

完整的http连接

客户端C,服务端S
三次握手
    1.C向S发送TCP的包,带上标志SYN
    2.S接受后开始回复SYN+ACK给C,表示同意连接
    3.C发送ACK给S,完成三次握手
四次挥手
    1.C经过大约30s表示不会再请求数据,便向S发送FIN的标志
    2.S收到向C发送ACK。   此时连接处于半关闭,S可以向C发送,C无法向S请求数据
    3.S要把连接关闭向C发送FIN
    4.C向S发送ACK,连接完全关闭

参考: https://zhuanlan.zhihu.com/p/27021102?group_id=849574141450412032


mysql语句执行顺序


1. FORM: 对FROM的左边的表和右边的表计算笛卡尔积。产生虚表VT1
2. ON: 对虚表VT1进行ON筛选,只有那些符合<join-condition>的行才会被记录在虚表VT2中。
3. JOIN: 如果指定了OUTER JOIN(比如left join、 right join),那么保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,
产生虚拟表VT3, rug from子句中包含两个以上的表的话,那么就会对上一个join连接产生的结果VT3和下一个表重复执行步骤1~3这三个步骤,
一直到处理完所有的表为止。
4. WHERE: 对虚拟表VT3进行WHERE条件过滤。只有符合<where-condition>的记录才会被插入到虚拟表VT4中。
5. GROUP BY: 根据group by子句中的列,对VT4中的记录进行分组操作,产生VT5.
6. CUBE | ROLLUP: 对表VT5进行cube或者rollup操作,产生表VT6.
7. HAVING: 对虚拟表VT6应用having过滤,只有符合<having-condition>的记录才会被 插入到虚拟表VT7中。
8. SELECT: 执行select操作,选择指定的列,插入到虚拟表VT8中。
9. DISTINCT: 对VT8中的记录进行去重。产生虚拟表VT9.
10. ORDER BY: 将虚拟表VT9中的记录按照<order_by_list>进行排序操作,产生虚拟表VT10.
11. LIMIT:取出指定行的记录,产生虚拟表VT11, 并将结果返回。

where后的查询条件是从右往左执行

mysql常用命令

1.设置mysql编码


查看原先的编码
show variables like'character%';
设置为utf8
设置默认编码为utf8:
set names utf8;
set character_set_client='utf8';
set character_set_connection='utf8';
set character_set_results='utf8';

2.mysql 重启


service mysqld restart

3.数据库导出


命令行下具体用法如下:  mysqldump -u用戶名 -p密码 -d 数据库名 表名 脚本名;
1、导出数据库为dbname的表结构(其中用戶名为root,密码为dbpasswd,生成的脚本名为db.sql)
mysqldump -uroot -pdbpasswd -d dbname >db.sql;
2、导出数据库为dbname某张表(test)结构
mysqldump -uroot -pdbpasswd -d dbname test>db.sql;
3、导出数据库为dbname所有表结构及表数据(不加-d)
mysqldump -uroot -pdbpasswd  dbname >db.sql;
4、导出数据库為dbname某张表(test)结构及表数据(不加-d)
mysqldump -uroot -pdbpasswd dbname test>db.sql;
5. 导出时候带有条件
mysqldump -uroot -pdbpasswd dbname  test -w"where_condition">db.sql;

4.数据库导入


导入数据库
常用source 命令
进入mysql数据库控制台,
如mysql -u root -p
mysql>use 数据库
然后使用source命令,后面参数为脚本文件(如这里用到的.sql)
mysql>source d:wcnc_db.sql
第二种方式导入
mysql -uroot -proot -h 127.0.0.1 cms < /root/cms20170207online.sql

5.查看connection使用情况


show processlist
查看最大连接数
show variables like '%max_connections%';
设置最大连接数
set global max_connections=1000;

6.配置权限


grant all privileges on cms.* to cms@'cms' identified by 'oupeng_cms';
flush privileges

7.导出查询语句数据 导入到excel 文件中


mysql -h 192.168.5.xx -P 3307 -uxxxx -pxxxx -e
"SELECT
    sid '广告位id',
    aid    '广告id',
    request    '广告请求',
    dsp_request 'dsp广告请求',
    dsp_response 'dsp广告返回',
    response    '广告返回',
    display    '展示',
    click    '点击',
    d    '日期',
    h '小时'
from
    ad_bdata.ad_data_monitor
where
    d BETWEEN 20170210 and 20170216
ORDER BY d desc, h desc" > monitordata.xls

8.待添加。。。。。

Data_structures_linked_list


1.链表定义

链表即是由节点(Node)组成的线性集合,每个节点可以利用指针指向其他节点。它是一种包含了多个节点的、能够用于表示序列的数据结构。
单向链表: 链表中的节点仅指向下一个节点,并且最后一个节点指向空。
双向链表: 其中每个节点具有两个指针 p、n,使得 p 指向先前节点并且 n 指向下一个节点;最后一个节点的 n 指针指向 null。
循环链表:每个节点指向下一个节点并且最后一个节点指向第一个节点的链表。
时间复杂度:
索引: O(n)
搜索: O(n)
插入: O(1)
移除: O(1)

2.code


//俩链表相加结果逆序放在一个新的链表
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
    ListNode l11 = l1;
    ListNode l22 = l2;
    ListNode lo = new ListNode(0);
    ListNode head = lo;
    int sum = 0;
    while (l11 != null || l22 != null) {
        sum /= 10;
        if (l11 != null) {
            sum += l11.val;
            l11 = l11.next;
        }
        if (l22 != null) {
            sum += l22.val;
            l22 = l22.next;
        }
        head.next = new ListNode(sum % 10);
        head = head.next;
    }
    if (sum / 10 == 1)
        head.next = new ListNode(1);
    return lo.next;
}

//删除链表中指定的元素
public void deleteNode(ListNode node) {
    node.val = node.next.val;
    node.next = node.next.next;
}

//链表逆序展示
public ListNode reverseList(ListNode head) {
    if (head == null) return head;
    ListNode newList = new ListNode(0);
    while (head != null) {
        ListNode tmp = head;
        head = tmp.next;
        tmp.next = newList;
        newList = tmp;
    }
    return newList;
}

/**
 * 回文结构  123321 正反读一样
 * 一个读的快 一个读的慢,
 * 栈先进后出
 *
 * @param head
 * @return
 */
public boolean isPalindrome(ListNode head) {
    ListNode s = head;
    ListNode f = head;
    Stack<Integer> stack = new Stack();

    while (f != null && f.next != null) {
        stack.push(s.val);
        f = f.next.next;
        s = s.next;
    }
    //如果只有一个数
    if (f != null)
        s = s.next;
    while (s.next != null) {
        if (s.next.val != stack.pop()) return false;
        s = s.next;
    }
    return true;
}

//链表排序
public ListNode mergeKLists(ListNode[] lists) {
    ListNode lo = new ListNode(0);
    ListNode head = lo;

    for (int i = 0; i < lists.length; i++) {
        for (int j = 0; j < lists.length - 1; j++) {
            if (lists[j].val < lists[j + 1].val) {
                ListNode tmp = null;
                tmp = lists[j];
                lists[j] = lists[j + 1];
                lists[j + 1] = tmp;
            }
        }
    }
    for (ListNode l : lists) {
        head.next = l;
        head = head.next;
    }
    return lo.next;
}
class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }

}