小议服务器命名

这个问题其实不能称之为问题,给服务器命名应该算是一个常识性问题,任何人都可以想到的,其实不仅是服务器,在我们生活中的一切都有名字,如果我们生活在一个没有名字的世界中,你想想有多可怕把?但为什么写这篇文章呢?因为我们公司很奇怪,不知道是运维疏忽还是啥,每次通过跳板机登陆线上服务器,必须通过 IP 地址才行,所以每个人一定要记录自己负责的服务器的 IP 地址才可以,否则一筹莫展,但是 IP 地址,大家都懂得,不然也不会有域名的存在了,大家都通过 IP 访问互联网就好了,前几天看公众号,刚好看到知书堂有位老师写过一篇文章来说这个问题,所以转载过来,供大家给服务器命名参考,后续也会给出我自己的小建议。原文如下: 这个问题太简单,以致于提起来,很多人忽略掉了。今天给大家秀一下这几年见到的命名情况,供大家赏玩。 这里面没有最好,但有最差。我们按命名满分 5分来打分。 第一位:无敌的localhost 提起这个大家不会陌生,REHL 系例安装默认的名字就是:localhost 很多学习环境里都是: localhost 很多测试环境里也是: localhost 几十台上线机器所是: localhost 爷,你真的无敌了。 不举例子了。使用这个命名的。只能说 I 服了 YOU,你离误操作也不远了。 命名评分:0 分。显然没毕业,建议学习去。 第二名:业务 + 编号 使用业务命加编号,如:user01、user02、。。。 命名评分:3 分。属于有规模管理想法,会减少一些误操作。全局管理上还有一定的局限性 第三名:业务 + 角色 + 编号 如:core-master-1、core-master-2、core-slave-1、core-slave-2 非常直观,但对于机器好象不能允许随便切来切去,只能在几台机器里面切换了。在传统企业或是中小企业里,这种命名结构见的比较多。 命名评分:3分。中小规模命名规则,不适合自动化环境。 第四名:工程派命名 先分测试库uat-业务名-编号、预上线库puat-业务名-编号、生产库prod-业务名-编号 这个命名有点Oracle教课书的感觉,估计系统里分区也是/u01之类的。 评份:4 分+ ,多给一分怕骄傲。就这样吧。 第五名:有规范的命名 机器的命名,原业务名 + IP(点用下划线替代)+ 机房简写,如:userdb_192_168_11_100_cs prod.系统类型.机房.ip,如:prod.v.cs.192.168.11.100 其中V表示虚机。 机房+IP,如:cs19216811100 使用IP地址做服务器的命名,有多个IP使用重要的IP命名。 在终端提示上也可以显示IP提示,这一块形式也比较多。 评分:5分。推荐 整体上来说这种命名结构属于比较严禁的结构,从命名上基本很容易判断这台机器是做什么的。 其它 Tips: 机器命名,其实没有好坏之分,原则上让在CMDB及监控系统里容易标识出来即可。 对于登录系统,也可以考虑利用/etc/motd 把该机器上跑的业务显示出来。 同时可以利用登录执行相关文件如:/etc/profile 把系统里的关键东西显示出来,如:当前该机器运行几个MySQL,端口号是什么、当前内存使用情况、当前磁盘使用情况 原文完 对于上面知书堂老师给出的命名方案最后一种,也是他认为最好的,但是我个人还是感觉有一些问题,例如首先从这台机器看不出是属于哪个团队的,这对于有多个团队的公司来说,不方便,也看不出角色等等,而对于 IP 地址很多时候我个人是不关心的,我只需要能登录到这台机器,并且无论研发运维都很好记即可,如果我已经连 IP 地址都记得了,那么我还记其他的干嘛,直接用 IP 登陆不就好了吗? ...

February 24, 2019 · 1 min · 106 words · Bridge Li

MySQL sort 分页重复数据(转载)

前两天在写一个东西的时候,测试的同学说发现一个问题,排序分页,第二页和第一页有重复数据,当时我看了一下,确实有这个问题,然后就想到几年前我就曾经遇到过这个问题,淘宝数据库内核月报上也做了说明,所以这个时候就体现出了老程序员的价值:踩过的坑多,坑坑相连也就都成了平地,考虑到很多人不知道这个问题,所以把原文转载过来,以期能够让更多的人看到,原文如下: 背景 6.5 号,小编在 Aliyun 的论坛中发现一位开发者提的一个问题,说 RDS 发现了一个超级大 BUG,吓的小编一身冷汗 = =!! 赶紧来看看,背景是一个 RDS 用户创建了一张表,在一个都是 NULL 值的非索引字段上进行了排序并分页,用户发现第二页和第一页的数据有重复,然后以为是 NULL 值的问题,把这个字段都更新成相同的值,发现问题照旧。详细的信息可以登录阿里云的官方论坛查看。 小编进行了尝试,确实如此,并且 5.5 的版本和 5.6 的版本行为不一致,所以,必须要查明原因。 原因调查 在 MySQL 5.6 的版本上,优化器在遇到 order by limit 语句的时候,做了一个优化,即使用了 priority queue。参考伪代码: while (get_next_sortkey()) { if (using priority queue) push sort key into queue else { if (no free space in sort_keys buffers) { sort sort_keys buffer; dump sorted sequence to ‘tempfile’; dump BUFFPEK describing sequence location into ‘buffpek_pointers’; } put sort key into ‘sort_keys’; } } if (sort_keys has some elements && dumped at least once) sort-dump-dump as above; else don’t sort, leave sort_keys array to be sorted by caller 使用 priority queue 的目的,就是在不能使用索引有序性的时候,如果要排序,并且使用了limit n,那么只需要在排序的过程中,保留 n 条记录即可,这样虽然不能解决所有记录都需要排序的开销,但是只需要 sort buffer 少量的内存就可以完成排序。 之所以 5.6 出现了第二页数据重复的问题,是因为 priority queue 使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。 5.5 没有这个优化,所以也就不会出现这个问题。 ...

January 26, 2019 · 1 min · 197 words · Bridge Li

Maven 打包 Excel 文件损坏

前几天在项目中遇到一个小问题,有一个 Excel 文件放在 classpath 下,通过流下载下来,本地测试的时候一点问题都没,但是部署到测试环境却不行了,说文件已损坏,然后打不开,简单代码如下: @RequestMapping(value = "/export", method = RequestMethod.GET) public void export(HttpServletResponse response) { ServletOutputStream servletOutputStream = null; String filename = "template.xlsx"; InputStream inputStream = ExcelHandleController.class.getClassLoader().getResourceAsStream(filename); try { byte[] b = new byte[inputStream.available()]; inputStream.read(b); response.setCharacterEncoding(StandardCharsets.UTF_8.name()); response.setHeader("Content-Disposition", "attachment;filename=" + filename); response.setContentType("application/octet-stream;charset=UTF-8"); //获取响应报文输出流对象 servletOutputStream = response.getOutputStream(); //输出 servletOutputStream.write(b); } catch (IOException e) { logger.error("文件下载出错", e); } finally { if (null != inputStream) { try { inputStream.close(); } catch (IOException e) { logger.error("文件下载出错", e); } } if (null != servletOutputStream) { try { servletOutputStream.flush(); servletOutputStream.close(); } catch (IOException e) { logger.error("文件下载出错", e); } } } } 当时就感觉这代码很简单啊,没什么问题的,但是下载下来就是不对,想到是不是测试环境有什么问题,查了一下没什么特殊之处,最后发现 Git 上的代码中的文件并没有什么问题,但是打成 war 包解压之后这文件本身就已经损坏了,而且比对了一下两个文件,发现 war 包之中的文件变大了,搜了一下资料,才知道原来 maven 打包会对一些文件转码,这个过程中会损坏一些文件,所以打不开,网上的资料也挺多,最简单的就是增加一个 plugin,不让该文件转码,代码如下: ...

January 13, 2019 · 2 min · 227 words · Bridge Li

Java 学习之路

前几天刷微博,看到博主 @Java大本营 发了一个图片,总结 Java 一些常见的知识点,感觉挺好,整理成文字版,发在我的个人博客,作为一个大家学习复习的文档,也欢迎有人在评论中留下各种参考资料,一下是正文。 一、基础篇 JVM ①. JVM 内存结构 堆、栈、方法区、直接内存、堆和栈的区别 ②. Java 内存模型 内存可见性、重排序、顺序一致性、volatile、锁、final ③. 垃圾回收 内存分配策略、垃圾收集器(G1)、GC 算法、GC 参数、对象存活的判定 ④. JVM 参数及调优 ⑤. Java 对象模型 oop-klass、对象头 ⑥. HotSpot 即时编译器、编译优化 ⑦. 类加载机制 ClassLoader、类加载过程、双亲委派(破坏双亲委派)、模块化(jboss、modules、osgl、jigsaw) ⑧. 虚拟机性能监控与故障处理工具 jps、jstack、jmap、jstat、jconsole、jinfo、jhat、javap、btrace、tprofiler 编译与反编译 javac、javap、jad、CRF Java 基础知识 ①. 阅读源代码 String、Integer、Long、Enum、BigDecimal、ThreadLocal、ClassLoader & URLClassLoader、ArrayList & LinkedList、HashMap & LinkedHashMap & TreeMap & ConcurrentHashMap、HashSet & LinkedHashSet & TreeSet ②. Java 中各种变量的类型 ③. 熟悉 Java String 的使用,熟悉 String 的各种函数 JDK 6 和 JDK 7 中 substring 的原理及区别、replaceFirst、replaceAll、replace 的区别、String 对 “+” 的重载、String.valueOf 和 Integer.toString 的区别、字符串的不可变性 ...

December 31, 2018 · 4 min · 717 words · Bridge Li

使用 Spring AOP 注意事项

说实话,由于我个人某些基础不是很牢固,所以前一段时间关于 Spring Aop 踩了一个坑,其实很简单,今天就记录一下,先说结论: 不能被 Spring AOP 增强的方法: 基于接口的动态代理:除 public 外的其它所有的方法,此外 public static 也不能被增强 基于 CGLib 的动态代理:private、static、final 的方法,也就是只有 public 和 protected 可以,但是要注意切入点语法的配置 测试用例如下,pom 文件: <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.11.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.11.RELEASE</version> </dependency> 配置文件就比较简单了: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <context:annotation-config/> <context:component-scan base-package="cn.bridgeli"/> <aop:aspectj-autoproxy/> </beans> 切面类: package cn.bridgeli.demo.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect @Component public class LogInterceptor { // @Pointcut("execution(\* \* com.bjsxt.service..*.add(..))") @Pointcut("execution(\* cn.bridgeli.demo.service..\*.*(..))") public void myMethod() { } @Before("myMethod()") public void before() { System.out.println("method before"); } @Around("myMethod()") public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable { System.out.println("method around start"); pjp.proceed(); System.out.println("method around end"); } } 测试类: ...

November 25, 2018 · 2 min · 279 words · Bridge Li

【转载】Redis 分布式锁进化史

按:系统架构经过多年演进,现在越来越多的系统采用微服务架构,而说到微服务架构必然牵涉到分布式,以前单体应用加锁是很简单的,但现在分布式系统下加锁就比较难了,我之前曾简单写过一篇文章,关于分布式锁的实现,但有一次发现实现的分布式锁是有问题的,因为出问题的概率很低,所以当时也没在意,前几天和朋友聊这个问题,想起来看过一篇文章,写的不错,今天特转载过来,希望能让更多的人看到,同时也加深一下记忆。原文链接是:http://tech.dianwoda.com/2018/04/11/redisfen-bu-shi-suo-jin-hua-shi/ 以下为原文: 近两年来微服务变得越来越热门,越来越多的应用部署在分布式环境中,在分布式环境中,数据一致性是一直以来需要关注并且去解决的问题,分布式锁也就成为了一种广泛使用的技术,常用的分布式实现方式为Redis,Zookeeper,其中基于Redis的分布式锁的使用更加广泛。 但是在工作和网络上看到过各个版本的Redis分布式锁实现,每种实现都有一些不严谨的地方,甚至有可能是错误的实现,包括在代码中,如果不能正确的使用分布式锁,可能造成严重的生产环境故障,本文主要对目前遇到的各种分布式锁以及其缺陷做了一个整理,并对如何选择合适的Redis分布式锁给出建议。 一. 各个版本的Redis分布式锁 V1.0 tryLock() { SETNX Key 1 EXPIRE Key Seconds } release() { DELETE Key } 这个版本应该是最简单的版本,也是出现频率很高的一个版本,首先给锁加一个过期时间操作是为了避免应用在服务重启或者异常导致锁无法释放后,不会出现锁一直无法被释放的情况。 这个方案的一个问题在于每次提交一个Redis请求,如果执行完第一条命令后应用异常或者重启,锁将无法过期,一种改善方案就是使用Lua脚本(包含SETNX和EXPIRE两条命令),但是如果Redis仅执行了一条命令后crash或者发生主从切换,依然会出现锁没有过期时间,最终导致无法释放。 另外一个问题在于,很多同学在释放分布式锁的过程中,无论锁是否获取成功,都在finally中释放锁,这样是一个锁的错误使用,这个问题将在后续的V3.0版本中解决。 针对锁无法释放问题的一个解决方案基于GETSET命令来实现 V1.1 基于GETSET tryLock() { NewExpireTime = CurrentTimestamp + ExpireSeconds if (SETNX Key NewExpireTime Seconds) { oldExpireTime = GET(Key) if (oldExpireTime < CurrentTimestamp) { NewExpireTime = CurrentTimestamp+ExpireSeconds CurrentExpireTime = GETSET(Key,NewExpireTime) if (CurrentExpireTime == oldExpireTime) { return 1; } else { return 0; } } } } release() { DELETE key } 思路: ...

October 14, 2018 · 1 min · 212 words · Bridge Li

【转载】设计 RPC 接口时,你有考虑过这些吗?

按:系统架构经过多年演进,现在越来越多的系统采用微服务架构,而微服务架构最重要的就是面向接口编程,所以接口的设计就尤为重要了,我一直认为一个好的接口自己会说话,也就是看到接口,我就知道这个接口是干啥的、参数是啥、返回值是啥以及可能会遇到哪些问题,但目前对 RPC 接口设计可以说有两派,前一段时间看了一篇文章是我的想法完全一样,特转载到本人博客,希望更多的能够看到、有更多的人参与讨论两种的优劣。 在开始之前呢,先吐槽一个本文没有提到的问题,我不知道有些人是怎么想的,对外暴露的接口,也就是最终被打成 jar 包供外部服务依赖模块,有些人喜欢在里面引入各种无关的第三方依赖,我遇到过把 spring mvc、spring、mybatis、dubbo 等等还有其他的像 POI 什么乱七八糟的第三方 jar 都依赖进来的,说实话,我只想问:可以说脏话吗?不可以啊,那好吧,我无话可说了,我们开始看原文吧。 RPC 框架的讨论一直是各个技术交流群中的热点话题,阿里的 dubbo,新浪微博的 motan,谷歌的 grpc,以及不久前蚂蚁金服开源的 sofa,都是比较出名的 RPC 框架。RPC 框架,或者一部分人习惯称之为服务治理框架,更多的讨论是存在于其技术架构,比如 RPC 的实现原理,RPC 各个分层的意义,具体 RPC 框架的源码分析…但却并没有太多话题和“如何设计 RPC 接口”这样的业务架构相关。 可能很多小公司程序员还是比较关心这个问题的,这篇文章主要分享下一些个人眼中 RPC 接口设计的最佳实践。 初识 RPC 接口设计 由于 RPC 中的术语每个程序员的理解可能不同,所以文章开始,先统一下 RPC 术语,方便后续阐述。 大家都知道共享接口是 RPC 最典型的一个特点,每个服务对外暴露自己的接口,该模块一般称之为 api;外部模块想要实现对该模块的远程调用,则需要依赖其 api;每个服务都需要有一个应用来负责实现自己的 api,一般体现为一个独立的进程,该模块一般称之为 app。 api 和 app 是构建微服务项目的最简单组成部分,如果使用 maven 的多 module 组织代码,则体现为如下的形式。 serviceA 服务 serviceA/pom.xml 定义父 pom 文件 <modules> <module>serviceA-api</module> <module>serviceA-app</module> </modules> <packaging>pom</packaging> <groupId>moe.cnkirito</groupId> <artifactId>serviceA</artifactId> <version>1.0.0-SNAPSHOT</version> serviceA/serviceA-api/pom.xml 定义对外暴露的接口,最终会被打成 jar 包供外部服务依赖 ...

September 2, 2018 · 3 min · 635 words · Bridge Li

关于 tomcat 排查错误的一个小小感悟

前几天响应公司的要求,系统日志接入公司的 ELK,按照中间件的同学要求之后,果然不出意外的遇到了问题,项目跑不起来了,控制台 catalina.out 打印日志如下: Aug 16, 2018 10:02:21 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-apr-8144"] Aug 16, 2018 10:02:21 AM org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-apr-58144"] Aug 16, 2018 10:02:21 AM org.apache.catalina.startup.Catalina start INFO: Server startup in 28819 ms Aug 16, 2018 10:02:23 AM org.apache.catalina.loader.WebappClassLoaderBase loadClass INFO: Illegal access: this web application instance has been stopped already. Could not load com.alibaba.rocketmq.shade.io.netty.util.concurren t.DefaultPromise$2. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate t he thread which caused the illegal access, and has no functional impact. java.lang.IllegalStateException at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1743) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1701) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) Exception in thread "NettyClientWorkerThread_3" java.lang.NoClassDefFoundError: com/alibaba/rocketmq/shade/io/netty/util/concurrent/DefaultPromi se$2 at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.ClassNotFoundException: com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise$2 at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1858) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1701) &#8230; 4 more Aug 16, 2018 10:02:23 AM org.apache.catalina.loader.WebappClassLoaderBase loadClass INFO: Illegal access: this web application instance has been stopped already. Could not load com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise$2. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. java.lang.IllegalStateException at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1743) at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1701) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) Exception in thread "NettyClientWorkerThread_4" java.lang.NoClassDefFoundError: com/alibaba/rocketmq/shade/io/netty/util/concurrent/DefaultPromise$2 at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) Exception in thread "NettyClientWorkerThread_2" Exception in thread "NettyClientWorkerThread_1" java.lang.NoClassDefFoundError: com/alibaba/rocketmq/shade/io/netty/util/concurrent/DefaultPromise$2 at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) java.lang.NoClassDefFoundError: com/alibaba/rocketmq/shade/io/netty/util/concurrent/DefaultPromise$2 at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) Exception in thread "NettyClientSelector_1" java.lang.NoClassDefFoundError: com/alibaba/rocketmq/shade/io/netty/util/concurrent/DefaultPromise$2 at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:590) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:398) at com.alibaba.rocketmq.shade.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:151) at java.lang.Thread.run(Thread.java:745) Aug 16, 2018 10:02:28 AM org.apache.catalina.loader.WebappClassLoaderBase loadClass 很常见的一个错,java.lang.NoClassDefFoundError,找不到 com/alibaba/rocketmq/shade/io/netty/util/concurrent/DefaultPromise,但是不应该啊,因为什么都没有修改,之前都是跑的好好地,怎么会突然找不到这个类,莫名其妙,有同事说,是不是修改 jar 的版本之类的,不过我确实没有修改,只是引入了公司 ELK 相关的 jar 而已,而且看了一下这个类在 classpath 下是存在的,后来经同事提醒,这个地方可能不是真正的报错的地方,看一下 tomcat 的 localhost 日志,果然在发现了如下的报错: ...

August 17, 2018 · 2 min · 387 words · Bridge Li

关于 MySQL 中 utf8 的问题

有一个段子,我每次看了都头皮发麻,这个段子是: 手持两把锟斤拷,口中疾呼烫烫烫,脚踏千朵屯屯屯,笑看万物锘锘锘 我相信凡是和我有一样感觉的应该都知道这是啥,所以为了避免这个问题,我们工作的建议就是,所有的地方都设置成:UTF-8,确实我们这样工作了很多年,不知道哪一年 emoji 突然火了,于是在上家公司做论坛的时候,有一个小伙伴遇到了类似于下面的一个小问题(我找不到原报错日志了): Incorrect string value: ‘\xF0\x9F\x98\x83 <…’ for column ‘summary’ at row 1 当时问我,我也不知道原因,然后经过一番搜索之后,发现原来是 MySQL 存储 emoji 时出错了,存储 emoji 的时候,不应该用 utf8,而是用 utf8mb4。 随着移动互联网的到来,emoji 的应用越来越广泛,本以为这个问题大家都知道了,所以就没有深究过,想着自己记着就行了,但是不知道为什么最近这个问题突然火了,原来不是所有人都知道这个问题,甚至有人说,在做微信开发的时候,天知道微信用户会取什么昵称,所以不得已把用户的昵称都 base64 编码一下,展示的时候再解码,我只能表示:厉害,人民群众的智慧是无穷的。 其实产生这个问题的原因也很简单,据说是 MySQL 的一个 bug: MySQL 的 utf8mb4 是真正的utf8。 MySQL 的 utf8 是一种专属的编码,它能够编码的 Unicode 字符并不多。 关于什么是编码,我相信大家应该都知道了,如果不知道请自行搜索(当年曾经给一个计算机在读博的学姐科普什么是 GBK、GB2312、GB18030、UTF-8、BIG5、ISO-8859-1 等等,也是心累),至于为什么 MySQL 的 utf8 不是真正的 utf8,这是一个历史原因,我搜索的资料是:MySQL 从 4.1 版本开始支持 UTF-8,也就是 2003 年,而今天使用的 UTF-8 标准(RFC 3629)是随后才出现的。 所以现在我们看到的很多 MySQL(或者 MySQL 的分支:MariaDB)资料依然在建议,MySQL 的编码使用 utf8,这在绝大多数的情况下,确实也没有问题,但确实是错误的,最好的选择是,选用真正的 utf8,也就是:utf8mb4。对于已经选用 utf8 需要改用 utf8mb4 的项目,这有一个指南: ...

August 4, 2018 · 1 min · 87 words · Bridge Li

JVM 群关于 Autowired 的讨论

前一段时间 JVM 群有人遇到了一个 stackoverflow 的问题,引发了一个关于 Autowired 的讨论,由于我做的项目可能比较小,并没有遇到过,但感觉这也许就是一个坑,记录下来 ,如果谁有遇到这个问题,说不定就有帮助。 下面我会贴出来群里面的讨论,如果不想看,直接看我的得出的结论,所以 TL;DR 版: spring 中依赖注入有两个注解:Autowired 和 Resource。Resource 的注入的时候是 byName,而 Autowired 注入的时候是 byType,所以平时并没有很大的区别,但 Autowired 和 getBean(Object.class) 会导致栈很深,有可能会导致 stackoverflow,所以如果遇到这个栈很深,不使用 Autowired 会缓解一下,也就是根据我的理解,在项目中能用 Resource 还是用 Resource 比较好。 原版群里的详细讨论如下图(至于深层次的原因,大家可以根据源码自己跟进看一下): 里面 深圳-随缘-颉 贴出的一张图: 感谢这一群小伙伴,如果有信息泄漏,很抱歉。 另外曾经有朋友因为 JVM 的存在,就认为 Java 没有内存泄漏的问题,这是对 Java 有多大的误解啊。

July 29, 2018 · 1 min · 43 words · Bridge Li