存档

2015年7月 的存档

Java中可以比较隐密的恶意代码

2015年7月30日 没有评论

先贴代码,看运行结果:

            Class<?> cache = Integer.class.getDeclaredClasses()[0];
            Field c = cache.getDeclaredField("cache");
            c.setAccessible(true);
            Integer[] array = (Integer[]) c.get(cache);
            array[130] = array[131];
            
            Integer x = 2;
            System.out.println(x + 2);

运行结果实际上是5,其它地方如果出现Integer类型的数值,2就会变成3。

更多内容…

单锚点同步多项数据问题

2015年7月24日 没有评论

业务中碰到单锚点同步多项数据问题,举个例子说明以备忘之。

概念解释:
锚点同步:client用自己得到的最后一次操作编号,来获取之后所有的操作,重放以达到状态一致。

问题描述:
多从库环境下,用一个锚点通过两次DAO去同步两类业务数据,有可能会因为两个从库的同步状态不一致,导致丢数据。
比如:用100锚点去同步时,先A业务,再B业务,同步A时,拉到123,同步B时拉到125,两次取数据间A业务产生了124操作。下次client用125来同步,会丢失124操作。

后续:
演练时发现跟是否双从或是否主从无关,只有主库的情况下同样有可能出现类似问题,两次操作有时差,没法保障数据一致(不可能锁上不让操作)。

解决办法:
每次同步时,记录每个业务的最大值操作编号max(a,b,c,d,…),下次以最大编号来拉时,每个业务按自己上次记录的编号拉。

问题:
有可能会出现用125来拉时,拉到124操作。相比之前的124操作丢失,会更好。
从单个业务看,一直是连续的不会丢,如果各业务间操作不耦合,不会有影响。
如果多业务间有时续要求,需要根据业务依赖关系来确定兼容方案,会更复杂,有两种方式可以解决:
1、拉完A后拉B,如果B小于A,则以A为准,可以结束;如果B大于A,拉B后再拉A(记做A1),丢弃掉A1中比B大的部分,以B为准。如果是多从库,必拉一次小的且拉小的数据的操作从主库进行。
2、耦合的业务操作,只重放到小编号的数据。这么做很安全,缺点是及时性差,而且如果某个业务较冷的时候,滞后会非常严重。
推荐方案1。

分类: 工作 标签: ,

Java获取本机IP忽然出错

2015年7月15日 没有评论

一直工作很好的线上服务,今天忽然发现有问题,原因是取到的本机IP是错的。
ifconfig的结果如下:

eth0      Link encap:Ethernet  HWaddr 12:xx:xx:xx:xx:xx  
          inet addr:10.xx.xx.xx  Bcast:10.xx.xx.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:347107351 errors:0 dropped:0 overruns:0 frame:0
          TX packets:521084913 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:73368864377 (68.3 GiB)  TX bytes:73126114339 (68.1 GiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:407951 errors:0 dropped:0 overruns:0 frame:0
          TX packets:407951 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:112925033 (107.6 MiB)  TX bytes:112925033 (107.6 MiB)

取IP的时候过滤掉了非isSiteLocalAddress的IP:

    public static String getLocalIp() {
        Enumeration<NetworkInterface> ifs;
        try {
            ifs = NetworkInterface.getNetworkInterfaces();
        } catch (SocketException e) {
            return "";
        }

        while (ifs.hasMoreElements()) {
            NetworkInterface i = ifs.nextElement();
            Enumeration<InetAddress> as = i.getInetAddresses();
            while (as.hasMoreElements()) {
                InetAddress a = as.nextElement();
                if (!a.isSiteLocalAddress()) continue;
                return a.getHostAddress();
            }
        }
        return "";
    }

取出来的是172.x.x.x,还能ping通,ping通后,arp信息中找不到对应的mac地址。瞬间晕了。
更多内容…

分类: 工作 标签: , , , ,

Java初始化中的clinit和init

2015年7月13日 没有评论

单纯理解Java的初始化,可以认为有两步,静态初始化的类构造器clinit和实例化的实例构造器init的初始化。
clinit发生在首次访问期静态数据或方法时,再或者是首次new的时候,在init之前。

什么时候有clinit?
《深入理解Java虚拟机》书中给出了大致的答案:

<clinit>()方法是由编译器自动收集类中的所有变更的赋值动作和静态语句块(static{}块)中的语句产生的

这句话总结的非常到位,但下面补的这一刀很容易把人带到沟里去,大意:

如果一个类中没有静态语句块,也没有对变量的赋值操作,可以不为这个类生成<clinit>()方法。

直接的理解是,不出现下面这两种代码,就不需要clinit方法;相反的,出现了,就需要。

//1.静态变量或静态常量
private static Xxx xxx = ....;
private static final Yyy yyy = ...;

//2.静态代码块
static{
Xxx.xxx();
Yyy.yyy();
}

实际上并不是这样的。我下面具体描述一下。
更多内容…

分类: 工作 标签: , , , ,

MySQL崩溃之utf8mb4的like非左匹配

2015年7月8日 没有评论

线上数据库崩溃,怀疑是utf8mb4编码导致的,目前已经重现,并找到具体的解决办法。

原因:
当支持utf8mb4的字段中出现emoji表情时,用like ‘%xx%’方式全搜索时,崩溃。
应该是MySQL的bug,怀疑是因为emoji的编码长度是4,而utf8_unicode_ci是3,MySQL的like非左匹配操作时,碰到占4字节的utf8mb4时出现问题(猜测)。

解决办法:
用instr函数取代like。不崩溃且效率高。instr(‘abcd’,’ab’)值为1,instr(‘abcd’,’ca’)值为0。即大于0为命中。

总结:在like左匹配的时候,用原生like靠谱。如果是两边匹配的时候,like支持复杂语法,所以效率较低。普通的%xx%类型的搜索,直接instr即可搞定。
另外:instr的大小写匹配跟like一样,默认是大小写不敏感的。

以下是完整的异常信息。
更多内容…

分类: 工作 标签: , , , ,