0%

命令概览

ZooKeeper服务命令:

  1. 启动ZK服务: sh bin/zkServer.sh start
  2. 查看ZK服务状态: sh bin/zkServer.sh status
  3. 停止ZK服务: sh bin/zkServer.sh stop
  4. 重启ZK服务: sh bin/zkServer.sh restart

zk客户端命令

使用zkcli.sh -server IP:PORT 连接

  1. 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
  2. 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
  3. 创建文件,并设置初始内容: create /zk “test” 创建一个新的 znode节点“ zk ”以及与它关联的字符串,可选参数 【-e】创建临时节点,【-s】创建顺序节点,不以路径结尾时可以设置前缀
  4. 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
  5. 修改文件内容: set /zk “zkbak” 对 zk 所关联的字符串进行设置
  6. 删除文件: delete /zk 将刚才创建的 znode 删除
  7. 退出客户端: quit
  8. 帮助命令: help
  9. 获取节点权限信息:getAcl /zk
    ZooKeeper 常用四字命令:
    Read more »

WIN下zookeeper单机集群

版本:Release 3.5.1-alpha 点击下载:http://mirror.reverse.net/pub/apache/zookeeper/zookeeper-3.5.1-alpha/zookeeper-3.5.1-alpha.tar.gz

说明

zookeeper单机集群和集群类似,只不过需要修改zk数据交换端口,选举端口和客户端链接端口

一、配置zoo.cfg

将下载的文件解压,先如下配置

1
2
3
4
5
tickTime=2000
initLimit=10
syncLimit=5
dataDir=d:\\tmp\\zookeeperA
clientPort=2181

到d盘创建相应目录,到zk的bin目录下执行zkServer.cmd,先确保单机没问题(如果报错,一般是JDK安装目录带了空格,重装JDK到没有空格的目录然后修改环境变量即可),成功后关闭zk,并复制zk整个目录,复制2份。然后分别如下修改:

Read more »

第一课笔记

基础知识:

一、XML(可扩展性标记语言)

element(元素)

xml的元素指开始标签知道结束标签的部分

1
<book>this is a book</book>

上面就是一个元素,称为book。

元素之间的部分就是元素的值,比如上面的”this is a book”,有时候元素还拥有子元素,大部分的时候,xml由大量的元素,子元素组成一个树形结构

attribute(属性)

xml的属性指每个元素可以携带的额外信息

1
2
3
<book bokName="精通JAVA"  bookPrice="25.00">
this is a book
</book>

上面book元素开始标签内的bokNamebookPrice就是属性,表示book的一些附加信息,当然这些信息也可以在子元素中描述。

Read more »

一、什么是Zookeeper,作用是什么。

zookeeper是什么:

简而言之,zookeeper是java语言编写的,属于Hadoop的一个子项目,是一个开源的、高性能的、分布式的、应用协调服务。

zookeeper能干什么:

zookeeper作为hadoop的子项目,在hadoop中扮演着指挥员的作用,保证集群稳定运行,资源有序调度。

zookeeper的作用

集群管理、发布订阅

名字服务(NameService)

1
2
3
4
5
6
7
分布式应用中,通常需要一套完备的命令机制,既能产生唯一的标识,又方便人识别和记忆。 我们知道,每个ZNode都可以由其路径唯一标识,路径本身也比较简洁直观,另外ZNode上还可以存储少量数据,这些都是实现统一的 NameService的基础。下面以在HDFS中实现NameService为例,来说明实现NameService的基本布骤:
目标:通过简单的名字来访问指定的HDFS机群
定义命名规则:这里要做到简洁易记忆。
下面是一种可选的方案: [serviceScheme://][zkCluster]-[clusterName],比如hdfs://lgprc-example/表示基于 lgprc ZooKeeper集群的用来做example的HDFS集群。
配置DNS映射: 将zkCluster的标识lgprc通过DNS解析到对应的ZooKeeper集群的地址
创建ZNode: 在对应的ZooKeeper上创建/NameService/hdfs/lgprc-example结点,将HDFS的配置文件存储于该结点下
用户程序要访问hdfs://lgprc-example/的HDFS集群,首先通过DNS找到lgprc的ZooKeeper机群的地址,然后在 ZooKeeper的/NameService/hdfs/lgprc-example结点中读取到HDFS的配置,进而根据得到的配置,得到HDFS的实际访问入口

配置管理

在分布式系统中,有很多节点的配置是一样的,如果每个节点维护一个配置,当改动是需要一个一个的修改,不仅低效而且造成服务可靠性降低,通过zk可以很容易解决这样的问题,配置集中存放在zk的一个node中,所有用到此配置的节点watch此node,当启动时拉取配置,当配置修改时得到通知更新配置。

1
2
3
4
5
6
7
组员管理(Group Membership) 
在典型的Master-Slave结构的分布式系统中,Master需要作为“总管”来管理所有的Slave, 当有Slave加入,或者有Slave宕机,Master都需要感知到这个事情,然后作出对应的调整,以便不影响整个集群对外提供服务。以HBase为 例,HMaster管理了所有的RegionServer,当有新的RegionServer加入的时候,HMaster需要分配一些Region到该 RegionServer上去,让其提供服务;当有RegionServer宕机时,HMaster需要将该RegionServer之前服务的 Region都重新分配到当前正在提供服务的其它RegionServer上,以便不影响客户端的正常访问。下面是这种场景下使用ZooKeeper的基本步骤:
Master在ZooKeeper上创建/service/slaves结点,并设置对该结点的Watcher
每个Slave在启动成功后,创建唯一标识自己的临时性(Ephemeral)结点/service/slaves/${slave_id},并将自己地址(ip/port)等相关信息写入该结点
Master收到有新子结点加入的通知后,做相应的处理
如果有Slave宕机,由于它所对应的结点是临时性结点,在它的Session超时后,ZooKeeper会自动删除该结点
Master收到有子结点消失的通知,做相应的处理
Read more »

百度编辑器服务端整合

基于Spring MVC的项目中使用百度编辑器,记录备忘。

服务端代码:

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
/**
* 初始化百度编辑器,可传入其他参数生成不同的编辑器
* @param response
* @param request
*/
@RequestMapping("/ueditor/init")
public void initUeditor(HttpServletResponse response,HttpServletRequest request){
response.setContentType("application/json");
//配置路径,首先获取webpp根目录绝对路径
String rootPath = request.getSession().getServletContext().getRealPath("/");
//将config.json放到与ueditor.config.js同一级的目录下。将ueditor所有文件放入到wapapp-static-ueditor下
//设置获取服务端配置文件地址修正路径,此路径同时作用于文件上传
rootPath=rootPath+"static";
PrintWriter writer=null;
try {
String exec = new ActionEnter(request, rootPath).exec();
writer = response.getWriter();
writer.write(exec);
writer.flush();
} catch (IOException e) {
logger.error("百度编辑器初始化错误!",e);
}finally {
if(writer!=null){
writer.close();
}
}
}
Read more »

场景

有很多的数据,但是数据结构完全一致,根据数据来源存放不同的表,数据库中间件完全能做到,但代价太大。由于只是简单入库,所以使用MyBatis中的${}表达式替换表名进行入库,同时返回入库记录id。
对只使用EL (${}),同时使用ONGL(#{})以及混用做测试。jdbc链接最好指定允许多查询

allowMultiQueries=true

Read more »

本文只对MyBatis快速使用简介,想要了解更多信息,请前往MyBatis查看官方帮助文档,部分示例也来源于此。

因为新入同事对MyBatis不熟悉,所以写下这个指导,只含有基础常用的说明。基于Spring framework整合,MyBatis采用xml配置文件的方式。

Read more »

MySQL存储过程和调度简单示例

存储过程

一个简单的存储过程示例

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
44
45
46
47
48
49
50
51
52
53
54
USE test;
DROP PROCEDURE IF EXISTS sp_switch_group_trade;
-- 声明结束标记,防止遇到;就结束
DELIMITER //;
CREATE PROCEDURE sp_switch_group_trade ()
-- 作者:杨龙
-- 功能:将blog分表中的行业转换到主表中
BEGIN
-- 变量申明
DECLARE v_trade VARCHAR (20) ;
DECLARE v_id BIGINT ;
DECLARE end_flag BOOLEAN DEFAULT FALSE ;
-- 游标查询转换分表中的行业
DECLARE cur CURSOR FOR
SELECT
CASE
t.trade_id
WHEN '100100'
THEN '1'
WHEN '100101'
THEN '2'
WHEN '100102'
THEN '3'
WHEN '100103'
THEN '4'
WHEN '100104'
THEN '5'
ELSE '0'
END trade,
t.id
FROM
industry t
WHERE
t.status = '1' ;
-- 游标标记
DECLARE CONTINUE HANDLER FOR NOT FOUND SET end_flag = TRUE ;
--打开游标,开始逐行读取
OPEN cur ;
read_loop : LOOP
-- 获取游标数据
FETCH cur INTO v_trade,v_id;
-- 循环跳出判断
IF end_flag
THEN LEAVE read_loop;
END IF ;
-- 操作执行语句块
UPDATE
main_trade
SET
trade = v_trade
WHERE group_id = v_id ;
END LOOP ;
CLOSE cur ;
END ;
Read more »

关于系统重构

其实对于系统重构,首先应该分清重写重构的区别

重构:在现有基础上进行扩展整合和代码及业务流程梳理。
重写:顾明思议,重新进行一个全新系统的开发。

##为什么要进行系统重构

  1. 过于复杂的代码结构满足不了新的需求。
  2. 生产力开始受到明显的影响。
  3. 系统维护性降低。

##什么时候开始重构
引用老外的话说,当你的代码出现badsmell时就应该启动重构。

  1. 重复的代码。

    如果你在一个以上的地点看到相同的程序结构,那么可以肯定:设法将他们合二为一。

  2. 过长的函数。

    越短的函数会存活的时间更长,存活的更好。

  3. 过长的类。

    如果想利用单一的类做很多的事情,那么该类的内部会出现很多的instance变量,重复代码就要接踵而至了。

  4. 过长的参数列。

    太长的参数列难以理解,太多的参数会造成前后不一致,不易使用,一旦你需要更多的数据,就不得不修改它。

  5. 发散式变化。

    一旦我修改软件,我希望只在一处修改就好,如果不能做到这点,该坏味道就出现了。

  6. 烟雾弹式修改。

    一旦软件进行修改,你必须去对多个类的内部做小修改,该坏味道出现了。

  7. 依恋情结。

    函数对某个类的兴趣高过对自己所处之host类的兴趣,坏味道出现了。

Read more »

#Shiro在集群环境下会丢失session解决
Shiro在集群时可能会选择Redis,ehcache,membercache等作为集群缓存,存放登陆认证的信息,有时候会存在丢失session的情况,通过分析,shiro自己实现了一个session,如下

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
public class SimpleSession implements ValidatingSession, Serializable {

// Serialization reminder:
// You _MUST_ change this number if you introduce a change to this class
// that is NOT serialization backwards compatible. Serialization-compatible
// changes do not require a change to this number. If you need to generate
// a new number in this case, use the JDK's 'serialver' program to generate it.
private static final long serialVersionUID = -7125642695178165650L;

//TODO - complete JavaDoc
private transient static final Logger log = LoggerFactory.getLogger(SimpleSession.class);

protected static final long MILLIS_PER_SECOND = 1000;
protected static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
protected static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;

//serialization bitmask fields. DO NOT CHANGE THE ORDER THEY ARE DECLARED!
static int bitIndexCounter = 0;
private static final int ID_BIT_MASK = 1 << bitIndexCounter++;
private static final int START_TIMESTAMP_BIT_MASK = 1 << bitIndexCounter++;
private static final int STOP_TIMESTAMP_BIT_MASK = 1 << bitIndexCounter++;
private static final int LAST_ACCESS_TIME_BIT_MASK = 1 << bitIndexCounter++;
private static final int TIMEOUT_BIT_MASK = 1 << bitIndexCounter++;
private static final int EXPIRED_BIT_MASK = 1 << bitIndexCounter++;
private static final int HOST_BIT_MASK = 1 << bitIndexCounter++;
private static final int ATTRIBUTES_BIT_MASK = 1 << bitIndexCounter++;

private transient Serializable id;
private transient Date startTimestamp;
private transient Date stopTimestamp;
private transient Date lastAccessTime;
private transient long timeout;
private transient boolean expired;
private transient String host;
private transient Map<Object, Object> attributes;

可以看到,很多属性是transient修饰的,也就是说,当我们不使用JDK原生序列化机制时,这些属性不会被序列化,特别是源码注释也说明了这一点,而我们使用的序列化器往往考虑到性能,使用的是ASM或反射机制来实现的序列化,因而在没有是否序列化transient属性的设置时,往往默认不序列化,例如Kryo,已经是一个定死的属性,不序列化transient属性。
那么解决的方式也很简单:

  1. 使用兼容原生序列化机制的序列化器。
  2. 重新SimpleSession