nodejs

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。
你编码不认真,java会给你丘,而nodejs会给你很多坑,使用WebStorm开发有的会错误会报错,有的则运行通过产生意料之外的行为。

socket.connect参数顺序

创建TCP客户端的坑之connect的参数顺序是先port再host:

var net = require('net');
var HOST = '127.0.0.1';
var PORT = 8888;
var client = new net.Socket();
client.connect(PORT, HOST, function() {
    console.log('CONNECTED TO: ' + HOST + ':' + PORT);
    // 建立连接后立即向服务器发送数据,服务器将收到这些数据 
    client.write('message');
});

pm2

Nodejs开发中修改完代码以后需要重启服务才能看到效果。
forever可以通过对资源变化的检测做到变化后自动重启,并且可以在异常后重启,保证服务一直在线。
pm2 = P (rocess) M (anager)2,是可以用于生产环境的Nodejs的进程管理工具,并且它内置一个负载均衡。它不仅可以保证服务不会中断一直在线,并且提供0秒reload功能,还有其他一系列进程管理、监控功能。并且使用起来非常简单。

pm2的安装和使用

pm2 start app.js
pm2 save
pm2 startup
pm2 reload all
pm2 list
pm2 restart [id]

~# ls -a显示所有包括隐藏的文件,可以看到.pm2文件夹

更多pm2常用的命令用法介绍
http://i5ting.github.io/node-deploy-practice/
http://www.111cn.net/sys/linux/120062.htm
http://www.pangjian.info/2016/12/02/deploy-nodejs-pm2-1/?utm_medium=referral

缓存

nodejs通过文件名缓存加载过的模块,这里是全局缓存,不是页面内缓存。

grpc

安装grpc-tools
$ sudo npm install grpc-tools -g
把proto文件生成js文件
$ /usr/local/lib/node_modules/grpc-tools/bin/protoc --js_out=import_style=commonjs,binary:. --grpc_out=. --plugin=protoc-gen-grpc=/usr/local/lib/node_modules/grpc-tools/bin/grpc_node_plugin *.proto

http参数

参数名是区分大小写的,不存在的参数值是undefined
取get地址?后面的传参
var id=req.query.id;
取rest路径中的参数
var id = req.params.id;
取post时json对象中的参数
id=req.body.id;

express超时重复请求

3种解决办法
1.httpserver设置超时函数
var app = express();
var http = require(‘http’);
var server = http.createServer(app);
server.on(‘timeout’, onTimeout);
function onTimeout(err) {
}
2.加大超时时间
server.timeout=10*60*1000;
3.request或response设置超时处理方法
router.post(‘/xxx’,function(req,res,next){
req.setTimeout(240000,function () {
});
}
http://blog.csdn.net/puncha/article/details/9378197

async

npm install async –save,其中–save参数会在工程package.json中dependencies中增加一条依赖;
async主要实现了三个部分的流程控制功能:
集合: Collections
流程控制: Control Flow
工具类: Utils

Nodejs异步流程控制Async

常用的流程控制:
series 串行,保证顺序不依赖
parallel 并行
waterfall 依赖串行、瀑布流,之间需要传递结果时使用
auto 并行加依赖串行
apply 给函数预置第一个参数,然后返回一个新的函数。

Json Web Token(JWT)

传统的 cookie-session 机制可以保证的接口安全,在没有通过认证的情况下会跳转至登入界面或者调用失败。
在如今 RESTful 化的 API 接口下,cookie-session 已经不能很好发挥其余热保护好你的 API 。
更多的形式下采用的基于 Token 的验证机制,JWT 本质的也是一种 Token,但是其中又有些许不同。
http://blog.csdn.net/liuwenbiao1203/article/details/52351772
https://www.npmjs.com/package/jsonwebtoken
http://www.haomou.net/2014/08/13/2014_web_token/

跨域请求会先发出一个option请求,再发出一个业务上的get或post请求。

socket超时

var socket = new net.Socket(); 创建后
socket.setTimeout(10 * 1000, function () {
if(!idle) {
console.log(‘timeout not idle’);
if (callback) {
callback(false, {message: ‘请求超时’});
callback = null;
}
}else{
console.log(‘timeout idle’);
}
});
不执行connect或write,10秒后会打印timeout idle。
等待9秒后再执行connect,如果connect很久,会在connect开始10秒后打印timeout not idle。
即创建socket和connect或write会开始新一轮超时计时。但不能多次设置settimeout,会引发emit数量警告。
idle为自定义的状态,在connect或wirte时设置idle=false。

安装最新稳定版本
https://segmentfault.com/a/1190000007542620

网络基础

子网掩码

255.255.0.0 表示192.168.(0 – 255).(0 – 255)的IP地址都在同一网段内。
255.255.255.0 表示192.168.0.(0 – 255)的IP地址都在同一网段内。

A、B、C类IP地址

IP地址是互联网上进行寻址的地址编码,IP地址有4个字节,32位组成。为了区分IP地址,将IP地址划分为A类,B类,C类。
C类地址第1字节、第2字节和第3个字节为网络地址,第4个字节为主机地址。第1个字节的前三位固定为110。地址范围 192.0.0.0到223.255.255.255,私有地址 192.168.0.0到192.168.255.255,默认子网掩码 255.255.255.0,第1个字节的二进制值前三位位必须是“110”,即11000000开始到11011111结束,所以第一段的范围为192~223。
一个C类地址是由3个字节的网络地址和1个字节的主机地址组成。每个C类地址可连接254台主机(0是网络号不可用, 255是广播地址,除去这2个,可用的就是254个地址),Internet有2097152个C类地址段(32*256*256),有532676608个地址(32*256*256*254)。

如果电脑超过了254台,如果子网掩码设为255.255.255.0,需要有2个网段,不同网段下的电脑需要路由器或者三层交换机才能互相访问。

双网卡设置内外网

为默认网关(default gateway)只能是一个!删掉局域网的网关配置。
http://blog.csdn.net/chenlycly/article/details/52136960

Linux命令

安装命令

一般来说著名的linux系统基本上分两大类:

1.社区组织维护的发行版本 Debian系列:Debian、Ubuntu等
apt-get:Advanced Packaging Tool,apt是Debian Linux发行版中的APT软件包管理工具。所有基于Debian的发行都使用这个包管理系统。deb包可以把一个应用的文件包在一起,类似Windows上的安装文件。

一般可以通过使用ppa/源方式或下载两种方式安装软件。
Ubuntu 安装 JDK 7 / JDK8 的两种方式
http://www.cnblogs.com/a2211009/p/4265225.html
如果在ubuntu上报 add-apt-repository: command not found,先安装python。
sudo apt-get install python-software-properties
sudo apt-get install software-properties-common

2.商业公司维护的发行版本 RedHat系列:Redhat、Centos、Fedora等
Yum(全称为 Yellow dog Updater, Modified)是一个在Fedora和RedHat以及SUSE中的Shell前端软件包管理器。基於RPM包管理,能够从指定的服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软体包,无须繁琐地一次次下载、安装。
简单点说, rpm 只能安装已经下载到本地机器上的rpm 包. yum能在线下载并安装rpm包,能更新系统,且还能自动处理包与包之间的依赖问题。

查看资源信息
yum info supervisor

修改网络

服务器地址设置为static,不使用dhcp
ifconfig
sudo vim /etc/network/interfaces
sudo vim /etc/resolv.conf
sudo /etc/init.d/networking restart 可能不起作用
sudo reboot

另外长按重置路由器要在带电时操作。

搜索

grep全称是Global Regular Expression Print,表示全局正则表达式版本,是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

$ grep 'abc' *.java
$ ps -ef | grep java

常用命令

netstat -anptl 查看服务监听端口
tar -zxvf xxxx.tgz 解压压缩包

查看Centos系统信息

cat /etc/redhat-release #查看os版本
free -h #查看内存使用

http://www.centoscn.com/CentOS/help/2013/0728/738.html

JVM

JVM

JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

Java语言的一个非常重要的特点就是与平台的无关性,使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码,Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

http://www.mamicode.com/info-detail-1028149.html

HotSpot VM

HotSpot VM是绝对的主流的JVM。大家用它的时候很可能就没想过还有别的选择,或者是为了迁就依赖了Oracle/Sun JDK某些具体实现的烂代码而选择用HotSpot VM省点心。Oracle / Sun JDK、OpenJDK的各种变种(例如IcedTea、Zulu),用的都是相同核心的HotSpot VM。从Java SE 7开始,HotSpot VM就是Java规范的“参考实现”(RI,Reference Implementation)。把它叫做“标准JVM”完全不为过。当大家说起“Java性能如何如何”、“Java有多少种GC”、“JVM如何调优”云云,经常默认说的就是特指HotSpot VM。可见其“主流性”。JDK8的HotSpot VM已经是以前的HotSpot VM与JRockit VM的合并版,也就是传说中的“HotRockit”,只是产品里名字还是叫HotSpot VM。不过要留意的是,这里我说的HotSpot VM特指“正常配置”版,而不包括“Zero / Shark”版。Wikipedia那个页面上把后者称为“Zero Port”。用这个版本的人应该相当少,很多时候它的release版都build不成功…

JVM调优-分代垃圾回收

分代垃圾回收采用分而治之的思想,进行代的划分,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收。

虚拟机中的共划分为三个代:年轻代(Young Generation)、年老代(Old Generation)和持久代
(Permanent Generation)。

年轻代
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

老年代
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

持久代
持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系不大。

什么情况下触发垃圾回收?

由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

Scavenge GC(搜寻)
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

Full GC
对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比ScavengeGC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:
· 年老代(Tenured)被写满
· 持久代(Perm)被写满
· System.gc()被显示调用

从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

特别注意,在程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。

https://my.oschina.net/ydsakyclguozi/blog/404389

操作系统

线程原理

多线程是宏观上的并行,微观上依旧是串行
多线程之所以能够实现,第一是硬件的功劳,也就是CPU。现代的CPU有一个很重要的特性,就是时间片。每一段获得CPU的代码只能运行一个时间片规定的时间,例如10ms。到时间之后CPU就会把正在运行的代码暂停,然后发生一个中断。这个中断是系统级的事件,只有操作系统能够接手,这样控制权就落到了操作系统手里。
接下来就是操作系统的事情了。线程对操作系统来说就是一段代码+运行时数据(主要是寄存器数据,还有线程中与资源相关的数据,比如打开的文件等)。操作系统会为每个线程保存相关的这些数据,当接收到来自CPU的时间片中断事件时,就会按一定规则从这些线程中选择一个,恢复它的运行时数据,这样CPU就可以继续执行这个线程了。

选择一个合适的线程的过程称为线程调度,最简单的规则是FCFS,也就是按排队的时间先后顺序调度,谁先来排队,下一个就让谁运行。另外还有按优先级、按任务大小等调度策略,以及多种策略的组合等方式。详细的可以去了解一下操作系统的原理。

Java中线程实现主要依赖于操作系统,其本身不进行线程管理。它只是把线程相关的操作进行了封装和抽象,以方便我们使用。例如,Java中的线程可以设置优先级,但如果操作系统本身不支持优先级调度策略,那么为线程设置优先级是没有任何作用的。

操作系统维护了一个任务队列,Java调用.start()之后会把任务放进队列之中等待执行,CPU不会一直执行同一个任务,而是每执行一段时间,就保存当前任务的状态,然后从队列中取到下一个任务继续执行。

总之,操作系统基于cpu时间片通过线程调度,来达到轮换执行线程对应的代码。

对阻塞及异步的概念理解

阻塞指的是进程被阻塞,即等待任务处理完成后进程才再往下走。
同步指的是资源被按顺序使用。

反向代理

正向代理:代理服务器代理的是客户端,客户端知道服务器,也知道代理服务器。正向代理服务器帮助客户端连接目的服务端。
反向代理:代理服务器代理的是服务端,客户端不知道服务器,只知道代理服务器。反向代理服务器向客户端隐藏了真实的服务端。

数据库性能优化

为什么要分库、分表、分读写?

单表的数据量限制,当单表数据量到一定条数之后数据库性能会显著下降。数据多了之后,对数据库的读、写就会很多。分库减少单台数据库的压力。 一些分库分表的系统,都是通过主键进行散列分裤分表的。这类数据比较特殊,主键就是唯一的获取该条信息的主要途径。比如:京东的订单、财付通的交易记录等。。。该类数据的用法,就是通过订单号、交易号来查询该笔订单、交易。

还有一类数据,比如用户信息,每个用户都有系统内部的一个userid,与userid对应的还有用户看到的登录名。那么如果分库分表的时候单纯通过userid进行散列分库,那么根据登录名来获取用户的信息,就无法知道该用户处于哪个数据库中。或许可以维护一个email—-userid的映射关系,根据email先查询到userid,在根据userid的分库分表规则到对应库的对应表来获取用户的记录信息。这么做是可以的,但是这个映射关系的条数本身也是个瓶颈,原则上是没有减少单表内数据的条数,算是一个单点。并且要维护这个映射关系和用户信息的一致性(修改登录名、多登录名等其他特殊需求),最大一个原因,其实用户信息是一个读大于写的库,web2.0都是以用户为中心,所有信息都和用户信息相关联,所以对用户信息拆分还是有一定局限性的。
对于这类读大于写并且数据量增加不是很明显的数据库,推荐采用读写分离+缓存的模式,试想一下一个用户注册、修改用户信息、记录用户登录时间、记录用户登录IP、修改登录密码,这些是写操作。但是以上这些操作次数都是很小的,所以整个数据库的写压力是很小的。唯一一个比较大的就是记录用户登录时间、记录用户登录IP这类信息,只要把这些经常变动的信息排除在外,那么写操作可以忽略不计。所以读写分离首要解决的就是经常变化的数据的拆分,比如:用户登录时间、记录用户登录IP。这类信息可以单独独立出来,记录在持久化类的缓存中(可靠性要求并不高,登陆时间、IP丢了就丢了,下次来了就又来了)
读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

以Oracle为例,主库负责写数据、读数据,读库仅负责读数据。每次有写库操作,同步更新cache,每次读取先读cache在读DB。写库就一个,读库可以有多个,采用dataguard来负责主库和多个读库的数据同步。

http://blog.csdn.net/kobejayandy/article/details/8775255

Spring-AOP

定义装备

定义切点

Spring中表示方式切点常用的有两种方式:1.使用正则表达式 2.使用AspectJ表达式
使用org.springframework.aop.support.JdkRegexpMethodPointcut来定义正则表达式切点

<bean id="sleepPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
 <property name="pattern" value=".*sleep"/>
</bean>

上面示例中pattern属性指定了正则表达式,它匹配所有的sleep方法

定义顾问

把通知和切点结合起来:
org.springframework.aop.support.DefaultPointcutAdvisor

<bean id="sleepHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
 <property name="advice" ref="sleepHelper"/>
 <property name="pointcut" ref="sleepPointcut"/>
</bean>

定义代理对象

<bean id="humanProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
     <property name="target" ref="human"/>
     <property name="interceptorNames" value="sleepHelperAdvisor" />
     <property name="proxyInterfaces" value="test.spring.aop.bean.Sleepable" />
</bean>

Spring还提供了一种自动代理的功能,不用显示定义代理对象,能让通知者和业务对象自动匹配,如下:

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

http://blog.csdn.net/udbnny/article/details/5870076
http://www.jb51.net/article/83173.htm

AOP概念

AOP是Aspect Oriented Programming的缩写,意思是面向切面(方面)编程。主要的功能有日志记录,性能统计,安全控制,事务处理,异常处理等,主要意图是将功能代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。AOP是其实是通过动态代理模式来实现业务逻辑的插入,使开发者在开发时不用关注其他与业务无关的点,通过代理的方式做到了插拔式操作。

AOP,OOP区别概念

  • AOP是OOP的补充
  • OOP编程将程序分解成各个层次的对象,AOP将程序运行过程分解成各个切面。
  • AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,
  • OOP是静态的抽象,AOP是动态的抽象,
  • AOP是对应用执行过程中的步骤进行抽象,从而获得步骤之间的逻辑划分。

AOP框架具有的两个特征:
1.各个步骤之间的良好隔离性
2.源代码无关性

IOC概念

IoC,(Inverse of Control)控制反转,其包含两个内容:其一是控制,其二是反转。在程序中,被调用类的选择控制权从调用它的类中移除,转交给第三方裁决。这个第三方比如Spring容器。IoC另解,依赖注入(Dependency Injection),调用类对被调用类的依赖关系由第三方注入。
IoC其实是遵循了软件设计理念的依赖倒转原则,面向对象的设计就是为了实现软件的更好的复用行和扩展性,我们就必须降低我们每个pojo的依赖关系,也就是解耦,耦合度低了,才能更好的重用和扩展。
IoC中用到了工厂模式

WebService

JAX-WS全称是JavaTM API forXML-Based WebServices
JAX-RS全称是JavaTM APIforRESTful Web Services
JAX-WS是针对WebService,JAX-RS是针对RESTful HTTP Service
这是两种风格的SOA架构风格:
JAX-WS以动词为中心,指定的是每次执行函数,大力支持的厂商如BEA,IBM,MS基本都是开发工具厂商
JAX-RS以名词为中心,每次执行的时候指的是资源,大力支持的厂商如Google,Yahoo,亚马孙等都是服务运营厂商

soap rest 区别
http://www.cnblogs.com/zhangchenglzhao/p/3728455.html

以前旧的基于方法的Web Service都是属于JAX-WS,现在较新的RESTful的Web Service则是属于JAX-RS。其中Jersey是SUN的JAX-RS的参考实现,RESTeasy则是Jboss的JAX-RS的实现。RESTful的Web Service简单来说就是将所有东西看作资源,每个资源都有一个URI,对资源的CRUD操作借助于HTTP协议的POST、GET、PUT、DELETE来实现。效率比旧的基于方法的Web Service要高。

开源WebService框架
CXF、Axis,SpringRMI

Hibernate

load与get

load(Object, Serializable):根据id查询 。查询返回的是代理对象,不会立刻访问数据库,是懒加载的。当真正去使用对象的时候才会访问数据库。
load()的时候会发现不会打印出查询语句,而使用get()的时候会打印出查询语句。
使用load()时如果在session关闭之后再查询此对象,会报异常:could not initialize proxy – no Session。处理办法:在session关闭之前初始化一下查询出来的对象:Hibernate.initialize(entity);

load()默认支持延迟加载,在用到对象中的其他属性数 据时才查询数据库,但是万一数据库中不存在该记录,只能抛异常ObjectNotFoundException;所说的load方法抛异常是指在使用该对象的数据时,数据库中不存在该数据时抛异常,而不是在创建这个对象时。由于session中的缓存对于hibernate来说是个相当廉价的资源,所以在load时会先查一下session缓存看看该id对应的对象是否存在,不存在则创建代理。
get()先在一级缓存找,没有就去二级缓存找,再没有就去数据库找,最后若没有就返回null ;而对于get方法,hibernate一定要获取到真实的数据,否则返回null。