hbase配置

  1. 下载并解压hbase(我使用的是hbase-1.2.4)
  2. 编辑hbase-1.2.4/conf/hbase-env.sh,添加JAVA_HOME配置:

    1
    export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home
  3. 编辑hbase-site.xml:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <configuration>
    <property>
    <name>hbase.rootdir</name>
    <value>file:///Users/tangliu/Tmp/hbase</value>
    </property>
    <property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/Users/tangliu/Tmp/zookeeper</value>
    </property>
    </configuration>

    分别表示数据和zookeeper数据存放地点。这样配置是本地单实例模式启动,具体和集群配置可以参考hbase官网。

  4. ./hbase-1.2.4/bin/start-hbase.sh启动
  5. ./hbase-1.2.4/bin/hbase shell hbase-create.hbase这是初始化pinpoint需要的表
  6. 验证页面:http://localhost:16010/master-status

配置pinpoint-collector

  1. 解压pinpoint-collector-1.6.1-SNAPSHOT.war包到tomcat-collector/webapps/ROOT/

    1
    unzip pinpoint-collector-1.6.1-SNAPSHOT.war -d ……./tomcat-collector/webapps/ROOT/
  2. 配置ROOT/WEB-INF/classes/hbase.properties:

    1
    2
    hbase.client.host=localhost
    hbase.client.port=2181

    指向zookeeper即可

  3. 配置tomcat-collector/conf/server.xml:

    1
    2
    3
    <Server port="8005" shutdown="SHUTDOWN">
    <Connector port="8088" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
    <!--<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->
  4. 启动tomcat

阅读全文

之前做文档站点的时候有一个需求,做一个在线部署页面,能够通过页面上点点点就自动部署远程服务器上的服务,并且看到部署日志。简单的思路就是,页面通过websocket连接到java后台,java代码调用shell脚本执行发布操作,获取输出,并通过websocket将输出内容返回页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Runtime runtime = Runtime.getRuntime();
Process process;
BufferedReader br = null;
BufferedWriter wr = null;
try {
process = runtime.exec("//要执行的命令");

br = new BufferedReader(new InputStreamReader(process.getInputStream()));
wr = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));

String inline;
while ((inline = br.readLine()) != null) {
if (!inline.equals("")) {
inline = inline.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
session.getBasicRemote().sendText(inline); //返回给页面
if (inline.endsWith("发布到服务器?[Y/N]:")) {
wr.write("y"); //自动输入y
wr.newLine();
wr.flush();
session.getBasicRemote().sendText("y");
}
} else {
session.getBasicRemote().sendText("\n"); //换行
}
}
br.close();
br = new BufferedReader(new InputStreamReader(process.getErrorStream())); //错误信息
while ((inline = br.readLine()) != null) {
if (!inline.equals(""))
session.getBasicRemote().sendText("<font color='red'>" + inline + "</font>");
else
session.getBasicRemote().sendText("\n");
}
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
session.getBasicRemote().sendText("<font color='red'>" + e.getMessage() + "</font>");
} finally {
if (br != null)
br.close();
if (wr != null)
wr.close();
session.getBasicRemote().sendText("End.");
}

安装shadowsocks
  1. 使用root登陆,下载和运行一键安装脚本

    1
    2
    3
    wget --no-check-certificate https://raw.githubusercontent.com/teddysun/shadowsocks_install/master/shadowsocks.sh
    chmod +x shadowsocks.sh
    ./shadowsocks.sh 2>&1 | tee shadowsocks.log
  2. 按提示修改端口和密码

    • 配置地址:/etc/shadowsocks.json
    • 启动:/etc/init.d/shadowsocks start
    • 停止:/etc/init.d/shadowsocks stop
    • 重启:/etc/init.d/shadowsocks restart
    • 状态:/etc/init.d/shadowsocks status
    • 卸载:./shadowsocks.sh uninstall
  3. 默认开机启动
修改ssh端口
  1. 修改/etc/ssh/sshd_config文件,将Port修改为自己想要的端口
  2. systemctl restart sshd.service 重启服务
  3. netstat -tulnp|grep sshd 查看端口
安装git

yum install git

安装nginx
1
2
yum -y install epel-release
yum install nginx

背景描述

自定义了一个注解:

1
2
3
4
5
6
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface ScheduledTask {
}

在一个实现类上添加此注解:

1
2
@ScheduledTask
public class TimerTaskServiceImpl implements TimeTaskService {

在代码中期望通过判断是否包含注解来执行操作:

1
2
if(bean.getClass().isAnnotationPresent(ScheduledTask.class)){
...

本来一切运行正常。但是,当我试图在实现类上添加事务注解@Transactional后,这里的判断就一直是false。调试发现,当跑到这一行代码时,bean不是实现类,而是一个Proxy代理类(JdkDynamicAopProxy),所以自定义的注解一直获取不到。搜索之后,才知道这是spring的事务管理对添加了@Transactional注解的类做了其他操作,我们获取到的是一个处理后的代理类。

阅读全文

背景

为了提高系统的健壮性,我们常常做出多节点负载均衡的设计,通过zookeeper注册和发现可用服务,调用端通过一定的负载均衡策略决定请求哪一个可用服务节点。

然后,在某些情况下,服务的调用并非由客户端发起,而是由这个服务自身发起。比如,一个服务可能存在一些定时任务,每分钟去操作一下数据库之类的。当系统只有一个容器时,不用考虑主从的问题,只管到时间了就执行。但如果系统是分布式的,一个服务可能同时运行在多个容器中,查询类的定时任务没有影响,但是某些定时任务每次只需要执行一次,没有区分主从的情况下,每个容器下的服务都会企图去执行,很可能会造成不可预料的结果。

所以,我们需要达到的目标是,服务能够判断自己是否是Master,如果是,则执行,如果不是,则不执行。同时,如果Master服务掉线(比如宕机了),那么某个容器里的slave服务能够自动升级为Master,并执行Master执行的任务。

基础

  • Zookeeper客户端可以创建临时节点并保持长连接,当客户端断开连接时,临时节点会被删除
  • Zookeeper客户端可以监听节点变化

实现

  1. 定义一个持久化节点/gzcb/master/services,此节点下的子节点为临时节点,分别代表不同的Master服务
  2. Container_1中的服务AccountService,在启动时,在zookeeper中创建临时节点/gzcb/master/services/AccountService:1.0.0,节点的数据为192.168.99.100:9090。这代表,192.168.99.100:9090这个容器中的AccountService(版本为1.0.0)成功竞选为Master服务。Container_1中维护一个缓存,如果竞选成功,对应service:version置为true,否则置为false;
  3. Container_2中的服务AccountService,在启动时,也试图创建临时节点/gzcb/master/services/AccountService:1.0.0,但是会创建失败,返回结果码显示该节点已经存在。所以服务就知道已经有一个Master的AccountService(1.0.0)存在,它竞选失败。
  4. Container_2会保持对该临时节点的监听,如果监听到该零时节点被删除,则试图再次创建(创建临时节点的过程就是竞选master的过程),创建成功,则更新缓存对应service:version为true,否则继续保持监听。

优化

不管竞选成功还是失败,可以维护一份Master缓存信息,并保持监听,实时更新。这样,不仅能够自动竞选master,还能够通过修改临时节点数据的方式,手动指定Master。

关键代码

阅读全文

最近在做一个工具包的时候,有这么一种需求:在运行main函数时,需要将resources资源文件夹下的xml子文件夹中的文件加载。原本可以使用Main.class.getClassLoader().getResoruceAsStream()将文件一一加载,但是xml子文件夹中的文件非常多,不可能一个个列文件名。所以最初我的写法是:

1
2
3
4
5
6
File parent = new File(ClassLoader.getSystemClassLoader().getResource("").getPath() + "/xml");
File[] files = parent.listFiles();
for (int i = 0; i < xmlFiles.length; i++) {
File xmlFile = xmlFiles[i];
//...
}

在IDE中运行并没有问题,能够正常得读取到资源文件夹和文件。但是当我使用maven将工程打成jar包,试图使用命令行启动时,跑到这里就会抛空指针异常了。不断的测试和查资料,终于明白,当打成一个jar包后,整个jar包是一个文件,只能使用流的方式读取资源,这时候就不能通过File来操作资源了,得通过getResourceAsStream来读取文件内容并操作。在IDE中之所以能正常运行,是因为IDE中的资源文件在target/classes目录下,是正常的文件系统结构。

然而问题来了,我不是读一个文件,而是试图读取一个文件夹,依次读取文件夹下所有文件资源。我试图按照网上的说法,读取资源,然后创建一个临时文件,在操作该临时文件,例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
File file = null;
URL res = PostHelper.class.getClassLoader().getResource("xml/");
if (res.toString().startsWith("jar:")) {
try {
InputStream input = PostHelper.class.getClassLoader().getResourceAsStream("xml/");
file = File.createTempFile("tempfile", ".tmp");
OutputStream out = new FileOutputStream(file);
int read;
byte[] bytes = new byte[1024];
while ((read = input.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
file.deleteOnExit();
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
file = new File(res.getFile());
}

阅读全文