Monthly Archives: August 2014

一道Redis面试题

这道面试题是这样子的:

请用Redis和任意语言实现一段恶意登录保护的代码,限制1小时内每用户Id最多只能登录5次。具体登录函数或功能用空函数即可,不用详细写出。

我乍看下觉得像是面试开发的题~
花了一下午了解了下redis,发现这货似乎蛮简单的,而且有哈希和列表数据结构.我一开始想用哈希,每个用户为key,登陆时间为value,统计下nownow-1h之间的key数目是否大于5,类似这样的sql
select count(user) from user_log where access between date_sub(now, interval 1 hour) and now().
但感觉这种范围查找会比较慢.后来觉得用列表是个好方法:列表中每个元素代表登陆时间,只要最后的第5次登陆时间和现在时间差不超过1小时就禁止登陆.用Python写的代码如下,感觉蛮简练的,如果网友有更巧妙的方法,欢迎指教.

#!/usr/bin/env python3
import redis  
import sys  
import time

r = redis.StrictRedis(host='127.0.0.1', port=6379, db=0)  
try:  
    id = sys.argv[1]
except:  
    print('input argument error')
    sys.exit(0)


if r.llen(id) >= 5 and time.time() - float(r.lindex(id, 4)) <= 3600:  
    print("you are forbidden logining")
else:  
    print('you are allowed to login')
    r.lpush(id, time.time())
    # login_func()

从10s到0.2s–个人博客提速简明手记

近期将博客从DigitalOcean迁移到Linode了,迁移完毕后顺便优化了下主机,效果很明显,访问速度从10s降低到0.2s,有图有真相:

Yslow的评分是95分!
以下是我的一些总结:
一.主机选择
1.地理位置–响应时间VS带宽
通常一个误区是新加坡、日本、香港的VPS速度要比美国快,但这里的只是因为地理位置接近而响应时间很快,也即ping显示数值小;但因为主机商的带宽提供各异和近几年国人对亚洲机房的蜂拥,在晚间访问速度并不一定比美国主机具有优势.
2.DNS
现在VPS厂商大都顺带提供域名解析服务,譬如linode的是nsX.linode.com;假如一个用户第一次访问你的博客,而假如他的本地宽带运营商没有缓存你的域名记录,解析就需到就需先到VPS提供商那,假如VPS提供商是海外的那解析时间还是比较长的;所以使用国内dns解析服务(如dnspod)可能是个比较好的提速选择.
3.虚拟化
一般OpenVZ的这种指令级虚拟化的提供商都会超卖,看起来实惠,其实很不稳定;KVM、XEN能较好的保证稳定性.

二.系统优化
1.系统选择
这没什么说的,Linux是标配了,windows用的少,也贵.
2.Linux优化相关
limits.conf和sysctl.conf里的nofile、nproc、vm.swappiness、vm.overcommit_memory等参数,具体配置要看实际运行情况.

三.Web优化
1.使用国内前端公共库
一些国外cms引用的字体、js库网址是海外的,所以获取速度;我博客之前打开速度奇慢主要就是对fonts.googleapi.com的漫长等待.一些国内良心厂商如百度360sinapp又拍云免费提供了常用前端公共库加速服务.
2.web server优化
KeepAlive、Gzip压缩、浏览器缓存、tcpfastopen、启用进程数等等很多了,一本书都讲不完.
3.图片相关
图片是影响网页打开速度的大头,因而优化图片至关重要.大部分博主应该是用现成cms,因而CSS合并贴图不太适用,但图片压缩确是一个可优化 点.Jpeg大部分情况下是最理想格式,但图片内有锐利图形(如截图屏幕)情况下png可能体积更小;值得一提的是png也可以有损压缩,我常用pngquant这个工具有损压缩png图片;Webp这个新星无论是无损还是有损都比png和Jpeg有优势,但目前只有chrome系的浏览器支持.
4.CDN
类似国外Cloudflare,国内很多厂商也提供适用博客的CDN加速服务,如百度加速乐360网站卫士安全宝,除了加速,CDN还能提供”网站永远在线”的效果;但使用CDN也可能因为CDN本身故障反而更慢和访问不了.
5.语言相关
编程语言、框架选择不同,相关优化也各不一样,这个要具体情况具体分析.

四.数据库优化
就和web server的优化一样,这部分知识也需要专门几本书来讲,在此不多讲.

五.更快速的远程连接
1.选择快速的ssh的加密算法
《The Secure Shell: The Definitive Guide》和orczhou的文章加速scp传输速度,都有对比不同加密算法的传输效率.
2.替换ssh–mosh
与基于tcp的ssh不同,mosh基于udp,但验证阶段还是得通过ssh来验证;一句话使用心得:用了mosh之后,现在连远程就像本地.
3.高效的梯子–shadowsocks
我的VPS除了用来写博客,附属(zhuyao)功能是用来当梯子,VPN杀伤范围太大,之前是用ssh建立本地隧道,现在使用shadowsocks,速度提升很明显;

六.安全
自从上次主机被挂马后,我就对安全也重视起来,毕竟都访问不了还谈什么提速优化,以下是我用的一些工具. 1.ssh登陆
我设为禁用root登陆、只允许key登陆、限制登录失败后的重试次数为3.
2.安全审计
Lynis
3.防火墙
Netfilter用法较难,它的封装APFshorewall相对人性化很多.
4.防暴利破解登陆口令
BFD denyhosts
Fail2ban
Sshguard
5.防DDOS
(D)DoS Deflate

记一次诡异的library cache lock事件

1 发现应用出现大量的library cache lock / library cache: mutex X,都是同一个sql_id 0y30pf6xwqt3x:

  SID USERNAME   MACHINE                EVENT                          PARAM                   W   WT SQL                          ST     LT LOGON_TIME
------ ---------- ---------------------- ------------------------------ -------------------- ---- ---- ---------------------------- -- ------ ----------
  1339 xxxxx_user JDBC Thin Client       library cache lock             592165555264/5905026    0    0 0y30pf6xwqt3x/c8rhf8yvfnfxg  A      70         70
                                                                        83424/5373954

  1343 xxxxx_user JDBC Thin Client       library cache lock             592165555264/5909307    0    0 0y30pf6xwqt3x/c8rhf8yvfnfxg  A      61         61
                                                                        85976/5373954

  1344 xxxxx_user JDBC Thin Client       library cache: mutex X         1442036623/904949609    0    0 0y30pf6xwqt3x/c8rhf8yvfnfxg  A     112        112
                                                                        2672/82

  1347 xxxxx_user JDBC Thin Client       library cache lock             592165555264/5909300    0    0 0y30pf6xwqt3x/459f3z9u4fb3u  A      51         94

2 查询对应的sql_id,找不到对应的sql_text

$sql 0y30pf6xwqt3x

no rows selected

SQL_ID CHILD outline/plan_hash_value Ex DISK_READS bg bg/exec rows LOAD_TIME
————- ———- —————————————————————- ———- ———- ————— ———— ———- ———–
TOTAL

No such SQL or cursor body of the SQL does not exist.

3 做了hanganalyze和systemdump
SQL> oradebug setmypid
Statement processed.
SQL> oradebug unlimit;
Statement processed.
SQL> oradebug dump hanganalyze 3
Statement processed.
SQL> oradebug dump systemstate 266
Statement processed.

awk -f ass109.awk 分析后没有发现什么异常

4 STATSPACK Statistics Report for Physical Standby因为我们这个是adg,已经部署了STATSPACK,显示’failed parse elapsed time’占用了最多的时间 :

Top 5 Timed Events                                                    Avg %Total
~~~~~~~~~~~~~~~~~~                                                   wait   Call
Event                                            Waits    Time (s)   (ms)   Time
----------------------------------------- ------------ ----------- ------ ------
library cache lock                           1,576,360     311,235    197   73.5
library cache: mutex X                       3,859,597      98,181     25   23.2
CPU time                                                    12,024           2.8
db file sequential read                      2,176,402         638      0     .2
read by other session                        1,455,746         492      0     .1

Time Model System Stats  DB/Inst: itemadg04/item  Snaps: 10255-10259
-> Ordered by % of DB time desc, Statistic name

Statistic                                       Time (s) % DB time
----------------------------------- -------------------- ---------
failed parse elapsed time                      432,886.6     102.1
parse time elapsed                             409,205.2      96.5

5 经过分析systemdump,发现了错误的sql:select 1

(session) sid: 2831 ser: 20921 trans: (nil), creator: 0x88c3105560 
flags: (0x41) USR/- flags_idl: (0x1) BSY/-/-/-/-/- 
flags2: (0x40009) -/-/INC 
DID: , short-term DID: 
txn branch: (nil) 
oct: 0, prv: 0, sql: 0x8a1fb511e8, psql: 0x89bd9a7e58, user: 45/xxxxx_user 

LibraryObjectLock: Address=0x895f96d108 Handle=0x8a1fb511e8 Mode=N CanBeBrokenCount=1 Incarnation=1 ExecutionCount=0 

User=0x88c3961660 Session=0x88c3961660 ReferenceCount=1 Flags=CNB/[0001] SavepointNum=53ed6599 
LibraryHandle: Address=0x8a1fb511e8 Hash=bbcb647d LockMode=N PinMode=0 LoadLockMode=0 Status=VALD 
ObjectName: Name=select 1 
FullHashValue=eae8b8ed4f6c136a0f0c1571bbcb647d Namespace=SQL AREA(00) Type=CURSOR(00) Identifier=3150668925 OwnerIdn=45 

产生竞争的的是一个cursor build lock: 

User=0x88c3961660 Session=0x88c3961660 ReferenceCount=1 Flags=CNB/[0201] SavepointNum=77 
LibraryHandle: Address=0x89dfd14c40 Hash=55f3bb8f LockMode=X PinMode=0 LoadLockMode=0 Status=0 
ObjectName: Name=$BUILD$. f0c1571bbcb647d 
FullHashValue=5185a2c8f9d62898c21e9d0c55f3bb8f Namespace=SQL AREA BUILD(82) Type=CURSOR(00) Identifier=0 OwnerIdn=0 

6 原因总结:
这个语句来自我们的一个jdbc连接池的检查语句,错误的把mysql的放到oracle上了:
#检查数据库连接的sql(注意:以下例句只适合MySQL,Oracle为select 1 from dual)
jdbc.validationQuery=select 1

导致oracle大量的解析错误,所以能看到sql_id,但是我们看不到sql_text.
同时因为这个是物理备库,我们的错误sql trigger是记录不了的。

另外,我们还遇到过另外一种情况可能找不到sql_text:
http://www.vmcd.org/2011/12/%E4%B8%80%E6%AC%A1lob%E5%AD%97%E6%AE%B5%E7%9A%84%E6%9F%A5%E8%AF%A2%E5%AF%BC%E8%87%B4%E7%9A%84%E7%B3%BB%E7%BB%9F%E9%97%AE%E9%A2%98%E4%BB%A5%E5%8F%8Asql_id%E5%8F%98%E5%8C%96%E7%9A%84%E6%8E%A2%E7%A9%B6/