依依成长日记201901

依依本月1周零11个月

2019017

晚上吃饭,依依下了饭桌自己玩,妈妈和奶奶还在吃饭。突然依依跑过来,拉着妈妈说:“救命呀,救命呀,那里有一个宝宝”。依依指着去卧室的过道,过道和卧室的灯都没开。

妈妈怕👻,都不敢过去看。妈妈被依依牵着手,在客厅从过道望过去,什么也没有看见。依依手指着过道尽头,边说“那里有一个宝宝”,妈妈被吓坏了。

然后妈妈又仔细观察了下,发现主卧内的卫生间玻璃门上有人影。主卧门开着,灯都没开,卫生间的玻璃门正对着过道,所以像镜子一样会反光。搞清楚原因之后,妈妈和奶奶都乐坏了。

爸爸还没到家,依依妈妈通过微信讲述了刚刚发生的这个趣事。

20190122

前几天家里安装了百度AI音响,奶奶说,白天在家让百度AI播放《世上只有妈妈好》,依依听了说:“爸爸也好,唱!爸爸也好,唱!”。

谢谢我的宝。

openjdk-alpine容器中的jvm如何dump

openjdk-alpine容器中的jvm如何dump

微服务架构之后,应用的jvm运行在容器之内,如果系统出现问题,如何对jvm进行dump?

有两种方法:

  1. 开启jmx,使用jvisualvm通过jmx连接jvm,生成dump。
  2. 使用docker命令,进入容器的shell环境,使用jmap命令生成dump。

本文主要介绍第二种方法。在之前的文章中说过,我们的项目使用Google的jib打包成镜像,使用的基础镜像是8-jdk-alpine。容器启动时第一个进程就是java:

1
2
3
4
5
6
[root@VM_16_16_centos pp]# docker exec -it pp_eureka_1 sh
/ # ps
PID USER TIME COMMAND
1 root 0:50 java -Xms256m -Xmx512m ......
94 root 0:00 sh
99 root 0:00 ps

使用alpine镜像会有个问题,如果java进程的pid=1,那么无法执行jdk的各种连接java进程的命令,会报如下错误:

Unable to get pid of LinuxThreads manager thread

其他os镜像未验证,相关issue:https://github.com/docker-library/openjdk/issues/76

解决的方法是:启动一个init进程(pid=1)来接收docker stop and docker kill的信号,它会转发信号给其他进程,负责关闭僵尸进程。java进程由init进程启动。

具体有以下两种做法。

docker run –init

在docker 1.13 之后的版本,可以在docker run时加上 --init 参数来实现。

1
2
3
4
5
6
7
$ docker run --rm -it --init openjdk:8-jdk-alpine
/ # ps
PID USER TIME COMMAND
1 root 0:00 /dev/init -- /bin/sh
7 root 0:00 /bin/sh
8 root 0:00 ps
/ #

如果是docker compse,可以在docker-compose中配置上init参数。

1
2
3
4
5
6
7
8
9
10
11
12
version: '2.2'
services:
web:
image: alpine:latest
init: true
version: '2.2'
services:
web:
image: alpine:latest
init: /usr/libexec/docker-init

需要注意的是,init参数对docker-compose.yml的文件格式版本有要求:

  1. v2版本,version必须配置为2.2或以上版本。
  2. v3版本,version必须配置为3.7或以上版本。
  3. 不同版本的compose文件,有docker版本兼容性要求

krallin/tini

安装Tini,使用tini作为入口进程,配置启动java进程。

1
2
3
RUN apk add --no-cache tini
# Tini is now available at /sbin/tini
ENTRYPOINT ["/sbin/tini", "--", "java", "-Xms256m", "-Xmx512m", ......]

实际上,docker的--init参数也是通过集成Tini实现的。

其他事项

上述两种方式,那种更好?关于这个问题,github上有相关的讨论。个人觉得,各有利弊:

  1. 使用docker --init 参数简单,但是需要运维人员注意,部署时存在人为操作遗漏的风险。
  2. 使用 Tini 不用担心人为失误,但用jib打包镜像会增加配置工作,需要为每个项目配置entrypoint参数。

另外需要注意的是,在centos下,docker必须是docker-1.13.1-88.git07f3374.el7.centos.x86_64之后的发行版本,之前版本有bug。这个问题耽误了我一天时间,在本地windows下都好使,部署到docker不好使,试了好久,最后发现是centos下docker版本bug,更新后就好了。

依依成长日记201812

依依本月1周零10个月

20181211

依依早上半夜醒来,黑暗中挥着小手,闭着眼睛在那喊着“不要,不要”。心理琢磨着这是做噩梦了吧,不要什么呢?“不要爸爸,不要爸爸”,爸爸心理崩溃。依依妈妈把这小事讲给同事听,大家笑死了。

最近一段时间忙着写论文,陪依依时间比较少,被嫌弃了啊。

20181220

今天下班后要去办事,回家比平时早了一点,比依依妈妈更早到家。最近一个多月时间,经常都是依依妈妈先到家。

依依刚睡醒没多久,奶奶刚热好奶正要喂依依吃。我钥匙开门,依依听见了开门声,奶都不喝欢快的从沙发那跳到门口,边走边说“妈妈回来”。然后门打开,依依看见是爸爸回来了,而不是期待的妈妈,突然就崩溃了,边哭边说“爱妈妈,爱妈妈”。可能依依满怀期待的要迎接妈妈,突然希望落空,失落的哭了。

爸爸赶紧去哄她,说“爸爸也爱依依”,同时蹲下来张开双手,要去抱她。依依说“不要,不要爸爸,爱妈妈”,边哭边躲,跑到了窗户边上,趴在窗台在那继续哭着,嘴上还在说着“爱妈妈”,特别可怜的样子。

就在这时,妈妈开门进来了,依依看见妈妈马上止哭,跑过去抱妈妈了。爸爸跟妈妈描述刚才的事情,还学依依哭的样子,依依听了还会跟着咔咔大笑。

20181223

今天周日,晚饭洗澡后,陪依依玩了一会捉迷藏。

卧室和走廊的灯关着,爸爸一会躲在门后,一会躲在衣柜边,一会又藏到了被窝里,依依有时候能找到,有时候又找不到。每一轮开始,依依都是先去上一轮找到爸爸的地方看看,小孩子的逻辑简单直接。找不到的时候,依依会说“哦?爸爸。哦?爸爸”,意思是爸爸在哪呢。

有一次爸爸藏在窗帘后,窗帘未落地,小腿以下露出来了,以为依依发现不了,然而却被她看见了。然后又一次,爸爸坐在床右侧地上,用被子盖着头,身后是窗户,边上就是刚才躲过的窗帘。依依走到窗帘边,掀了几次窗帘发现没有人,爸爸坐在边上看着她也不做声。依依检查完窗帘,左转身的时候突然发现了爸爸,咔咔咔笑的很开心。

依依玩的很高兴,跟她说玩最后一次,然后还想玩,说“还要玩一次”,实际又玩了5次以上。

微信小程序开发问题总结(1)

微信小程序开发问题总结(1)

项目外包研发小伙伴开发的小程序,遇到2个问题解决不了:

  1. 某同事Z的小米6手机,打开小程序,在选择法院界面,搜索输入任何内容都没有搜索结果。周围其他同事手机上没遇到问题。
  2. 某同事C的华为mate手机,进入法院选择页面,选择法院后跳转回首页,选择的结果未刷新。周围其他同事手机上能正常。

问题1

同样的程序,周围其他人手机上正常,说明可能跟环境有关。

远程调试,跟踪代码的时候发现,代码写法不严格,很多语句结尾没有加封号。相关的js文件里,把代码的结尾封号都加上,再远程调试,就好了。

原因推测:微信针对不同的Android手机平台,编译了不同版本的js引擎。

总结:虽然js语法宽松,但是为了避免出现莫名其妙的问题,代码写法需要保持严格。这是个低级错误。

问题2

首页(/homepage/homepage)相关代码:

1
2
3
4
5
onLoad: function(options) {
// ...
var courtName = wx.getStorageSync('courtName');
// 更新首页中已选择法院输入框的值
}

法院选择页(/court/court)相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bindcourt: function (e) {
var courtName = e.currentTarget.dataset.court; //选中的法院名称
var courtId = e.currentTarget.dataset.cid; //选中的法院ID
wx.setStorageSync('courtName', courtName);
wx.setStorageSync('courtId', courtId);
wx.switchTab({
url: '../homepage/homepage',
success: function (e) {
var page = getCurrentPages().pop();
if (page == undefined || page == null) return;
page.onLoad();
}
});
}

代码说明:在法院选择页,选中了法院之后,将选择结果保存到本地存储(小程序即使退出,下次进入也要默认使用最后一次的选择结果,所以存储)。然后调用switchTab返回首页,switchTab的success回调中,调用getCurrentPages()获取当前页,然后调用onLoad进行主动刷新。

上述代码有几个问题:

  1. 在switchTab的回调中去调用getCurrentPages(),可能会有同步问题,不能保证得到的页面就是目标页面。
  2. getCurrentPages().pop() 修改了页面栈,可能引发未知问题。
  3. 首页的onLoad是事件函数,一个页面只会调用一次。

解决方法:

  1. 首页在onShow事件中进行页面的刷新处理。
  2. 移出swtichTab中的回调处理代码。

感悟

编程习惯也是非常重要的技能,不好的编程习惯,误用的方法会引入莫名其妙的问题。

依依成长日记201810

依依本月1周零8个月

20181020

今天带依依去新奥购物中心和奥森玩,妈妈带着依依走到了儿童服装区,依依看见鞋架上鞋子就拿下来,然后快速的踢踢踢把鞋子脱了,去试穿新鞋,动作利索。

吃完饭去给依依取儿童滑板车,路过小火车,妈妈说依依一路跟着,想要做。然后妈妈带着坐了一圈,到站了还不下来,嚎啕大哭,大嗓门引得路人侧目。

带依依取奥森,想去看雨看秋菊,依依一路自己带着滑板车,有时推有时踩,不让人帮忙。往回走的时候已经比较熟练了。

20181022

今天周一,早上楼上邻居彤彤奶奶带彤彤来家里玩,依依不高兴,彤彤进门就开始一直叫“走、走、走”。彤彤在客厅,穿了依依一只凉鞋,依依穿着另一只,两人争执不下,依依生气的推着自己的小椅子,进到了厨房里,边哭边叫走走走,还抖椅子撞击地板,发出嗒嗒嗒的声音。

依依最近跟彤彤玩,老被欺负,彤彤总拍她脑袋,所以依依不喜欢彤彤。小小年纪已经有了爱恨。

20181023

半夜依依在睡眠中,爸爸憋不住放了个响屁,把依依都给震醒了。依依半睡半醒中反复说着“依依放屁屁,奶奶,依依放屁屁”。妈妈把依依搂过去,又给奶睡了。