-
Notifications
You must be signed in to change notification settings - Fork 134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
踩过的那些技术坑 #21
Comments
开源软件: RocksDB @Override
public boolean hasNext() {
return iterator.isValid();
}
@Override
public byte[] next() {
iterator.next();
return iterator.key();
} 解决办法: 无责任吐槽: |
开源软件: JDK/java.nio.channels 包 public static void main(String[] args) throws Exception {
Selector selector = Selector.open();
System.out.println("step 1");
new Thread(() -> {
try {
System.out.println("step 2");
selector.select(3000);
System.out.println("step 3");
} catch (Exception e) {
}
}).start();
Thread.sleep(1000);
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_CONNECT); // 直到select结束时才会被执行
System.out.println("step 4");
} 这是因为执行 Selector.select 的线程阻塞了,主线程执行到 SelectableChannel.register 时也会被阻塞, private int lockAndDoSelect(long timeout) throws IOException {
synchronized (this) {
if (!isOpen())
throw new ClosedSelectorException();
synchronized (publicKeys) {
synchronized (publicSelectedKeys) {
return doSelect(timeout);
}
}
}
} 最关键的是 synchronized (publicKeys) 这一行,占有了publicKeys 相关的锁后,执行 doSelect 的过程中就算线程被阻塞了,线程占用的锁依然没有释放。当主线程执行到 SelectableChannel.register 时会调用到 sun.nio.ch.SelectorImpl.register(AbstractSelectableChannel, int, Object) 它的代码如下: protected final SelectionKey register(AbstractSelectableChannel ch,
int ops,
Object attachment)
{
if (!(ch instanceof SelChImpl))
throw new IllegalSelectorException();
SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
k.attach(attachment);
synchronized (publicKeys) {
implRegister(k);
}
k.interestOps(ops);
return k;
} 最关键的也是 synchronized (publicKeys) ,主线程因为无法获得 publicKeys 相关的锁所以就卡在那里了,直到执行 Selector.select 的线程超时为止。 解决办法: 无责任吐槽: |
刚刚又踩了 NIO 的一个坑,排查了快两小时,找了各种原因才发现服务器端收到的字节数总是少于客户端要发送的,结果是因为调用了 java.nio.channels.SocketChannel.write 方法时,只是简单的channel.write(ByteBuffer) 了,这样调用可能只写了部分数据,要像这样用: while (buffer.hasRemaining())
channel.write(buffer); 为什么要这样设计?我都给你传一个ByteBuffer了,里面有pos,有limit,要写多少数据不会自己算吗?! |
沉没好久了 |
做 Java 开发,是否有必要用 NIO 实现自己的网络客户端或网络服务器? 简而言之,99%以上的场景都是没必要的。用 NIO 实现一个成熟稳定的高性能的网络应用程序是一件很繁琐很容易出错的事,Java 开源社区已经有像 Apache MINA 、Netty 和 Vert.x 这样的网络框架或工具库了,直接拿了用就好了。 在 Lealone-Plugins 的网络层插件中就包含对 MINA、Netty 和 Vertx 的支持,不过我最近倒是心血来潮自己用 NIO 实现了一个用于 Lealone 数据库的网络客户端和网络服务器。 之所以自己造了一个,是因为我在开发 Lealone 的过程中常常要快速启动一些测试程序,启动速度大于 1.5 秒就无法忍受了,Vertx 的启动速度最慢,在我的机器上经常要 3 秒左右,Netty 要两秒多,MINA 要接近两秒,为什么慢,这两个代码例子中的注释给出了一些原因: Netty例子 、Vertx例子 当然,用 NIO 开发程序时,除了上面说到的,还有挺多的,今天在做性能测试时,又对一个非常诡异的问题排查了大半天,发现是 NIO、协议、多线程并发同时引起的终极难搞问题,最后只需要调整两三行代码的顺序!!! 代码在此 最后,Lealone 启动速度是快了,小于1秒,总算是个安慰!:) |
NIO太多坑了. |
排查 drill 1.15.0 和 hadoop 2.7.4 问题的一个案例: 在windows7下,最初跑drill的测试用例时一开始就报这个错但是没理: Area [xxxxxx] must be writable and executable for application user 今天我下了drill的分发包来跑,执行sqlline.bat时又报这个错,我仔细看了看xxxxxx目录的权限都是可写可执行的呀为啥还报错。 还好UserGroupInformation.getLoginUser()允许通过设置环境变量HADOOP_PROXY_USER来指定代理用户名,把它设成Administrators就解决了。 之所以fileStatus.getOwner()返回Administrators,我跟踪了代码,发现在org.apache.hadoop.fs.RawLocalFileSystem.DeprecatedRawLocalFileStatus.loadPermissionInfo() 里面它用了winutils.exe ls -F xxxxxx命令得到了一个"drwx------|1|BUILTIN\Administrators..."这样的字符串,然后Owner就变成了Administrators,也就是它取了管理员用户组去了。 |
此贴记录日常工作中踩过的技术坑
The text was updated successfully, but these errors were encountered: