#Java

hadoop 3.1.2 单机模式安装配置

Published at August 25, 2019 ·  1 min read

hadoop 3.1.2 单机模式安装配置 现在搞大数据记录一下,方便查阅。 1.安装配置jdk和下载hadoop略。 hadoop 下载地址:http://mirror.bit.edu.cn/apache/hadoop/common/ 使用了较新且保守的3.1.2版本 2.配置修改 环境变量修改 export HADOOP_HOME=/soft/hadoop export PATH=$PATH:$HADOOP_HOME/bin 配置etc/hadoop/hadoop-env.sh export JAVA_HOME=/soft/java export HADOOP_HOME=/soft/hadoop 配置etc/hadoop/core-site.xml <configuration> <property> <name>hadoop.tmp.dir</name> <value>file:///develop/data/hadoop</value> <description>Abase for other temporary directories.</description> </property> <property> <name>fs.defaultFS</name> <value>hdfs://192.168.0.104:8888</value> </property> </configuration> 配置etc/hadoop/hdfs-site.xml <configuration> <property> <name>dfs.replication</name> <value>1</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>file:///develop/data/hadoop/dfs/name</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>file:///develop/data/hadoop/dfs/data</value> </property> <property> <name>dfs.datanode.du.reserved</name> <value>1073741824</value> <description>Reserved space in bytes per volume..</description> </property> </configuration> 3.配置免密码SSH登录 ssh-keygen -t rsa cat ~/ssh/id_rsa....


讲清楚CAS的那点事

Published at July 16, 2019 ·  1 min read

互联网低潮,老是会看到别人发面试经验,看到很多人谈乐观锁,谈CAS,但是都没有说清楚。忍不住叨叨几句。 那什么是乐观锁呢,比较书面的定义是 “它假设多用户并发的事务在处理时不会彼此互相影响,各事务能够在不产生锁的情况下处理各自影响的那部分数据。在提交数据更新之前,每个事务会先检查在该事务读取数据后,有没有其他事务又修改了该数据。如果其他事务有更新的话,正在提交的事务会进行回滚。”,在多线程中则指对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突。在Java中,是通过CAS来实现乐观锁的。 CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。 更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。 CAS比较难于理解的地方就在于V、A、B这三个变量到底代表什么含义,很容易混淆,也不容易讲清楚。单纯看书上的文章会觉得晦涩,我们可以来看个例子。 举个例子: 1.在内存地址V当中,存储着值为10的变量 2.此时线程1想要把变量的值增加1。对线程1来说,旧的预期值A=10,要修改的新值B=11。 3.在线程1要提交更新之前,另一个线程2抢先一步,把内存地址V中的变量值率先更新成了11。 4.线程1开始提交更新,首先进行A和地址V的实际值比较(Compare),发现A不等于V的实际值,提交失败。 5.线程1重新获取内存地址V的当前值,并重新计算想要修改的新值。此时对线程1来说,A=11,B=12。这个重新尝试的过程被称为自旋。 6.这一次比较幸运,没有其他线程改变地址V的值。线程1进行Compare,发现A和地址V的实际值是相等的,线程1进行Swap,把地址V的值替换为B,也就是12。在这一步,Compare和Swap这个过程是原子的(由操作系统和硬件保证),比较并更新的过程是不会被其他线程打断的。 到这里,其实基本说请了CAS的过程,但是CAS的API,还是不够清晰,很多人能够进行到这里,但如果让他实际使用CAS的API时则又没辙了,这里我们通过一个例子来演示CAS的API实际用例。 /** * 使用CAS来获取单例 */ public class CasSingleton { private static final AtomicReference<CasSingleton> INSTANCE=new AtomicReference<>(); private CasSingleton(){} public static CasSingleton getInstance(){ for(;;){ CasSingleton singleton=INSTANCE.get(); if(null!=singleton){ return singleton; } singleton=new CasSingleton(); if(INSTANCE.compareAndSet(null,singleton)){ return singleton; } } } public static void main(String[] args) { CasSingleton singleton=getInstance(); CasSingleton singleton1=getInstance(); System.out.println(singleton); System.out.println(singleton1); } } 这里使用CAS来实现单例,我们对照着compareAndSet的API来看看 /** * Atomically sets the value to {@code newValue} * if the current value {@code == expectedValue}, * with memory effects as specified by {@link VarHandle#compareAndSet}....


Netty实现http服务器keep Alive无效的问题排查

Published at July 6, 2019 ·  2 min read

netty实现http服务器keep-alive无效的问题排查 今天在用netty实现一个http服务器的时候,发现keep-alive并没有生效,具体表现是在request和response的header里都能看到keep-alive的标志: request: Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Cache-Control: max-age=0 Connection: keep-alive response: HTTP/1.1 200 OK content-type: text/html;charset=UTF-8 content-length: 0 connection: keep-alive 可以看出,无论是请求还是响应,都是keep-alive的,但是请求两次,服务器端日志如下: 七月 06, 2019 9:51:27 下午 io.netty.handler.logging.LoggingHandler channelRead 信息: [id: 0xade39344, L:/0:0:0:0:0:0:0:0:8080] READ: [id: 0x26d40041, L:/0:0:0:0:0:0:0:1:8080 - R:/0:0:0:0:0:0:0:1:33130] 七月 06, 2019 9:51:27 下午 io.netty.handler.logging.LoggingHandler channelReadComplete 信息: [id: 0xade39344, L:/0:0:0:0:0:0:0:0:8080] READ COMPLETE keepAlive=true channel id=26d40041 http uri: /a.txt?name=chen&f=123;key=456 name=chen f=123 key=456 七月 06, 2019 9:51:29 下午 io....


Filebeat7自定义index的一个坑

Published at June 26, 2019 ·  2 min read

我用的filebeat7来收集日志发给Elastic search,版本是7.1.1,对应的elasticsearch版本和其相同。 默认的,filebeat生成的索引名字是filebeat-7.1.1-2019.06.24这种,不利于区分不同的业务,需要自定义索引,看了下官方文档, 是这么写的 indexedit The index name to write events to. The default is "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}" (for example, "filebeat-7.2.0-2019-06-26"). If you change this setting, you also need to configure the setup.template.name and setup.template.pattern options (see Load the Elasticsearch index template). If you are using the pre-built Kibana dashboards, you also need to set the setup.dashboards.index option (see Load the Kibana dashboards). You can set the index dynamically by using a format string to access any event field....


使用Java自动登录需要动态密码的堡垒机

Published at November 16, 2018 ·  1 min read

公司的生产服务器买了QiZhi Technologie的堡垒机,每次登录都得输入密码+空格+OTOP验证码,都得打开手机APP操作一把,烦不胜烦。 不可忍,想了想,还是借助Java在每次调用时自动生成验证码,然后搞个ssh自动登录(别问我问啥不用公钥,哪有权限啊)得了。 结合之前写的博客 TOTP算法Java版本,很容易就写出计算验证码的代码: public long getCode(String secret, long timeMsec) throws Exception { Base32 codec = new Base32(); byte[] decodedKey = codec.decode(secret); long t = (timeMsec / 1000L) / 30L; for (int i = -window_size; i <= window_size; ++i) { long hash; try { hash = verify_code(decodedKey, t + i); return hash; } catch (Exception e) { e.printStackTrace(); } } return 0L; } 写一个类,专门调用这个方法生成验证码,获取程序执行结果 java -Dfile.encoding=UTF-8 -classpath /soft/tool/authcode/ GoogleAuthTest ,接下来,要实现自动登录就简单多了,先写一个shell...


使用内嵌undertow开发调试jfinal项目

Published at May 19, 2018 ·  1 min read

今天在修一个老项目,使用的是jfinal框架,这个框架算是一个比较传统的框架,只支持打包成war运行放入容器中运行,但是在开发过程中可以使用jetty快速启动和调试。个人不是很喜欢jetty,遂换成了undertow。 引入如下依赖 <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-core</artifactId> <version>2.0.1.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>io.undertow</groupId> <artifactId>undertow-servlet</artifactId> <version>2.0.1.Final</version> <scope>provided</scope> </dependency> 再写一个启动类就好了 public class Main { public static void main(String[] args) throws Exception { DeploymentInfo servletBuilder = Servlets.deployment() .setContextPath("/") .setClassLoader(Main.class.getClassLoader()) .setDeploymentName("zooadmin.war") ; FilterInfo jfinalFilter=new FilterInfo("jfinal",JFinalFilter.class); jfinalFilter.addInitParam("configClass","com.baicai.core.Config"); servletBuilder.addFilter(jfinalFilter); servletBuilder.addFilterUrlMapping("jfinal","/*", DispatcherType.REQUEST); servletBuilder.addFilterUrlMapping("jfinal","/*", DispatcherType.FORWARD); servletBuilder.setResourceManager(new FileResourceManager(new File("src/main/webapp"), 1024)); DeploymentManager manager = Servlets.defaultContainer().addDeployment(servletBuilder); manager.deploy(); PathHandler path = Handlers.path(Handlers.redirect("/")) .addPrefixPath("/", manager.start()); Undertow server = Undertow.builder() .addHttpListener(1080, "localhost") .setHandler(path) .build(); // start server server....


Java里常见的几个语法小坑

Published at May 5, 2018 ·  2 min read

很久没更新博客了,想到几个小坑,虽然没啥技术含量,但或许有人不知道呢。 1.删除sublist的元素导致原对象元素被删除 看下面这段代码 List<Integer> students=new ArrayList<Integer>(); for (int i = 0; i <5 ; i++) { students.add(i); } List<Integer> subList=new ArrayList<Integer>(); subList=students.subList(0,5); subList.remove(0); subList.remove(1); for (int i = 0; i <5 ; i++) { System.out.println(i+"="+students.get(i)); } students是个list,然后我们新建立了一个subList对象,这个对象截取了students的一部分,我们删除了subList对象里的一些元素,看下运行结果。 0=1 1=3 2=4 Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 3, Size: 3 at java.util.ArrayList.rangeCheck(ArrayList.java:657) at java.util.ArrayList.get(ArrayList.java:433) at bai.ListDo.main(ListDo.java:17) 难道说,删除subList对象里的元素也会导致students里的元素被删除?我明明是新建了一个对象啊。然而,事实确实是这样的。 我们要理解一个事情,使用new新建一个对象,只是开辟了一块空间,用来存放这个对象的地址指针,但是这个新建的对象地址,指向的却是原有对象,也就是说,使用subList这个方法的时候,并没有从students里把内容拷贝了一份,仅仅是纪录了一个指针的移动,这样从某种角度来说,是提高了性能节省内存的做法。 看一下subList这个方法的JavaDoc我们就更清楚了。 Returns a view of the portion of this list between the specified * <tt>fromIndex</tt>, inclusive, and <tt>toIndex</tt>, exclusive....


折腾阿里云OSS的API

Published at January 25, 2018 ·  2 min read

这两天想给博客做个插件,利用阿里云的OSS来存储文件.但阿里的文档和代码都烂的超乎想象,要么代码老旧不堪,要么跟小脚老太一样引入一坨依赖,想必这块是外包团队做的吧,或者阿里非核心业务员的技术水平也就这样吧.  所以想绕开阿里云官方提供的代码自己整一套OSS的API,先跑一个上传文件的demo,能在客户端跑通后再用代码去实现.最简单的方法就是用REST client来模拟.折腾了一下,还挺费劲,记录下折腾过程  先来试试上传文件,选择PUT方法,要请求的URL为http://baicaidoc.oss-cn-shenzhen.aliyuncs.com/image/small/mm1.jpg ,添加以下header,header头需要包含哪些内容可以看这里 Authorization:OSS LTAIxkX6Qj2OuMZ6:tLZ7nYYP/hkCJbG/6gkOJ7Mi4E= Date:Thu, 25 Jan 2018 15:20:39 GMT Content-Disposition:attachment;filename=ivy.jpg Host:baicaidoc.oss-cn-shenzhen.aliyuncs.com Content-Encoding:utf-8 然后在body里添加file body. 至于header头怎么写和Authorization字段计算的方法,文档里说的比较清晰了https://help.aliyun.com/document_detail/31951.html. 尤其需要注意的是Date必须是GMT格式,这个对Java来说也好办,不过要注意时区的问题,GMT时间比东八区慢了8个小时.还有Host需要带上bucket,这在早期是不需要的(早期带上反而会报错SignatureDoesNotMatch) 另外就是这个Authorization字段的签名需要注意,base64需要处理byte[]数组,而不是字符串.所以用网上的在线验证工具是验证不了的. Java版的签名代码如下: import bai.tool.Base64; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; /** * Hello world! * */ public class App { public static byte[] hamcsha1(byte[] data, byte[] key) { try { SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(signingKey); return mac.doFinal(data); } catch (NoSuchAlgorithmException e) { e....


FireJava输出Java服务器端调试日志到控制台

Published at January 10, 2018 ·  1 min read

针对最新火狐浏览器50+以上版本的firebug协议,类似FirePHP,但是FirePHP已经很久不更新,并且对最新的浏览器也已失效。 > 这个在Firebug之上运行的扩展,结合一个服务器端的库,就可以让你的PHP代码向浏览器发送调试信息,该信息以HTTP响应头(HTTP headers)的方式编码。经过设置,你可以像在Firebug控制台调试JavaScript代码一样得到PHP脚本的警告和错误提示。下面我们来看看具体步骤。 直接上代码 import com.alibaba.fastjson.JSON; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Objects; /** * @version V1.0 * @Description:直接输出服务器端调试日志到控制台,简易版本。 * @date 2017/6/13 16:51 */ public class DebugTool { public final String VERSION = "2.0.j1"; public final String HEADER_NAME = "X-ChromeLogger-Data"; protected Map<String, Object> console = new HashMap<>(); private String response=""; public DebugTool() { console.put("version", VERSION); console.put("columns", new String[]{"log", "backtrace", "type"}); console.put("rows", new ArrayList<Objects>()); console.put("request_uri", this.getClass().getName()); } public DebugTool(Class cls) { this(); console....


TOTP算法Java版本

Published at January 8, 2018 ·  6 min read

TOTP 概念 TOTP - Time-based One-time Password Algorithm is an extension of the HMAC-based One Time Password algorithm HOTP to support a time based moving factor. TOTP(基于时间的一次性密码算法)是支持时间作为动态因素基于HMAC一次性密码算法的扩展。它是OTP算法的一种 算法如下: TOTP = Truncate(HMAC-SHA-1(K, (T - T0) / X)) K 共享密钥 T 时间 T0 开始计数的时间步长 X 时间步长 代码实现 最简实现需要如下两个类 1.Base32.java public class Base32 { private static final char[] ALPHABET = { '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', '2', '3', '4', '5', '6', '7' }; private static final byte[] DECODE_TABLE; static { DECODE_TABLE = new byte[128]; for (int i = 0; i < DECODE_TABLE....