??xml version="1.0" encoding="utf-8" standalone="yes"?> 丰富的数据结构得redis的设计非常的有趣。不像关pd数据库那PDEV和DBA需要深度沟通,review每行sql语句Q也不像memcached那样Q不需要DBA的参与。redis的DBA需要熟悉数据结构,q能了解使用场景?/p>
下面举一些常见适合kv数据库的例子来谈谈键值的设计Qƈ与关pd数据库做一个对比,发现关系型的不之处?/p>
记录用户d信息的一个系l, 我们化业务后只留下一张表?/p>
user_id表的主键Qname表示用户名,login_times表示该用Ldơ数Q每ơ用L录后Qlogin_times会自增,而last_login_time更新为当前时间?/p>
关系型数据{化ؓKV数据库,我的Ҏ如下Q?/p>
key 表名Q主键|列名 value 列?/p>
一般用冒号做分割W,q是不成文的规矩。比如在php-admin for redispȝ里,是默认以冒号分Ԍ于是user:1 user:2{key会分成一l。于是以上的关系数据转化成kv数据后记录如下: q样在已知主键的情况下,通过get、set可以获得或者修改用Ldơ数和最后登录时间和姓名?/p>
一般用h无法知道自己的id的,只知道自q用户名,所以还必须有一个从name到id的映关p,q里的设计与上面的有所不同?/p>
q样每次用户d的时候业务逻辑如下Qpython版)Qr是redis对象Qname是已l获知的用户名?/p>
如果需求仅仅是已知idQ更新或者获取某个用L最后登录时_dơ数Q关pd和kv数据库无啥区别。一个通过btree pkQ一个通过hashQ效果都很好?/p>
假设有如下需求,查找最q登录的N个用戗开发h员看看,q是比较单的Q一个sql搞定?/p>
DBA了解需求后Q考虑C后表如果比较大,所以在last_login_time上徏个烦引。执行计划从索引leafblock 的最双开始访问N条记录,再回表Nơ,效果很好?/p>
q了两天Q又来一个需求,需要知道登录次数最多的人是谁。同L关系型如何处理?DEV说简?/p>
DBA一看,又要在login_time上徏立一个烦引。有没有觉得有点问题呢,表上每个字段上都有素引?/p>
关系型数据库的数据存储的的不灉|是问题的源头Q数据仅有一U储存方法,那就是按行排列的堆表。统一的数据结构意味着你必M用烦引来改变sql的访问\径来快速访问某个列的,而访问\径的增加又意味着你必M用统计信息来辅助Q于是一大堆的问题就出现了?/p>
没有索引Q没有统计计划,没有执行计划Q这是kv数据库?/p>
redis里如何满以上的需求呢Q?对于求最新的N条数据的需求,链表的后q后出的特点非常适合。我们在上面的登录代码之后添加一D代码,l护一个登录的链表Q控制他的长度,使得里面永远保存的是最q的N个登录用戗?/p>
q样需要获得最新登录h的idQ如下的代码卛_ 另外Q求dơ数最多的人,对于排序Q积分榜q类需求,sorted set非常的适合Q我们把用户和登录次数统一存储在一个sorted set里?/p>
q样假如某个用户dQ额外维护一个sorted setQ代码如?/p>
那么如何获得dơ数最多的用户呢,逆序排列取的排名WN的用户即?/p>
可以看出QDEV需要添?行代码,而DBA不需要考虑索引什么的?/p>
tag在互联网应用里尤其多见,如果以传l的关系型数据库来设计有点不伦不cR我们以查找书的例子来看看redis在这斚w的优ѝ?/p>
两张表,一张book的明l,一张tag表,表示每本的tagQ一本书存在多个tag?/p>
tag表自兌2ơ再与book兌Q这个sqlq是比较复杂的,如果要求即rubyQ但不是web斚w的书c呢Q?/p>
关系型数据其实ƈ不太适合q些集合操作?/p>
首先book的数据肯定要存储的,和上面一栗?/p>
tag表我们用集合来存储数据Q因为集合擅长求交集、ƈ?/p>
那么Q即属于ruby又属于web的书Q?/p>
卛_于rubyQ但不属于web的书Q?/p>
属于ruby和属于web的书的合集? 单到不行ѝ?/p>
从以?个例子可以看出在某些场景里,关系型数据库是不太适合的,你可能能够设计出满需求的pȝQ但L感觉的怪怪的Q有U生搬硬套的感觉?/p>
其dpȝq个例子Q频J的Z务徏立烦引。放在一个复杂的pȝ里,ddlQ创建烦引)有可能改变执行计划。导致其它的sql采用不同的执行计 划,业务复杂的老系l,q个问题是很N估的Qsql千奇百怪。要求DBA对这个系l里所有的sql都了解,q点太难了。这个问题在oracle里尤其严 重,每个DBA估计都碰到过。对于MySQLq类pȝQddl又不方便Q虽然现在有online ddl的方法)。碰到大表,DBA凌晨爬v来在业务低峰期操作,q事我没干q。而这U需求放到redis里就很好处理QDBA仅仅对容量进行预估即可?/p>
未来的OLTPpȝ应该是kv和关pd的紧密结合?/p>
来源Q?a target="_blank" rel="nofollow">www.hoterran.info用户dpȝ
关系型数据库的设?/h4>
mysql> select * from login;
+---------+----------------+-------------+---------------------+
| user_id | name | login_times | last_login_time |
+---------+----------------+-------------+---------------------+
| 1 | ken thompson | 5 | 2011-01-01 00:00:00 |
| 2 | dennis ritchie | 1 | 2011-02-01 00:00:00 |
| 3 | Joe Armstrong | 2 | 2011-03-01 00:00:00 |
+---------+----------------+-------------+---------------------+
REDIS的设?/h4>
Set login:1:login_times 5
Set login:2:login_times 1
Set login:3:login_times 2
Set login:1:last_login_time 2011-1-1
Set login:2:last_login_time 2011-2-1
Set login:3:last_login_time 2011-3-1
set login:1:name ”ken thompson?
set login:2:name “dennis ritchie?
set login:3:name ”Joe Armstrong?/pre>
set "login:ken thompson:id" 1
set "login:dennis ritchie:id" 2
set "login: Joe Armstrong:id" 3
1
#获得用户的id
2
uid
=
r.get(
"login:%s:id"
%
name)
3
#自增用户的登录次?/code>
4
ret
=
r.incr(
"login:%s:login_times"
%
uid)
5
#更新该用L最后登录时?/code>
6
ret
=
r.
set
(
"login:%s:last_login_time"
%
uid, datetime.datetime.now())
1
select
*
from
login
order
by
last_login_time
desc
limit N
1
select
*
from
login
order
by
login_times
desc
limit N
1
#把当前登录hd到链表里
2
ret
=
r.lpush(
"login:last_login_times"
, uid)
3
#保持链表只有N?/code>
4
ret
=
redis.ltrim(
"login:last_login_times"
,
0
, N
-
1
)
1
last_login_list
=
r.lrange(
"login:last_login_times"
,
0
, N
-
1
)
zadd login:login_times 5 1
zadd login:login_times 1 2
zadd login:login_times 2 3
1
#对该用户的登录次数自?
2
ret
=
r.zincrby(
"login:login_times"
,
1
, uid)
1
ret
=
r.zrevrange(
"login:login_times"
,
0
, N
-
1
)
TAGpȝ
关系型数据库的设?/h4>
mysql> select * from book;
+------+-------------------------------+----------------+
| id | name | author |
+------+-------------------------------+----------------+
| 1 | The Ruby Programming Language | Mark Pilgrim |
| 1 | Ruby on rail | David Flanagan |
| 1 | Programming Erlang | Joe Armstrong |
+------+-------------------------------+----------------+
mysql> select * from tag;
+---------+---------+
| tagname | book_id |
+---------+---------+
| ruby | 1 |
| ruby | 2 |
| web | 2 |
| erlang | 3 |
+---------+---------+
假如有如此需求,查找xruby又是web斚w的书c,如果以关pd数据库会怎么处理Q?/pre>
1
select
b.
name
, b.author
from
tag t1, tag t2, book b
2
where
t1.tagname =
'web'
and
t2.tagname =
'ruby'
and
t1.book_id = t2.book_id
and
b.id = t1.book_id
REDIS的设?/h4>
set book:1:name ”The Ruby Programming Language?
Set book:2:name ”Ruby on rail?
Set book:3:name ”Programming Erlang?
set book:1:author ”Mark Pilgrim?
Set book:2:author ”David Flanagan?
Set book:3:author ”Joe Armstrong?/pre>
sadd tag:ruby 1
sadd tag:ruby 2
sadd tag:web 2
sadd tag:erlang 3
inter_list = redis.sinter("tag.web", "tag:ruby")
inter_list = redis.sdiff("tag.ruby", "tag:web")
inter_list = redis.sunion("tag.ruby", "tag:web")
]]>
#
注意单位问题Q当需要设|内存大的时候,可以使用cM1k?GB?Mq样的常见格式:
#
#
1k => 1000 bytes
#
1kb => 1024 bytes
#
1m => 1000000 bytes
#
1mb => 1024*1024 bytes
#
1g => 1000000000 bytes
#
1gb => 1024*1024*1024 bytes
#
#
单位是大写不敏感的Q所?GB 1Gb 1gB的写法都是完全一L?/span>
#
Redis默认是不作ؓ守护q程来运行的。你可以把这个设|ؓ"yes"让它作ؓ守护q程来运行?/span>
#
注意Q当作ؓ守护q程的时候,Redis会把q程ID写到 /var/run/redis.pid
daemonize no
#
当以守护q程方式q行的时候,Redis会把q程ID默认写到 /var/run/redis.pid。你可以在这里修改\径?/span>
pidfile
/
var
/
run
/
redis.pid
#
接受q接的特定端口,默认?379?/span>
#
如果端口讄?QRedis׃会监听TCP套接字?/span>
port
6379
#
如果你想的话Q你可以l定单一接口Q如果这里没单独讄Q那么所有接口的q接都会被监听?/span>
#
#
bind 127.0.0.1
#
指定用来监听q接的unxi套接字的路径。这个没有默认|所以如果你不指定的话,Redis׃会通过unix套接字来监听?/span>
#
#
unixsocket /tmp/redis.sock
#
unixsocketperm 755
#
一个客LI闲多少U后关闭q接?0代表用Q永不关?
timeout 0
#
讄服务器调试等U?/span>
#
可能|
#
debug Q很多信息,对开?试有用Q?/span>
#
verbose Q很多精的有用信息,但是不像debug{那么多)
#
notice Q适量的信息,基本上是你生产环境中需要的E度Q?/span>
#
warning Q只有很重要/严重的信息会记录下来Q?/span>
loglevel verbose
#
指明日志文g名。也可以使用"stdout"来强制让Redis把日志信息写到标准输Z?/span>
#
注意Q如果Redis以守护进E方式运行,而你讄日志昄到标准输出的话,那么日志会发送到 /dev/null
logfile stdout
#
要用系l日志记录器很简单,只要讄 "syslog-enabled" 为?yes" 可以了?/span>
#
然后Ҏ需要设|其他一些syslog参数可以了?/span>
#
syslog-enabled no
#
指明syslogw䆾
#
syslog-ident redis
#
指明syslog的设备。必L一个用h者是 LOCAL0 ~ LOCAL7 之一?/span>
#
syslog-facility local0
#
讄数据库个数。默认数据库是 DB 0Q你可以通过SELECT <dbid> WHERE dbidQ??databases' - 1Q来为每个连接用不同的数据库?/span>
databases
16
#
############################### 快照 #################################
#
#
把数据库存到盘?
#
#
save <seconds> <changes>
#
#
会在指定U数和数据变化次C后把数据库写到磁盘上?/span>
#
#
下面的例子将会进行把数据写入盘的操?
#
900U(15分钟Q之后,且至?ơ变?/span>
#
300U(5分钟Q之后,且至?0ơ变?/span>
#
60U之后,且至?0000ơ变?/span>
#
#
注意Q你要想不写盘的话把所有?save" 讄注释掉就行了?/span>
save
900
1
save
300
10
save
60
10000
#
当导出到 .rdb 数据库时是否用LZF压羃字符串对象?/span>
#
默认讄为?yes"Q所以几乎L生效的?/span>
#
如果你想节省CPU的话你可以把q个讄为?no"Q但是如果你有可压羃的key的话Q那数据文g׃更大了?/span>
rdbcompression yes
#
数据库的文g?/span>
dbfilename dump.rdb
#
工作目录
#
#
数据库会写到q个目录下,文g名就是上面的 "dbfilename" 的倹{?/span>
#
#
累加文g也放q里?/span>
#
#
注意你这里指定的必须是目录,不是文g名?/span>
dir .
/
#
################################ 同步 #################################
#
#
M同步。通过 slaveof 配置来实现Redis实例的备份?/span>
#
注意Q这里是本地从远端复制数据。也是_本地可以有不同的数据库文件、绑定不同的IP、监听不同的端口?/span>
#
#
slaveof <masterip> <masterport>
#
如果master讄了密码(通过下面的?requirepass" 选项来配|)Q那么slave在开始同步之前必进行n份验证,否则它的同步h会被拒绝?/span>
#
#
masterauth <master-password>
#
当一个slave失去和master的连接,或者同步正在进行中Qslave的行为有两种可能Q?/span>
#
#
1) 如果 slave-serve-stale-data 讄为?yes" (默认?Qslave会l响应客LhQ可能是正常数据Q也可能是还没获得值的I数据?/span>
#
2) 如果 slave-serve-stale-data 讄为?no"Qslave会回?正在从master同步QSYNC with master in progressQ?来处理各U请求,除了 INFO 和 SLAVEOF 命o?/span>
#
slave
-
serve
-
stale
-
data yes
#
slaveҎ指定的时间间隔向服务器发送pingh?/span>
#
旉间隔可以通过 repl_ping_slave_period 来设|?/span>
#
默认10U?/span>
#
#
repl-ping-slave-period 10
#
下面的选项讄了大块数据I/O、向masterh数据和ping响应的过期时间?/span>
#
默认?0U?/span>
#
#
一个很重要的事情是Q确保这个值比 repl-ping-slave-period 大,否则master和slave之间的传输过期时间比预想的要短?/span>
#
#
repl-timeout 60
#
################################# 安全 ###################################
#
要求客户端在处理M命o旉要验证n份和密码?/span>
#
q在你信不过来访者时很有用?/span>
#
#
Z向后兼容的话Q这D应该注释掉。而且大多Ch不需要n份验证(例如Q它们运行在自己的服务器上。)
#
#
警告Q因为Redis太快了,所以居心不良的人可以每U尝?50k的密码来试图破解密码?/span>
#
q意味着你需要一个高强度的密码,否则破解太容易了?/span>
#
#
requirepass foobared
#
命o重命?/span>
#
#
在共享环境下Q可以ؓ危险命o改变名字。比如,你可以ؓ CONFIG 改个其他不太Ҏ猜到的名字,q样你自׃然可以用,而别人却没法做坏事了?/span>
#
#
例如:
#
#
rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
#
甚至也可以通过l命令赋g个空字符串来完全用q条命oQ?/span>
#
#
rename-command CONFIG ""
#
################################## 限制 ####################################
#
#
讄最多同时连接客L数量?/span>
#
默认没有限制Q这个关pdRedisq程能够打开的文件描q符数量?/span>
#
Ҏ?0"表示没有限制?/span>
#
一旦达到这个限ӞRedis会关闭所有新q接q发送错?辑ֈ最大用h上限Qmax number of clients reachedQ?
#
#
maxclients 128
#
不要用比讄的上限更多的内存。一旦内存用达C限,Redis会根据选定的回收策略(参见Qmaxmemmory-policyQ删除key?/span>
#
#
如果因ؓ删除{略问题Redis无法删除keyQ或者策略设|ؓ "noeviction"QRedis会回复需要更多内存的错误信息l命令?/span>
#
例如QSET,LPUSH{等。但是会l箋合理响应只读命oQ比如:GET?/span>
#
#
在用Redis作ؓLRU~存Q或者ؓ实例讄了硬性内存限制的时候(使用 "noeviction" {略Q的时候,q个选项q是满有用的?/span>
#
#
警告Q当一堆slaveq上辑ֈ内存上限的实例的时候,响应slave需要的输出~存所需内存不计在使用内存当中?/span>
#
q样当请求一个删除掉的key的时候就不会触发|络问题Q重新同步的事gQ然后slave׃收到一堆删除指令,直到数据库空了ؓ止?/span>
#
#
而言之,如果你有slaveq上一个master的话Q那你把master内存限制讑ְ点儿Q确保有_的系l内存用作输出缓存?/span>
#
Q如果策略设|ؓ"noeviction"的话׃无所谓了Q?/span>
#
#
maxmemory <bytes>
#
内存{略Q如果达到内存限制了QRedis如何删除key。你可以在下面五个策略里面选:
#
#
volatile-lru -> ҎLRU法生成的过期时间来删除?/span>
#
allkeys-lru -> ҎLRU法删除Mkey?/span>
#
volatile-random -> Ҏq期讄来随机删除key?/span>
#
allkeys->random -> 无差别随机删?/span>
#
volatile-ttl -> Ҏ最q过期时间来删除Q辅以TTLQ?/span>
#
noeviction -> 谁也不删Q直接在写操作时q回错误?/span>
#
#
注意Q对所有策略来_如果Redis找不到合适的可以删除的key都会在写操作时返回一个错误?/span>
#
#
q里涉及的命令:set setnx setex append
#
incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
#
sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
#
zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
#
getset mset msetnx exec sort
#
#
默认值如下:
#
#
maxmemory-policy volatile-lru
#
LRU和最TTL法的实现都不是很精,但是很接q(Z省内存)Q所以你可以用样例做试?/span>
#
例如Q默认Redis会检查三个key然后取最旧的那个Q你可以通过下面的配|项来设|样本的个数?/span>
#
#
maxmemory-samples 3
#
############################# U篏加模式?##############################
#
默认情况下,Redis是异步的把数据导出到盘上。这U情况下Q当Redis挂掉的时候,最新的数据׃了?/span>
#
如果不希望丢掉Q何一条数据的话就该用U篏加模式:一旦开启这个模式,Redis会把每次写入的数据在接收后都写入 appendonly.aof 文g?/span>
#
每次启动时Redis都会把这个文件的数据d内存里?/span>
#
#
注意Q异步导出的数据库文件和U篏加文件可以ƈ存(你得把上面所?save"讄都注释掉Q关掉导出机Ӟ?/span>
#
如果U篏加模式开启了Q那么Redis会在启动时蝲入日志文件而忽略导出的 dump.rdb 文g?/span>
#
#
重要Q查看 BGREWRITEAOF 来了解当累加日志文g太大了之后,怎么在后台重新处理这个日志文件?/span>
appendonly no
#
U篏加文件名字(默认Q?appendonly.aof"Q?/span>
#
appendfilename appendonly.aof
#
fsync() h操作pȝ马上把数据写到磁盘上Q不要再{了?/span>
#
有些操作pȝ会真的把数据马上刷到盘上;有些则要蹭一下,但是会尽快去做?/span>
#
#
Redis支持三种不同的模式:
#
#
noQ不要立dQ只有在操作pȝ需要刷的时候再列比较快?/span>
#
alwaysQ每ơ写操作都立d入到aof文g。慢Q但是最安全?/span>
#
everysecQ每U写一ơ。折h案?/span>
#
#
默认的?everysec" 通常来说能在速度和数据安全性之间取得比较好的^衡?/span>
#
如果你真的理解了q个意味着什么,那么讄"no"可以获得更好的性能表现Q如果丢数据的话Q则只能拿到一个不是很新的快照Q;
#
或者相反的Q你选择 "always" 来牺牲速度保数据安全、完整?/span>
#
#
如果拿不准,q "everysec"
#
appendfsync always
appendfsync everysec
#
appendfsync no
#
如果AOF的同步策略设|成 "always" 或者?everysec"Q那么后台的存储q程Q后台存储或写入AOF日志Q会产生很多盘I/O开销?/span>
#
某些Linux的配|下会Redis因ؓ fsync() 而阻塞很久?/span>
#
注意Q目前对q个情况q没有完修正,甚至不同U程的 fsync() 会阻塞我们的 write(2) h?/span>
#
#
Z~解q个问题Q可以用下面q个选项。它可以在 BGSAVE 或 BGREWRITEAOF 处理旉止 fsync()?/span>
#
#
q就意味着如果有子q程在进行保存操作,那么Redis处?不可同步"的状态?/span>
#
q实际上是说Q在最差的情况下可能会丢掉30U钟的日志数据。(默认Linux讑֮Q?/span>
#
#
如果你有延迟的问题那把q个设ؓ "yes"Q否则就保持 "no"Q这是保存持久数据的最安全的方式?/span>
no
-
appendfsync
-
on
-
rewrite no
#
自动重写AOF文g
#
#
如果AOF日志文g大到指定癑ֈ比,Redis能够通过 BGREWRITEAOF 自动重写AOF日志文g?/span>
#
#
工作原理QRedisC上次重写时AOF日志的大(或者重启后没有写操作的话,那就直接用此时的AOF文gQ,
#
基准寸和当前尺寸做比较。如果当前尺寸超q指定比例,׃触发重写操作?/span>
#
#
你还需要指定被重写日志的最尺寸,q样避免了达到约定百分比但尺总然很的情况q要重写?/span>
#
#
指定癑ֈ比ؓ0会禁用AOF自动重写Ҏ?/span>
auto
-
aof
-
rewrite
-
percentage
100
auto
-
aof
-
rewrite
-
min
-
size 64mb
#
################################# 慢查询日志?##################################
#
Redis慢查询日志可以记录超q指定时间的查询。运行时间不包括各种I/O旉?/span>
#
例如Q连接客LQ发送响应数据等。只计算命oq行的实际时_q是唯一一U命令运行线E阻塞而无法同时ؓ其他h服务的场景)
#
#
你可以ؓ慢查询日志配|两个参敎ͼ一个是标旉Q单位ؓ微妙Q记录超q个旉的命令?/span>
#
另一个是慢查询日志长度。当一个新的命令被写进日志的时候,最老的那个记录会被删掉?/span>
#
#
下面的时间单位是微秒Q所?000000是1U。注意,负数旉会禁用慢查询日志Q?则会强制记录所有命令?/span>
slowlog
-
log
-
slower
-
than
10000
#
q个长度没有限制。只要有_的内存就行。你可以通过 SLOWLOG RESET 来释攑ֆ存。(译者注Q日志居然是在内存里的OrzQ?/span>
slowlog
-
max
-
len
128
#
############################### 虚拟内存 ###############################
#
## 警告Q虚拟内存在Redis 2.4是反对的?/span>
#
## 非常不鼓׃用虚拟内存!Q?/span>
#
虚拟内存可以使Redis在内存不够的情况下仍然可以将所有数据序列保存在内存里?/span>
#
Z做到q一点,高频key会调到内存里Q而低频key会{C换文仉Q就像操作系l用内存页一栗?/span>
#
#
要用虚拟内存,只要把?vm-enabled" 讄为?yes"QƈҎ需要设|下面三个虚拟内存参数就可以了?/span>
vm
-
enabled no
#
vm-enabled yes
#
q是交换文g的\径。估计你猜到了,交换文g不能在多个Redis实例之间׃nQ所以确保每个Redis实例使用一个独立交换文件?/span>
#
#
最好的保存交换文gQ被随机讉KQ的介质是固态硬盘(SSDQ?/span>
#
#
*** 警告 *** 如果你用共享主机,那么默认的交换文件放刊W?tmp 下是不安全的?/span>
#
创徏一个Redis用户可写的目录,q|Redis在这里创Z换文件?/span>
vm
-
swap
-
file
/
tmp
/
redis.swap
#
"vm-max-memory" 配置虚拟内存可用的最大内存容量?/span>
#
如果交换文gq有I间的话Q所有超标部分都会放C换文仉?/span>
#
#
"vm-max-memory" 讄?表示pȝ会用掉所有可用内存?/span>
#
q默认g咋地Q只是把你能用的内存全用掉了Q留点余量会更好?/span>
#
例如Q设|ؓ剩余内存?0%-80%?/span>
vm
-
max
-
memory 0
#
Redis交换文g是分成多个数据页的?/span>
#
一个可存储对象可以被保存在多个q箋里Q但是一个数据页无法被多个对象共享?/span>
#
所以,如果你的数据太大,那么对象就会浪Ҏ很多I间?/span>
#
如果数据太,那用于存储的交换I间׃更少Q假定你讄相同的数据页数量Q?/span>
#
#
如果你用很多小对象Q徏议分尺ؓ64?2个字节?/span>
#
如果你用很多大对象Q那q大一些的寸?/span>
#
如果不确定,那就用默认值?)
vm
-
page
-
size
32
#
交换文g里数据页L?/span>
#
Ҏ内存中分表Q已?未用的数据页分布情况Q,盘上每8个数据页会消耗内存里1个字节?/span>
#
#
交换区容量? vm-page-size * vm-pages
#
#
Ҏ默认?2字节的数据页寸?34217728的数据页数来,Redis的数据页文g会占4GBQ而内存里的分表会消?6MB内存?/span>
#
#
Z的应验程序设|最且够用的数字比较好Q下面这个默认值在大多数情况下都是偏大的?/span>
vm
-
pages
134217728
#
同时可运行的虚拟内存I/OU程数?/span>
#
q些U程可以完成从交换文件进行数据读写的操作Q也可以处理数据在内存与盘间的交互和编?解码处理?/span>
#
多一些线E可以一定程度上提高处理效率Q虽然I/O操作本n依赖于物理设备的限制Q不会因为更多的U程而提高单ơ读写操作的效率?/span>
#
#
Ҏ?会关闭线EI/OQƈ会开启阻塞虚拟内存机制?/span>
vm
-
max
-
threads
4
#
############################## 高配置 ###############################
#
当有大量数据Ӟ适合用哈希编码(需要更多的内存Q,元素数量上限不能过l定限制?/span>
#
你可以通过下面的选项来设定这些限Ӟ
hash
-
max
-
zipmap
-
entries
512
hash
-
max
-
zipmap
-
value
64
#
与哈希相cMQ数据元素较的情况下,可以用另一U方式来~码从而节省大量空间?/span>
#
q种方式只有在符合下面限制的时候才可以用:
list
-
max
-
ziplist
-
entries
512
list
-
max
-
ziplist
-
value
64
#
q有q样一U特D编码的情况Q数据全?4位无W号整型数字构成的字W串?/span>
#
下面q个配置就是用来限制这U情况下使用q种~码的最大上限的?/span>
set
-
max
-
intset
-
entries
512
#
与第一、第二种情况怼Q有序序列也可以用一U特别的~码方式来处理,可节省大量空间?/span>
#
q种~码只适合长度和元素都W合下面限制的有序序列:
zset
-
max
-
ziplist
-
entries
128
zset
-
max
-
ziplist
-
value
64
#
哈希hQ每100个CPU毫秒会拿?个毫U来hRedis的主哈希表(键值映表Q?/span>
#
redis所用的哈希表实玎ͼ见dict.cQ采用gq哈希刷新机Ӟ你对一个哈希表操作多Q哈希刷新操作就频J;
#
反之Q如果服务器非常不活跃那么也是用点内存保存哈希表而已?/span>
#
#
默认是每U钟q行10ơ哈希表hQ用来刷新字典,然后快释放内存?/span>
#
#
Q?/span>
#
如果你对延迟比较在意的话q "activerehashing no"Q每个请求gq?毫秒不太好嘛?/span>
#
如果你不太在意gq而希望尽快释攑ֆ存的话就讄 "activerehashing yes"?/span>
activerehashing yes
#
################################# 包含 ###################################
#
包含一个或多个其他配置文g?/span>
#
q在你有标准配置模板但是每个redis服务器又需要个性设|的时候很有用?/span>
#
包含文gҎ允怽引h其他配置文gQ所以好好利用吧?/span>
#
#
include /path/to/local.conf
#
include /path/to/other.conf
]]>
启动jvm监控服务。它是一个基于rmi的应用,向远E机器提供本机jvm应用E序的信息。默认端?099?br />实例Qjstatd -J-Djava.security.policy=my.policy
my.policy文g需要自己徏立,内如如下Q?br />grant codebase "file:$JAVA_HOME/lib/tools.jar" {
permission java.security.AllPermission;
};
q是安全{略文gQ因为jdk对jvm做了jaas的安全检,所以我们必设|一些策略,使得jstatd被允怽|络操作
jps
列出所有的jvm实例
实例Q?br />jps
列出本机所有的jvm实例
jps 192.168.0.77
列出q程服务?92.168.0.77机器所有的jvm实例Q采用rmi协议Q默认连接端口ؓ1099
Q前提是q程服务器提供jstatd服务Q?br />
输出内容如下Q?br />jones@jones:~/data/ebook/java/j2se/jdk_gc$ jps
6286 Jps
6174 Jstat
jconsole
一个图形化界面Q可以观察到javaq程的gcQclassQ内存等信息。虽然比较直观,但是个hq是比较們于用jstat命oQ在最后一部分会对jstat作详l的介绍Q?br />
jinfoQlinux下特有)
观察q行中的javaE序的运行环境参敎ͼ参数包括Java System属性和JVM命o行参?br />实例Qjinfo 2083
其中2083是javaq程idP可以用jps得到q个id受?br />输出内容太多了,不在q里一一列DQ大家可以自己尝试这个命令?br />
jstackQlinux下特有)
可以观察到jvm中当前所有线E的q行情况和线E当前状?br />jstack 2083
输出内容如下Q?br />
jmapQlinux下特有,也是很常用的一个命令)
观察q行中的jvm物理内存的占用情c?br />参数如下Q?strong>
-heapQ打印jvm heap的情?br />-histoQ?/strong>打印jvm heap的直方图。其输出信息包括cdQ对象数量,对象占用大小?br />-histoQlive Q?/strong>同上Q但是只{应存活对象的情?br />-permstatQ?/strong>打印permanent generation heap情况
命o使用Q?br />jmap -heap 2083
可以观察到New GenerationQEden SpaceQFrom SpaceQTo SpaceQ?tenured generation,Perm Generation的内存用情?br />输出内容Q?br />
jmap -histo 2083 ?jmap -histo:live 2083
可以观察heap中所有对象的情况Qheap中所有生存的对象的情况)。包括对象数量和所占空间大?br />输出内容Q?br />
写个脚本Q可以很快把占用heap最大的对象扑և来,对付内存泄漏特别有效?br />
jstat
最后要重点介绍下这个命令?br />q是jdk命o中比较重要,也是相当实用的一个命令,可以观察到classloaderQcompilerQgc相关信息
具体参数如下Q?br />-classQ统计class loader行ؓ信息
-compileQ统计编译行Z?br />-gcQ统计jdk gc时heap信息
-gccapacityQ统计不同的generationsQ不知道怎么译好,包括新生区,老年区,permanent区)相应的heap定w情况
-gccauseQ统计gc的情况,Q同-gcutilQ和引vgc的事?br />-gcnewQ统计gcӞ新生代的情况
-gcnewcapacityQ统计gcӞ新生代heap定w
-gcoldQ统计gcӞ老年区的情况
-gcoldcapacityQ统计gcӞ老年区heap定w
-gcpermcapacityQ统计gcӞpermanent区heap定w
-gcutilQ统计gcӞheap情况
-printcompilationQ不知道q什么的Q一直没用过?br />
一般比较常用的几个参数是:
jstat -class 2083 1000 10 Q每?U监控一ơ,一共做10ơ)
输出内容含义如下Q?br />Loaded Number of classes loaded. Bytes Number of Kbytes loaded. Unloaded Number of classes unloaded. Bytes Number of Kbytes unloaded. Time Time spent performing class load and unload operations.
jstat -gc 2083 2000 20Q每?U监控一ơ,共做10Q?br />输出内容含义如下Q?br />S0C Current survivor space 0 capacity (KB). EC Current eden space capacity (KB). EU Eden space utilization (KB). OC Current old space capacity (KB). OU Old space utilization (KB). PC Current permanent space capacity (KB). PU Permanent space utilization (KB). YGC Number of young generation GC Events. YGCT Young generation garbage collection time. FGC Number of full GC events. FGCT Full garbage collection time. GCT Total garbage collection time.
输出内容Q?br />
如果能熟l运用这些命令,其是在linux下,那么完全可以代替jprofile{监控工具了Q谁让它收费呢。呵c?br />用命令的好处是速度快,q且辅助于其他命令,比如grep gawk sed{,可以l装多种W合自己需求的工具?
]]>
青山依旧在,
几度夕阳U?br />
白发渔樵江渚上,
惯看U月春风?br />一壶浊酒喜盔R,
古今多少事,
都付W谈中?br />
又一兄弟要离开了,怎么说呢。百感交集~~~
或许人都有更高的q求吧?br />
呜呼~~
]]>
千里之行Q始于下,千里之堤Q毁于蚁I_做好设计的第一步就是写好你的代码,博文8 Signs your code sucksȝ了代码中W一个感觉的臭味Q让你能够于l微之处发现软g的质量问题?br />
1.Ҏ内代码超q一个电脑屏q:
一个方法只应该执行特定的Q务,一个方法不应该包含一些这L逻辑Q例如判断用户名字段包哈巴的数据是否有效Q是否存在等。如果一个方法代码大得超q一个屏q,那么q是表明它做了太多的事情Q需要切分?br />
2.你在重用变量Q?br />除非你工作于嵌入式领域,否则内存是便宜的Q不要做内存的守财奴Q要注重可维护性?br />
3.你直接访问request/session Q?br />q和具体应用服务器环境绑定,难于试Q所有应用数据应该直接解耦Session/requestQ保存到Bean中,通过 bean?getters ?settersҎ, 创徏使用者访问数据的合约Q这大大帮助代码的可维护性,个h补充Q不要把cM的Collection字段直接通过Collection getCollection来暴露给外界Q通过Ҏ装对Collection的操作?br />
4.你需要用注解来解释代码如何使用Q?br />代码应该自己能够解释它如何用,易于可读Q如果你发现你自己都需要注解专门解释如何用,那么p重构你的代码。这里注解不是指javadoc{必要文档?br />
5.一个exceptionpd错误没有q回最原始的错误:
你不应该吃掉exception错误Q在catch一个exceptionӞ要打印出其出错tack trace. 如果不知道错误来源,如何U正错误呢?
6.你的代码是一堆惔球:
代码_在一PZ没有分离分层Q代码应该是模块化,q样易于l护和重用?MVC是关注用户View视图界面发生的事情,控制器是xE序程和数据的校验Q而处理业务逻辑是领域模型的事情Q只有模型可以和数据库访问直接进行交互?br />
7.难于单元试
如果你发现BugQ那么些一D|的代码片D,它会花去你一些时_但是q样代码p处理更加复杂的事情了?/span>
]]>
]]>
]]>
]]>
1
、以下哪条语句会产生q行错误Q(
Q?/span>
A.var obj = ();//
语法错误
B.var obj = [];//
创徏数组
C.var obj = {};//
创徏对象
D.var obj = //;
2、以下哪个单词不属于javascript保留字:Q?/span>Q?/span>
A.with
B.parent
C.class
D.void
3、请选择l果为真的表辑ּQ(Q?/span>
A.null instanceof ObjectQ?/span>(!(nullinstanceof Object))Q?/span>
B.null === undefined
C.null == undefined
D.NaN == NaN
二、不定项选择?/span>
4、请选择?/span>javascript理解有误的:()
A.JScript?/span>javascript的简U?/span>
B.javascript是网景公司开发的一U?/span>Java脚本语言Q其目的是ؓ了简?/span>Java的开发难?/span>
C.FireFox?/span>IE存在大量兼容性问题的主要原因在于他们?/span>javascript的支持不同上
D.AJAX技术一定要使用javascript技?/span>
5?/span>foo对象?/span>att属性,那么获取att属性的|以下哪些做法是可以的Q(Q?/span>
A.foo.att
B.foo(“att?
C.foo[“att”]
D.foo{“att”}
E.foo[“a?”t?”t”]
6、在不指定特D属性的情况下,哪几U?/span>HTML标签可以手动输入文本Q(Q?/span>
A.<TEXTAREA></TEXTAREA>
B.<INPUT type=”text?>
C.<INPUT type=”hidden?>
D.<DIV></DIV>
7、以下哪些是javascript的全局函数Q(Q?/span>
A.escape
B.parseFloat
C.eval
D.setTimeout
E.alert
8、关?/span>IFrame表述正确的有Q?/span>()
A.通过IFrameQ网可以嵌入其他网内容,q可以动态更?/span>
B.在相同域名下Q内嵌的IFrame可以获取外层|页的对?/span>
C.在相同域名下Q外层网脚本可以获?/span>IFrame|页内的对象
D.可以通过脚本调整IFrame的大?/span>
9、关于表Dq正的有:Q?/span>Q?/span>
A.表格中可以包?/span>TBODY元素
B.表格中可以包?/span>CAPTION元素
C.表格中可以包含多?/span>TBODY元素
D.表格中可以包?/span>COLGROUP元素
E.表格中可以包?/span>COL元素
10、关?/span>IE?/span>window对象表述正确的有Q(Q?/span>
A.window.opener属性本w就是指?/span>window对象
B.window.reload()Ҏ可以用来h当前面
C.window.location=”a.html?/span>?/span>window.location.href=”a.html?/span>的作用都是把当前面替换?/span>a.html面
D.定义了全局变量gQ可以用window.g的方式来存取该变?/span>
三、问{题Q?/span>
1、谈?/span>javascript数组排序Ҏsort()的用,重点介绍sort()参数的用及其内部机?br />2、简q?/span>DIV元素?/span>SPAN元素的区别?br />3、结?/span>textq段l构Q谈?/span>innerHTML outerHTML innerText之间的区别?br />4、说几条XHTML规范的内容(臛_3条)
5、对Web标准化(或网站重构)知道哪些相关的知识,q几条你知道?/span>Web标准Q?br />四、程序题Q?/span>
1、完?/span>foo()函数的内容,要求能够弹出对话框提C当前选中的是W几个单选框?/span>
(1)非静态对象的初始?/p>
在创建对象时Q对象所在类的所有数据成员会首先q行初始化?/p>
基本cdQ?a class="bluekey" target="_blank">int型,初始化ؓ0?/p>
如果为对象:q些对象会按序初始化?/p>
d所有类成员初始化完成之后,才调用本cȝ构造方法创建对象?/p>
构造方法的作用是初始化?/p>
(2)静态对象的初始?/p>
E序中主cȝ静态变量会在mainҎ执行前初始化?/p>
不仅W一ơ创建对象时Q类中的所有静态变量都初始化,q且W一ơ访问某c?注意此时未创建此cd?的静态对象时Q所有的静态变量也要按它们在类中的序初始化?/p>
2、承时Q对象的初始化过E?
(1)ȝ的超cȝ高到低按序初始化静态成员,无论静态成员是否ؓprivate?/p>
(2)ȝ静态成员的初始化?/p>
(3)ȝ的超cȝ高到低进行默认构造方法的调用。注意,在调用每一个超cȝ默认构造方法前Q先q行Ҏ类q行非静态对象的初始化?/p>
(4)ȝ非静态成员的初始化?/p>
(5)调用ȝ的构造方法?/p>
3、关于构造方?/font>
(1)cd以没有构造方法,但如果有多个构造方法,应该要有默认的构造方法,否则在承此cLQ需要在子类中显式调用父cȝ某一个非默认的构造方法了?/p>
(2)在一个构造方法中Q只能调用一ơ其他的构造方法,q且调用构造方法的语句必须是第一条语句?/p>
4、有关public、private和protected
(1)无public修饰的类Q可以被其他c访问的条g是:a.两个cd同一文g中,b.两个cd同一文g夹中Qc.两个cd同一软g包中?/p>
(2)protectedQ承类和同一软g包的cd讉K?/p>
(3)如果构造方法ؓprivateQ那么在其他cM不能创徏该类的对象?br />
5、抽象类
(1)抽象cM能创建对象?/p>
(2)如果一个类中一个方法ؓ抽象ҎQ则q个cdMؓabstract抽象cR?/p>
(3)l承抽象cȝcdcM必须实现抽象cM的抽象方法?/p>
(4)抽象cM可以有抽象方法,也可有非抽象Ҏ。抽象方法不能ؓprivate?/p>
(5)间接l承抽象cȝcd以不l出抽象Ҏ的定义?/p>
6、final关键?/font>
(1)一个对象是帔RQ不代表不能转变对象的成员,仍可以其成员q行操作?/p>
(2)帔R在用前必须赋|但除了在声明的同时初始化外,只能在构造方法中初始化?/p>
(3)final修饰的方法不能被重置(在子cM不能出现同名Ҏ)?/p>
(4)如果声明一个类为finalQ则所有的Ҏ均ؓfinalQ无论其是否被final修饰Q但数据成员可ؓfinal也可不是?/p>
7、接?/font>interface(用implements来实现接?
(1)接口中的所有数据均为static和final即静态常量。尽可以不用这两个关键字修饎ͼ但必ȝ帔R赋初倹{?/p>
(2)接口中的Ҏ均ؓpublicQ在实现接口cMQ实现方法必dpublic关键字?/p>
(3)如果使用public来修饰接口,则接口必M文g名相同?/p>
8、多重?
(1)一个类l承了一个类和接口,那么必须类写在前面Q接口写在后面,接口之间用逗号分隔?/p>
(2)接口之间可多重承,注意使用关键字extends?/p>
(3)一个类虽只实现了一个接口,但不仅要实现q个接口的所有方法,q要实现q个接口l承的接口的ҎQ接口中的所有方法均dcM实现?/p>
9、接口的嵌入
(1)接口嵌入cMQ可以用private修饰。此Ӟ接口只能在所在的cM实现Q其他类不能讉K?/p>
(2)嵌入接口中的接口一定要为public?
10、类的嵌?/font>
(1)cd以嵌入另一个类中,但不能嵌入接口中?/p>
}
(2)在静态方法或其他Ҏ中,不能直接创徏内部cd象,需通过手段来取得?/p>
手段有两U:
class A { class B {} B getB() { B b = new B(); return b; } } static void m() { A a = new A(); A.B ab = a.getB(); // 或者是 A.B ab = a.new B(); }
(3)一个类l承了另一个类的内部类Q因cL内部c,而内部类的构造方法不能自动被调用Q这样就需要在子类的构造方法中明确的调用超cȝ构造方法。接上例Q?/p>
class C extends A.B { C() { new A().super(); // q一句就实现了对内部cL造方法的调用?} }
构造方法也可这样写Q?/p>
C(A a) { a.super(); } // 使用q个构造方法创建对象,要写成C c = new C(a); a是A的对象?/p>
11、异常类JAVA中除了RunTimeExceptionc,其他异常均须捕获或抛出?/p>