******** 问题解决 ******** ================== 常见问题解决的经验积累 ================== 1. 像这种dao bo的空指针要么是没有set要么是xml配置里面写错了 2. 返回的数据里面明明set了,但是客户端没有接收到,这个问题出在你set了但是get不出来,有可能是你对于java bean没有提供get方法导致的 3. 如果不报错出现数据异常,先看数据库的数据是否异常,如果数据库的数据没有问题,那就是取数据的代码逻辑有问题 4. sdk出错是因为更新sdk后没有把老的删除掉 5. 如果部署的时候发现有job跑不起来,看看日志,有This is very likely to create a memory leak警告一般都是触发器的名称配重了,至于为什么和内存泄露有关系就要好好研究一下了 ============== 问题解决方法论 ============== 目前遇到的两种类型的问题 1. 结果与预期不符,其实就是代码有bug,比如上次数组越界的导致异常的bug | (1)首先确定出现了什么问题,有什么信息,这些信息能够定位到bug在哪里 | (2)其次看看能不能复现一遍问题,就服务端来说比如测试的时候拿请求失败的那个id去进行请求然后debug | (3)不容易复现的话或者无法进行debug的话可能需要通过日志什么的来定位,还没接触过,不太清楚 2. 需求难以实现 | (1)首先我写的需求大部分都有同类代码可以参考,直接找下业务逻辑差不多的需求,参考一下代码 | (2)其次如果没有可参考的代码,我当前遇到的问题基本都有解决手段的,网上多搜索一下 | (3)搜到的东西应用起来还是有问题一般是对原理理解不足(比如上回的ssh连接) | (2)如果需求比较个性化,就拆分成常规处理的组合 ============ 傻逼问题合集 ============ 问题1 ----- 犯了一个很蠢的错误,if那里没有进行调用导致判断恒为真 .. code-block:: python def find_all_files(source_dir): file_list = [] for dir_entry in os.scandir(source_dir): # 默认不会去找.和..两个特殊的dir,所以可以放心食用 if dir_entry.is_dir and dir_entry.name != r'\..+': son_file_list = find_all_files(dir_entry.path) file_list.append += son_file_list 问题2 ----- 正则表达式不是这样用的,要借助re函数 .. code-block:: python In [8]: '.DS_Store' == r'*' Out[8]: False In [9]: '.DS_Store' == r'.*' Out[9]: False ============== 问题9 死锁检查 ============== 问题描述 -------- 2018年4月19日发生死锁,看了一下报错信息看不出个所以然来,然后在阿里云的死锁信息中找到了死锁完整信息 ------------------------ LATEST DETECTED DEADLOCK ------------------------ 180419 0:45:25 *** (1) TRANSACTION: TRANSACTION 438E41539, ACTIVE 0.055 sec starting index read mysql tables in use 1, locked 1 LOCK WAIT 5 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1 LOCK BLOCKING MySQL thread id: 151443056 block 134470944 MySQL thread id 134470944, OS thread handle 0x2b65eb7ce700, query id 31044628413 10.168.52.9:43800 voice Updating UPDATE user_info SET STATUS='1',GMT_MODIFIED = now(),total_time=total_time+0 WHERE STATUS='0' AND ID in ( 30407794 , 30207934 ) *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 3053 page no 14166 n bits 112 index `PRIMARY` of table `voice`.`user_info` trx id 438E41539 lock_mode X locks rec but not gap waiting *** (2) TRANSACTION: TRANSACTION 438E41538, ACTIVE 0.055 sec starting index read mysql tables in use 1, locked 1 12 lock struct(s), heap size 3112, 6 row lock(s), undo log entries 6 MySQL thread id 151443056, OS thread handle 0x2b675fc50700, query id 31044628947 10.168.52.9:43842 voice Updating UPDATE video_chat_info SET GMT_MODIFIED = now() , modifier = 'user_end' , actual_end_time = '2018-04-19 00:45:25' , end_user_id = 30407794 , status = 'end' , user_time = 0 , to_user_time = 0 , total_time = 0 where ID=9044605 *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 3053 page no 14166 n bits 112 index `PRIMARY` of table `voice`.`user_info` trx id 438E41538 lock_mode X locks rec but not gap *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 3963 page no 6186 n bits 168 index `PRIMARY` of table `voice`.`video_chat_info` trx id 438E41538 lock_mode X locks rec but not gap waiting *** WE ROLL BACK TRANSACTION (1) 问题解决 -------- 这个信息中记录了两个事务的死锁情况,第一个事务是要执行UPDATE user_info SET STATUS='1',GMT_MODIFIED = now(),total_time=total_time+0 WHERE STATUS='0' AND ID in ( 30407794 , 30207934 ),等待加在`voice`.`user_info primary索引上的锁,第二个事务是要执行UPDATE video_chat_info SET GMT_MODIFIED = now() , modifier = 'user_end' , actual_end_time = '2018-04-19 00:45:25' , end_user_id = 30407794 , status = 'end' , user_time = 0 , to_user_time = 0 , total_time = 0 where ID=9044605等待加在`voice`.`video_chat_info` primary索引上的锁,一看就知道两个事务都是chatService.end的调用,然后再一看调用者的id竟然是同一个,这样就能知道导致死锁的原因是同时调用两次end 如何避免这种问题呢? 不要出现update video_chat update user_info update video_chat这样的夹心饼干,同时调用很容易死锁,为了避免不同方法的死锁,最好update是有一定顺序的,最好的方法还是拆分事务,可能异步做的就异步去做 =========================== 问题8 记录一下SQL引发的问题 =========================== 问题描述 -------- .. code-block:: SQL SELECT a.gmt_modified, b.gmt_modified from voice.user_value_info AS a left JOIN voice.user_value_detail_info AS b on a.user_id= b.user_id WHERE a.type= 'richValue' AND a.gmt_modified> 2018-03-09 AND a.id >= 71380 AND b.gmt_modified < '2018-03-09' 发现删除了下面那个引号会导致查询失效,因此就很奇怪了。有没有引号究竟有什么区别呢?上面没引号为啥没问题? 问题解决 -------- 这时候就应该把问题抽离出来,单独使用没引号的去试试(其实是构造了一个模糊的猜想,可能是没有引号的情况下存在某种问题),能不能获得准确结果,这样一试,结果就显而易见了,因此排查问题的时候要针对一个点去检测,首先要挑最有可能出问题的那个点,如果一直抱着一串代码看,那是看不出问题来的,一定要假设,并且实验 ==================== 问题7 男生豪气榜异常 ==================== 问题描述 -------- 合合告诉我说一个男生送了大礼物但是豪气榜上没有排名,初步查了一下发现这个男生的detail记录没有,但是total记录有 问题解决 -------- 一开始找遍了所有的可能性还是百思不得其解,本来都已经打算当成数据库错误准备放弃了,后来一想可以看看有没有共性错误发生,使用sql查询了同样性质的错误(同一时间段添加了total记录但是没有添加detail记录的),发现有二十来个,然后一看发现所有错误都是total记录是第一次添加的时候出现的。再一看代码,原来在添加新的total记录之后直接return了。这个bug太简单了,不应该犯这个错的。 ==================================== 问题6 使用javastack排查cpu100%的问题 ==================================== 问题描述 -------- 基础平台的服务器出现了长时间的cpu100% 问题解决 -------- 首先上网查了如何解决cpu问题,根据教程使用ps -H -p pid命令查看了占用cpu的线程id,然后使用jstack查看这些线程的调用堆栈,发现全部是可运行状态,然后都停留在两个位置。刚开始以为是这两个位置调用静态方法卡死,改了之后还是有问题,静态方法不会导致这些问题。就打了日志,最后发现是死循环导致的。原来之所以停在那里是因为死循环而那些代码耗时比较长所以会取stack的时候会发现代码总是执行到那个地方。 ================================== 问题5 连续请求导致的数据库记录混乱 ================================== 问题描述 -------- 有一个请求会先检测数据库中有无该记录,没有则插入数据,有则不插入,但是在连续请求的情况下会导致同时插入两条一样的数据 问题解决 -------- 根本原因应该是在于数据库事务级别上http://bbs.csdn.net/topics/391076492,当前的解决方式是通过memcache限制单位时间内的请求次数,但是这个治标不治本啊,是否有什么方式能够像线程锁那样卡住?或者有什么设计手段可以规避这种问题的出现?这些是我值得思量的,应该是存在一些更加高阶的手段的。memcache其实也可以用来做锁,不过感觉有些太浪费了。 ================================== 问题4 python安装包总是安装到/lib下 ================================== 问题描述 -------- 持续很久了,使用pip进行安装的时候总是装到/lib下,导致很多东西都无法正常使用,第一次尝试解决没有解决 问题解决 -------- 最近又尝试了一次,这次折腾的时间也是够长的。 首先,我认为安装路径和PYTHON_PATH变量有关系,然后通过unset PYTHONPATH命令移除了这个变量,发现问题仍然存在。 我再去看报错信息,发现好像是说和一个什么pre的东西也会影响到安装目录,然后我就想有哪些可能呢?如果有这个东西又是在哪里配置的呢?这样就想到有可能在home目录下有这个配置,于是乎发现在一个.pydistutils.cfg的文件下配了这个pre,删除后问题完美解决。 总结一下,本来定位到这个问题其实通过切换用户看问题是否仍然存在就行了。效率会高很多。以后可以这么来搞。同时,对于这种配置导致的错误,要看配置有可能是从哪里取的,一般有三种情况,环境变量,应用配置文件,home配置文件,可以通过检查环境变量、切换用户来快速锁定到底问题出在哪一个点。 ================================== 问题3 撩聊等服务器奔溃问题追踪回顾 ================================== 问题描述 -------- 某天下午4点半的样子出现撩聊服务器奔溃,其他app的服务器或多或少服务无法使用的现象 问题解决 -------- 我在追踪问题原因的时候走了很多弯路,刚接触到的时候完全不知道应该怎么做,虽然最后通过日志找到了问题出现的原因,但是花的时间太长了。 总结一下,遇到此类问题之后要如何处理,如何追踪 1. 首先查看数据库、服务器是否有报警(如果报警怎么办,可能要紧急修改问题代码) 2. 其次查看服务器是否运行 3. 查看nginx是否运行 4. 然后开启或者重启服务器,隔10分钟之后开启另外一台(防止cpu报警) 5. 追踪问题原因 那么如何追踪问题原因呢? 1. 首先问题一般会出现在哪里呢?数据库IO,服务器网络问题,缓存,队列,业务逻辑问题等等都有可能 2. 需要根据日志来查看出现问题的点,一般是异常和任务处理时长两个点 3. 如果有直接明了的异常那么可以根据异常进行跟踪,如果没有那么可以根据任务处理时长来跟踪 4. 任务处理时长远超一般情况的那么肯定是存在IO问题的 5. 如果出现多个app同时受累,那么问题多出现在外部服务,比如缓存、队列、数据库 更多的总结可能还需要多服务底层更加深入的了解和更多解决实际问题的经验才有可能 ======================================= 问题2 数据库记录错误导致程序bug问题回顾 ======================================= 问题描述 -------- 数据库记录不匹配,关系表中有一条在用户表中被删除id的数据,导致业务处理过程当中没有取到对应的那个用户,由于使用了下标迭代两个list,出现了list越界的异常 问题解决 -------- 一般来说在正式环境这种问题是不会出现的,但是我从中还是要学到一些东西 1. 首先数组越界对于使用过迭代的逻辑处理代码而言是很容易出现的一种异常,特别是在一些特殊情况下,所以写下标迭代的代码,第一要注意循环次数,第二要注意是否有可能出现越界的情况,这种情况是否在常规情况范围之内 2. 还有一个值得注意的问题是空指针,要避免任何可能出现空指针的情况 3. 最后一个是如何规避错误,最好要能使代码能够运行在出现异常的情况之下,而不产生超出想象的问题,这是对于代码健壮性的要求。另外,还要尽可能地规避数据库操作过程当中偶然出现的一些不一致,以及一些可能想见的异常流,比如客户端的一些常见异常等等,因此对于任何会出现空指针和越界的代码都要做事先的预防处理,对此还是需要形成一套体系化的方法论才行 ==================== 问题1 git hook的使用 ==================== 问题描述 -------- 使用git hook的时候发现跟着教程创建的git hook根本就无法使用 问题解决 -------- 确认是权限的问题,下次要记住自己创建的脚本是没有执行权限的,怪不得教程里面的要复制,还有zsh会把可执行的标红,不可执行的标白,这个也值得注意一下,其实想想自己的步骤有哪些和别人不同就行了,从这点出发就可以想到了 还有通过bin中的程序执行脚本不需要权限,因为相当于是程序读取脚本再执行,而自执行脚本是需要权限的