ivaneeo's blog

自由的力量,自由的生活。

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

#

本文有标题党之嫌。在NoSQL如日中天的今天,各种NoSQL产品可谓百花齐放,但每一个产品都有自己的特点,有长处也有不适合的场景。本文对CassandraMongodbCouchDBRedisRiak 以及 HBase 进行了多方面的特点分析,希望看完此文的您能够对这些NoSQL产品的特性有所了解。

CouchDB

  • Written in: Erlang
  • Main point: DB consistency, ease of use
  • License: Apache
  • Protocol: HTTP/REST
  • Bi-directional (!) replication,
  • continuous or ad-hoc,
  • with conflict detection,
  • thus, master-master replication. (!)
  • MVCC – write operations do not block reads
  • Previous versions of documents are available
  • Crash-only (reliable) design
  • Needs compacting from time to time
  • Views: embedded map/reduce
  • Formatting views: lists & shows
  • Server-side document validation possible
  • Authentication possible
  • Real-time updates via _changes (!)
  • Attachment handling
  • thus, CouchApps (standalone js apps)
  • jQuery library included

Best used: For accumulating, occasionally changing data, on which pre-defined queries are to be run. Places where versioning is important.

For example: CRM, CMS systems. Master-master replication is an especially interesting feature, allowing easy multi-site deployments.

Redis

  • Written in: C/C++
  • Main point: Blazing fast
  • License: BSD
  • Protocol: Telnet-like
  • Disk-backed in-memory database,
  • but since 2.0, it can swap to disk.
  • Master-slave replication
  • Simple keys and values,
  • but complex operations like ZREVRANGEBYSCORE
  • INCR & co (good for rate limiting or statistics)
  • Has sets (also union/diff/inter)
  • Has lists (also a queue; blocking pop)
  • Has hashes (objects of multiple fields)
  • Of all these databases, only Redis does transactions (!)
  • Values can be set to expire (as in a cache)
  • Sorted sets (high score table, good for range queries)
  • Pub/Sub and WATCH on data changes (!)

Best used: For rapidly changing data with a foreseeable database size (should fit mostly in memory).

For example: Stock prices. Analytics. Real-time data collection. Real-time communication.

MongoDB

  • Written in: C++
  • Main point: Retains some friendly properties of SQL. (Query, index)
  • License: AGPL (Drivers: Apache)
  • Protocol: Custom, binary (BSON)
  • Master/slave replication
  • Queries are javascript expressions
  • Run arbitrary javascript functions server-side
  • Better update-in-place than CouchDB
  • Sharding built-in
  • Uses memory mapped files for data storage
  • Performance over features
  • After crash, it needs to repair tables
  • Better durablity coming in V1.8

Best used: If you need dynamic queries. If you prefer to define indexes, not map/reduce functions. If you need good performance on a big DB. If you wanted CouchDB, but your data changes too much, filling up disks.

For example: For all things that you would do with MySQL or PostgreSQL, but having predefined columns really holds you back.

Cassandra

  • Written in: Java
  • Main point: Best of BigTable and Dynamo
  • License: Apache
  • Protocol: Custom, binary (Thrift)
  • Tunable trade-offs for distribution and replication (N, R, W)
  • Querying by column, range of keys
  • BigTable-like features: columns, column families
  • Writes are much faster than reads (!)
  • Map/reduce possible with Apache Hadoop
  • I admit being a bit biased against it, because of the bloat and complexity it has partly because of Java (configuration, seeing exceptions, etc)

Best used: When you write more than you read (logging). If every component of the system must be in Java. (“No one gets fired for choosing Apache’s stuff.”)

For example: Banking, financial industry (though not necessarily for financial transactions, but these industries are much bigger than that.) Writes are faster than reads, so one natural niche is real time data analysis.

Riak

  • Written in: Erlang & C, some Javascript
  • Main point: Fault tolerance
  • License: Apache
  • Protocol: HTTP/REST
  • Tunable trade-offs for distribution and replication (N, R, W)
  • Pre- and post-commit hooks,
  • for validation and security.
  • Built-in full-text search
  • Map/reduce in javascript or Erlang
  • Comes in “open source” and “enterprise” editions

Best used: If you want something Cassandra-like (Dynamo-like), but no way you’re gonna deal with the bloat and complexity. If you need very good single-site scalability, availability and fault-tolerance, but you’re ready to pay for multi-site replication.

For example: Point-of-sales data collection. Factory control systems. Places where even seconds of downtime hurt.

HBase

  • Written in: Java
  • Main point: Billions of rows X millions of columns
  • License: Apache
  • Protocol: HTTP/REST (also Thrift)
  • Modeled after BigTable
  • Map/reduce with Hadoop
  • Query predicate push down via server side scan and get filters
  • Optimizations for real time queries
  • A high performance Thrift gateway
  • HTTP supports XML, Protobuf, and binary
  • Cascading, hive, and pig source and sink modules
  • Jruby-based (JIRB) shell
  • No single point of failure
  • Rolling restart for configuration changes and minor upgrades
  • Random access performance is like MySQL

Best used: If you’re in love with BigTable. :) And when you need random, realtime read/write access to your Big Data.

For example: Facebook Messaging Database (more general example coming soon)

原文链接:Cassandra vs MongoDB vs CouchDB vs Redis vs Riak vs HBase comparison

posted @ 2011-07-05 15:11 ivaneeo 阅读(1250) | 评论 (0)编辑 收藏

xStream性能不高,参考
https://github.com/eishay/jvm-serializers/wiki
如果纯java场景应用,可以参考kryo
如果需要跨语言,可以参考ProtoBuf
posted @ 2011-07-01 23:33 ivaneeo 阅读(324) | 评论 (0)编辑 收藏

如果有不明白的地方或者陌生的端口可以在这里查到。以便于检查系统是否感染病毒或木马。但是在有防火墙的情况下,一般的防火墙都是严格审核程序的网络连接 的,所以会预先封闭所有的端口,有需要访问网络的程序会预先向防火墙提出申请,防火墙做出响应,并弹出提示,要求用户做出选择,这时候我们就要认真看了, 是哪一个程序,在文件夹的哪一个位置,要做一个估计,陌生程序就更要检查。这样才能不给恶意程序任何余地。同时系统自动升级最好打开,或者定期到 windows的微软网站下载系统更新程序,这样也非常有利于系统安全。系统漏洞可能会使恶意程序通过系统漏洞绕过防火墙连接到网络。

端口:1
服务:tcpmux
说 明:这显示有人在寻找sgi irix机器。irix是实现tcpmux的主要提供者,默认情况下tcpmux在这种系统中被打开。irix机器在发布是含有几个默认的无密码的帐户, 如:ip、guest uucp、nuucp、demos 、tutor、diag、outofbox等。许多管理员在安装后忘记删除这些帐户。因此hacker在internet上搜索tcpmux并利用这些帐 户。

端口:7
服务:echo
说明:能看到许多人搜索fraggle放大器时,发送到x.x.x.0和x.x.x.255的信息。

端口:19
服务:character generator
说 明:这是一种仅仅发送字符的服务。udp版本将会在收到udp包后回应含有**字符的包。tcp连接时会发送含有**字符的数据流直到连接关闭。 hacker利用ip欺骗可以发动dos攻击。伪造两个chargen服务器之间的udp包。同样fraggle dos攻击向目标地址的这个端口广播一个带有伪造受害者ip的数据包,受害者为了回应这些数据而过载。

端口:21
服务:ftp
说 明:ftp服务器所开放的端口,用于上传、下载。最常见的攻击者用于寻找打开anonymous的ftp服务器的方法。这些服务器带有可读写的目录。木马 doly trojan、fore、invisible ftp、webex、wincrash和blade runner所开放的端口。

端口:22
服务:ssh
说明:pcanywhere建立的tcp和这一端口的连接可能是为了寻找ssh。这一服务有许多弱点,如果配置成特定的模式,许多使用rsaref库的版本就会有不少的漏洞存在。

端口:23
服务:telnet
说明:远程登录,入侵者在搜索远程登录unix的服务。大多数情况下扫描这一端口是为了找到机器运行的操作系统。还有使用其他技术,入侵者也会找到密码。木马tiny telnet server就开放这个端口。

端口:25
服务:smtp
说 明:smtp服务器所开放的端口,用于发送邮件。入侵者寻找smtp服务器是为了传递他们的spam。入侵者的帐户被关闭,他们需要连接到高带宽的 e-mail服务器上,将简单的信息传递到不同的地址。木马antigen、email password sender、haebu coceda、shtrilitz stealth、winpc、winspy都开放这个端口。

端口:31
服务:msg authentication
说明:木马master paradise、hackers paradise开放此端口。

端口:42
服务:wins replication
说明:wins复制

端口:53
服务:domain name server(dns)
说明:dns服务器所开放的端口,入侵者可能是试图进行区域传递(tcp),欺骗dns(udp)或隐藏其他的通信。因此防火墙常常过滤或记录此端口。

端口:67
服务:bootstrap protocol server
说 明:通过dsl和cable modem的防火墙常会看见大量发送到广播地址255.255.255.255的数据。这些机器在向dhcp服务器请求一个地址。hacker常进入它 们,分配一个地址把自己作为局部路由器而发起大量中间人(man-in-middle)攻击。客户端向68端口广播请求配置,服务器向67端口广播回应请 求。这种回应使用广播是因为客户端还不知道可以发送的ip地址。

端口:69
服务:trival file transfer
说明:许多服务器与bootp一起提供这项服务,便于从系统下载启动代码。但是它们常常由于错误配置而使入侵者能从系统中窃取任何 文件。它们也可用于系统写入文件。

端口:79
服务:finger server
说明:入侵者用于获得用户信息,查询操作系统,探测已知的缓冲区溢出错误,回应从自己机器到其他机器finger扫描。

端口:80
服务:http
说明:用于网页浏览。木马executor开放此端口。

端口:99
服务:metagram relay
说明:后门程序ncx99开放此端口。

端口:102
服务:message transfer agent(mta)-x.400 over tcp/ip
说明:消息传输代理。

端口:109
服务:post office protocol -version3
说明:pop3服务器开放此端口,用于接收邮件,客户端访问服务器端的邮件服务。pop3服务有许多公认的弱点。关于用户名和密码交 换缓冲区溢出的弱点至少有20个,这意味着入侵者可以在真正登陆前进入系统。成功登陆后还有其他缓冲区溢出错误。

端口:110
服务:sun公司的rpc服务所有端口
说明:常见rpc服务有rpc.mountd、nfs、rpc.statd、rpc.csmd、rpc.ttybd、amd等

端口:113
服务:authentication service
说 明:这是一个许多计算机上运行的协议,用于鉴别tcp连接的用户。使用标准的这种服务可以获得许多计算机的信息。但是它可作为许多服务的记录器,尤其是 ftp、pop、imap、smtp和irc等服务。通常如果有许多客户通过防火墙访问这些服务,将会看到许多这个端口的连接请求。记住,如果阻断这个端 口客户端会感觉到在防火墙另一边与e-mail服务器的缓慢连接。许多防火墙支持tcp连接的阻断过程中发回rst。这将会停止缓慢的连接。

端口:119
服务:network news transfer protocol
说明:news新闻组传输协议,承载usenet通信。这个端口的连接通常是人们在寻找usenet服务器。多数isp限制,只有他们的客户才能访问他们的新闻组服务器。打开新闻组服务器将允许发/读任何人的帖子,访问被限制的新闻组服务器,匿名发帖或发送spam。

端口:135
服务:本地 service
说 明:microsoft在这个端口运行dce rpc end-point mapper为它的dcom服务。这与unix 111端口的功能很相似。使用dcom和rpc的服务利用计算机上的end-point mapper注册它们的位置。远端客户连接到计算机时,它们查找end-point mapper找到服务的位置。hacker扫描计算机的这个端口是为了找到这个计算机上运行exchange server吗?什么版本?还有些dos攻击直接针对这个端口。

端口:137、138、139
服务:netbios name service
说明:其中137、138是udp端口,当通过网上邻居传输文件时用这个端口。而139端口:通过这个端口进入的连接试图获得netbios/smb服务。这个协议被用于windows文件和打印机共享和samba。还有wins regisrtation也用它。

端口:143
服务:interim mail access protocol v2
说 明:和pop3的安全问题一样,许多imap服务器存在有缓冲区溢出漏洞。记住:一种linux蠕虫(admv0rm)会通过这个端口繁殖,因此许多这个 端口的扫描来自不知情的已经被感染的用户。当redhat在他们的linux发布版本中默认允许imap后,这些漏洞变的很流行。这一端口还被用于 imap2,但并不流行。

端口:161
服务:snmp
说明:snmp允许远程管理设备。所有配置和运行信息的储存 在数据库中,通过snmp可获得这些信息。许多管理员的错误配置将被暴露在internet。cackers将试图使用默认的密码public、 private访问系统。他们可能会试验所有可能的组合。snmp包可能会被错误的指向用户的网络。

端口:177
服务:x display manager control protocol
说明:许多入侵者通过它访问x-windows操作台,它同时需要打开6000端口。

端口:389
服务:ldap、ils
说明:轻型目录访问协议和netmeeting internet locator server共用这一端口。

端口:443
服务:https
说明:网页浏览端口,能提供加密和通过安全端口传输的另一种http。

端口:456
服务:【null】
说明:木马hackers paradise开放此端口。

端口:513
服务:login,remote login
说明:是从使用cable modem或dsl登陆到子网中的unix计算机发出的广播。这些人为入侵者进入他们的系统提供了信息。

端口:544
服务:【null】
说明:kerberos kshell

端口:548
服务:macintosh,file services(afp/ip)
说明:macintosh,文件服务。

端口:553
服务:corba iiop (udp)
说明:使用cable modem、dsl或vlan将会看到这个端口的广播。corba是一种面向对象的rpc系统。入侵者可以利用这些信息进入系统。

端口:555
服务:dsf
说明:木马phase1.0、stealth spy、inikiller开放此端口。

端口:568
服务:membership dpa
说明:成员资格 dpa。

端口:569
服务:membership msn
说明:成员资格 msn。

端口:635
服务:mountd
说 明:linux的mountd bug。这是扫描的一个流行bug。大多数对这个端口的扫描是基于udp的,但是基于tcp的mountd有所增加(mountd同时运行于两个端口)。 记住mountd可运行于任何端口(到底是哪个端口,需要在端口111做portmap查询),只是linux默认端口是635,就像nfs通常运行于 2049端口。

端口:636
服务:ldap
说明:ssl(secure sockets layer)

端口:666
服务:doom id software
说明:木马attack ftp、satanz backdoor开放此端口

端口:993
服务:imap
说明:ssl(secure sockets layer)

端口:1001、1011
服务:【null】
说明:木马silencer、webex开放1001端口。木马doly trojan开放1011端口。

端口:1024
服务:reserved
说 明:它是动态端口的开始,许多程序并不在乎用哪个端口连接网络,它们请求系统为它们分配下一个闲置端口。基于这一点分配从端口1024开始。这就是说第一 个向系统发出请求的会分配到1024端口。你可以重启机器,打开telnet,再打开一个窗口运行natstat -a 将会看到telnet被分配1024端口。还有sql session也用此端口和5000端口。

端口:1025、1033
服务:1025:network blackjack 1033:【null】
说明:木马netspy开放这2个端口。

端口:1080
服务:socks
说 明:这一协议以通道方式穿过防火墙,允许防火墙后面的人通过一个ip地址访问internet。理论上它应该只允许内部的通信向外到达internet。 但是由于错误的配置,它会允许位于防火墙外部的攻击穿过防火墙。wingate常会发生这种错误,在加入irc聊天室时常会看到这种情况。
端口:1170
服务:【null】
说明:木马streaming audio trojan、psyber stream server、voice开放此端口。

端口:1234、1243、6711、6776
服务:【null】
说明:木马subseven2.0、ultors trojan开放1234、6776端口。木马subseven1.0/1.9开放1243、6711、6776端口。

端口:1245
服务:【null】
说明:木马vodoo开放此端口。

端口:1433
服务:sql
说明:microsoft的sql服务开放的端口。

端口:1492
服务:stone-design-1
说明:木马ftp99cmp开放此端口。

端口:1500
服务:rpc client fixed port session queries
说明:rpc客户固定端口会话查询

端口:1503
服务:netmeeting t.120
说明:netmeeting t.120

端口:1524
服务:ingress
说 明:许多攻击脚本将安装一个后门shell于这个端口,尤其是针对sun系统中sendmail和rpc服务漏洞的脚本。如果刚安装了防火墙就看到在这个 端口上的连接企图,很可能是上述原因。可以试试telnet到用户的计算机上的这个端口,看看它是否会给你一个shell。连接到 600/pcserver也存在这个问题。

端口:1600
服务:issd
说明:木马shivka-burka开放此端口。

端口:1720
服务:netmeeting
说明:netmeeting h.233 call setup。

端口:1731
服务:netmeeting audio call control
说明:netmeeting音频调用控制。

端口:1807
服务:【null】
说明:木马spysender开放此端口。

端口:1981
服务:【null】
说明:木马shockrave开放此端口。

端口:1999
服务:cisco identification port
说明:木马backdoor开放此端口。

端口:2000
服务:【null】
说明:木马girlfriend 1.3、millenium 1.0开放此端口。

端口:2001
服务:【null】
说明:木马millenium 1.0、trojan cow开放此端口。

端口:2023
服务:xinuexpansion 4
说明:木马pass ripper开放此端口。

端口:2049
服务:nfs
说明:nfs程序常运行于这个端口。通常需要访问portmapper查询这个服务运行于哪个端口。

端口:2115
服务:【null】
说明:木马bugs开放此端口。

端口:2140、3150
服务:【null】
说明:木马deep throat 1.0/3.0开放此端口。

端口:2500
服务:rpc client using a fixed port session replication
说明:应用固定端口会话复制的rpc客户

端口:2583
服务:【null】
说明:木马wincrash 2.0开放此端口。

端口:2801
服务:【null】
说明:木马phineas phucker开放此端口。

端口:3024、4092
服务:【null】
说明:木马wincrash开放此端口。

端口:3128
服务:squid
说 明:这是squid http代理服务器的默认端口。攻击者扫描这个端口是为了搜寻一个代理服务器而匿名访问internet。也会看到搜索其他代理服务器的端口8000、 8001、8080、8888。扫描这个端口的另一个原因是用户正在进入聊天室。其他用户也会检验这个端口以确定用户的机器是否支持代理。

端口:3129
服务:【null】
说明:木马master paradise开放此端口。

端口:3150
服务:【null】
说明:木马the invasor开放此端口。

端口:3210、4321
服务:【null】
说明:木马schoolbus开放此端口

端口:3333
服务:dec-notes
说明:木马prosiak开放此端口

端口:3389
服务:超级终端
说明:windows 2000终端开放此端口。

端口:3700
服务:【null】
说明:木马portal of doom开放此端口

端口:3996、4060
服务:【null】
说明:木马remoteanything开放此端口

端口:4000
服务:qq客户端
说明:腾讯qq客户端开放此端口。

端口:4092
服务:【null】
说明:木马wincrash开放此端口。

端口:4590
服务:【null】
说明:木马icqtrojan开放此端口。

端口:5000、5001、5321、50505
服务:【null】
说明:木马blazer5开放5000端口。木马sockets de troie开放5000、5001、5321、50505端口。

端口:5400、5401、5402
服务:【null】
说明:木马blade runner开放此端口。

端口:5550
服务:【null】
说明:木马xtcp开放此端口。

端口:5569
服务:【null】
说明:木马robo-hack开放此端口。

端口:5632
服务:pcanywere
说 明:有时会看到很多这个端口的扫描,这依赖于用户所在的位置。当用户打开pcanywere时,它会自动扫描局域网c类网以寻找可能的代理(这里的代理是 指agent而不是proxy)。入侵者也会寻找开放这种服务的计算机。,所以应该查看这种扫描的源地址。一些搜寻pcanywere的扫描包常含端口 22的udp数据包。

端口:5742
服务:【null】
说明:木马wincrash1.03开放此端口。

端口:6267
服务:【null】
说明:木马广外女生开放此端口。

端口:6400
服务:【null】
说明:木马the thing开放此端口。

端口:6670、6671
服务:【null】
说明:木马deep throat开放6670端口。而deep throat 3.0开放6671端口。

端口:6883
服务:【null】
说明:木马deltasource开放此端口。

端口:6969
服务:【null】
说明:木马gatecrasher、priority开放此端口。

端口:6970
服务:realaudio
说明:realaudio客户将从服务器的6970-7170的udp端口接收音频数据流。这是由tcp-7070端口外向控制连接设置的。

端口:7000
服务:【null】
说明:木马remote grab开放此端口。

端口:7300、7301、7306、7307、7308
服务:【null】
说明:木马netmonitor开放此端口。另外netspy1.0也开放7306端口。

端口:7323
服务:【null】
说明:sygate服务器端。

端口:7626
服务:【null】
说明:木马giscier开放此端口。

端口:7789
服务:【null】
说明:木马ickiller开放此端口。

端口:8000
服务:oicq
说明:腾讯qq服务器端开放此端口。

端口:8010
服务:wingate
说明:wingate代理开放此端口。

端口:8080
服务:代理端口
说明:www代理开放此端口。

端口:9400、9401、9402
服务:【null】
说明:木马incommand 1.0开放此端口。

端口:9872、9873、9874、9875、10067、10167
服务:【null】
说明:木马portal of doom开放此端口。

端口:9989
端口:9989
服务:【null】
说明:木马ini-killer开放此端口。

端口:11000
服务:【null】
说明:木马sennaspy开放此端口。

端口:11223
服务:【null】
说明:木马progenic trojan开放此端口。

端口:12076、61466
服务:【null】
说明:木马telecommando开放此端口。

端口:12223
服务:【null】
说明:木马hack? keylogger开放此端口。

端口:12345、12346
服务:【null】
说明:木马netbus1.60/1.70、gabanbus开放此端口。

端口:12361
服务:【null】
说明:木马whack-a-mole开放此端口。

端口:13223
服务:powwow
说 明:powwow是tribal voice的聊天程序。它允许用户在此端口打开私人聊天的连接。这一程序对于建立连接非常具有攻击性。它会驻扎在这个tcp端口等回应。造成类似心跳间隔 的连接请求。如果一个拨号用户从另一个聊天者手中继承了ip地址就会发生好象有很多不同的人在测试这个端口的情况。这一协议使用opng作为其连接请求的 前4个字节。

端口:16969
服务:【null】
说明:木马priority开放此端口。

端口:17027
服务:conducent
说明:这是一个外向连接。这是由于公司内部有人安装了带有conducent"adbot"的共享软件。conducent"adbot"是为共享软件显示广告服务的。使用这种服务的一种流行的软件是pkware。

端口:19191
服务:【null】
说明:木马蓝色火焰开放此端口。

端口:20000、20001
服务:【null】
说明:木马millennium开放此端口。

端口:20034
服务:【null】
说明:木马netbus pro开放此端口。

端口:21554
服务:【null】
说明:木马girlfriend开放此端口。

端口:22222
服务:【null】
说明:木马prosiak开放此端口。

端口:23456
服务:【null】
说明:木马evil ftp、ugly ftp开放此端口。

端口:26274、47262
服务:【null】
说明:木马delta开放此端口。

端口:27374
服务:【null】
说明:木马subseven 2.1开放此端口。

端口:30100
服务:【null】
说明:木马netsphere开放此端口。

端口:30303
服务:【null】
说明:木马socket23开放此端口。

端口:30999
服务:【null】
说明:木马kuang开放此端口。

端口:31337、31338
服务:【null】
说明:木马bo(back orifice)开放此端口。另外木马deepbo也开放31338端口。

端口:31339
服务:【null】
说明:木马netspy dk开放此端口。

端口:31666
服务:【null】
说明:木马bowhack开放此端口。

端口:33333
服务:【null】
说明:木马prosiak开放此端口。

端口:34324
服务:【null】
说明:木马tiny telnet server、biggluck、tn开放此端口。

端口:40412
服务:【null】
说明:木马the spy开放此端口。

端口:40421、40422、40423、40426、
服务:【null】
说明:木马masters paradise开放此端口。

端口:43210、54321
服务:【null】
说明:木马schoolbus 1.0/2.0开放此端口。

端口:44445
服务:【null】
说明:木马happypig开放此端口。

端口:50766
服务:【null】
说明:木马fore开放此端口。

端口:53001
服务:【null】
说明:木马remote windows shutdown开放此端口。

端口:65000
服务:【null】
说明:木马devil 1.03开放此端口。


端口:88
说明:kerberos krb5。另外tcp的88端口也是这个用途。

端口:137
说 明:sql named pipes encryption over other protocols name lookup(其他协议名称查找上的sql命名管道加密技术)和sql rpc encryption over other protocols name lookup(其他协议名称查找上的sql rpc加密技术)和wins netbt name service(wins netbt名称服务)和wins proxy都用这个端口。

端口:161
说明:simple network management protocol(smtp)(简单网络管理协议)。

端口:162
说明:snmp trap(snmp陷阱)

端口:445
说明:common internet file system(cifs)(公共internet文件系统)

端口:464
说明:kerberos kpasswd(v5)。另外tcp的464端口也是这个用途。

端口:500
说明:internet key exchange(ike)(internet密钥交换)

端口:1645、1812
说明:remot authentication dial-in user service(radius)authentication(routing and remote access)(远程认证拨号用户服务)

端口:1646、1813
说明:radius accounting(routing and remote access)(radius记帐(路由和远程访问))

端口:1701
说明:layer two tunneling protocol(l2tp)(第2层隧道协议)

端口:1801、3527
说明:microsoft message queue server(microsoft消息队列服务器)。还有tcp的135、1801、2101、2103、2105也是同样的用途。

端口:2504
说明:network load balancing(网络平衡负荷)
posted @ 2011-06-20 20:17 ivaneeo 阅读(414) | 评论 (0)编辑 收藏

 前面系统讨论过java类型加载(loading)的问题,在这篇文章中简要分析一下java类型卸载(unloading)的问题,并简要分析一下如何解决如何运行时加载newly compiled version的问题。

【相关规范摘要】
    首先看一下,关于java虚拟机规范中时如何阐述类型卸载(unloading)的:
    A class or interface may be unloaded if and only if its class loader is unreachable. The bootstrap class loader is always reachable; as a result, system classes may never be unloaded.
    Java虚拟机规范中关于类型卸载的内容就这么简单两句话,大致意思就是:只有当加载该类型的类加载器实例(非类加载器类型)为unreachable状态时,当前被加载的类型才被卸载.启动类加载器实例永远为reachable状态,由启动类加载器加载的类型可能永远不会被卸载.

    我们再看一下Java语言规范提供的关于类型卸载的更详细的信息(部分摘录):
    //摘自JLS 12.7 Unloading of Classes and Interfaces
    1、An implementation of the Java programming language may unload classes.
    2、Class unloading is an optimization that helps reduce memory use. Obviously,the semantics of a program should not depend  on whether and how a system chooses to implement an optimization such as class unloading.
    3、Consequently,whether a class or interface has been unloaded or not should be transparent to a program

    通过以上我们可以得出结论: 类型卸载(unloading)仅仅是作为一种减少内存使用的性能优化措施存在的,具体和虚拟机实现有关,对开发者来说是透明的.

    纵观java语言规范及其相关的API规范,找不到显示类型卸载(unloading)的接口, 换句话说:
    1、一个已经加载的类型被卸载的几率很小至少被卸载的时间是不确定的
    2、一个被特定类加载器实例加载的类型运行时可以认为是无法被更新的

【类型卸载进一步分析】
     前面提到过,如果想卸载某类型,必须保证加载该类型的类加载器处于unreachable状态,现在我们再看看有 关unreachable状态的解释:
    1、A reachable object is any object that can be accessed in any potential continuing computation from any live thread.
    2、finalizer-reachable: A finalizer-reachable object can be reached from some finalizable object through some chain of references, but not from any live thread. An unreachable object cannot be reached by either means.

    某种程度上讲,在一个稍微复杂的java应用中,我们很难准确判断出一个实例是否处于unreachable状态,所    以为了更加准确的逼近这个所谓的unreachable状态,我们下面的测试代码尽量简单一点.
    
    【测试场景一】使用自定义类加载器加载, 然后测试将其设置为unreachable的状态
    说明:
    1、自定义类加载器(为了简单起见, 这里就假设加载当前工程以外D盘某文件夹的class)
    2、假设目前有一个简单自定义类型MyClass对应的字节码存在于D:/classes目录下
    
public class MyURLClassLoader extends URLClassLoader {
   public MyURLClassLoader() {
      super(getMyURLs());
   }

   private static URL[] getMyURLs() {
    try {
       return new URL[]{new File ("D:/classes/").toURL()};
    } catch (Exception e) {
       e.printStackTrace();
       return null;
    }
  }
}

 1 public class Main {
 2     public static void main(String[] args) {
 3       try {
 4          MyURLClassLoader classLoader = new MyURLClassLoader();
 5          Class classLoaded = classLoader.loadClass("MyClass");
 6          System.out.println(classLoaded.getName());
 7
 8          classLoaded = null;
 9          classLoader = null;
10
11          System.out.println("开始GC");
12          System.gc();
13          System.out.println("GC完成");
14        } catch (Exception e) {
15            e.printStackTrace();
16        }
17     }
18 }

        我们增加虚拟机参数-verbose:gc来观察垃圾收集的情况,对应输出如下:   
MyClass
开始GC
[Full GC[Unloading class MyClass]
207K->131K(1984K), 0.0126452 secs]
GC完成

    【测试场景二】使用系统类加载器加载,但是无法将其设置为unreachable的状态
      说明:将场景一中的MyClass类型字节码文件放置到工程的输出目录下,以便系统类加载器可以加载
        
 1 public class Main {
 2     public static void main(String[] args) {
 3      try {
 4       Class classLoaded =  ClassLoader.getSystemClassLoader().loadClass(
 5 "MyClass");
 6
 7
 8      System.out.printl(sun.misc.Launcher.getLauncher().getClassLoader());
 9      System.out.println(classLoaded.getClassLoader());
10      System.out.println(Main.class.getClassLoader());
11
12      classLoaded = null;
13
14      System.out.println("开始GC");
15      System.gc();
16      System.out.println("GC完成");
17
18      //判断当前系统类加载器是否有被引用(是否是unreachable状态)
19      System.out.println(Main.class.getClassLoader());
20     } catch (Exception e) {
21         e.printStackTrace();
22     }
23   }
24 }
        
        我们增加虚拟机参数-verbose:gc来观察垃圾收集的情况, 对应输出如下:
sun.misc.Launcher$AppClassLoader@197d257
sun.misc.Launcher$AppClassLoader@197d257
sun.misc.Launcher$AppClassLoader@197d257
开始GC
[Full GC 196K->131K(1984K), 0.0130748 secs]
GC完成
sun.misc.Launcher$AppClassLoader@197d257

        由于系统ClassLoader实例(AppClassLoader@197d257">sun.misc.Launcher$AppClassLoader@197d257)加载了很多类型,而且又没有明确的接口将其设置为null,所以我们无法将加载MyClass类型的系统类加载器实例设置为unreachable状态,所以通过测试结果我们可以看出,MyClass类型并没有被卸载.(说明: 像类加载器实例这种较为特殊的对象一般在很多地方被引用, 会在虚拟机中呆比较长的时间)

    【测试场景三】使用扩展类加载器加载, 但是无法将其设置为unreachable的状态

        说明:将测试场景二中的MyClass类型字节码文件打包成jar放置到JRE扩展目录下,以便扩展类加载器可以加载的到。由于标志扩展ClassLoader实例(ExtClassLoader@7259da">sun.misc.Launcher$ExtClassLoader@7259da)加载了很多类型,而且又没有明确的接口将其设置为null,所以我们无法将加载MyClass类型的系统类加载器实例设置为unreachable状态,所以通过测试结果我们可以看出,MyClass类型并没有被卸载.
        
 1 public class Main {
 2      public static void main(String[] args) {
 3        try {
 4          Class classLoaded = ClassLoader.getSystemClassLoader().getParent()
 5 .loadClass("MyClass");
 6
 7          System.out.println(classLoaded.getClassLoader());
 8
 9          classLoaded = null;
10
11          System.out.println("开始GC");
12          System.gc();
13          System.out.println("GC完成");
14          //判断当前标准扩展类加载器是否有被引用(是否是unreachable状态)
15          System.out.println(Main.class.getClassLoader().getParent());
16       } catch (Exception e) {
17          e.printStackTrace();
18       }
19    }
20 }

        我们增加虚拟机参数-verbose:gc来观察垃圾收集的情况,对应输出如下:
sun.misc.Launcher$ExtClassLoader@7259da
开始GC
[Full GC 199K->133K(1984K), 0.0139811 secs]
GC完成
sun.misc.Launcher$ExtClassLoader@7259da


    关于启动类加载器我们就不需再做相关的测试了,jvm规范和JLS中已经有明确的说明了.


    【类型卸载总结】
    通过以上的相关测试(虽然测试的场景较为简单)我们可以大致这样概括:
    1、有启动类加载器加载的类型在整个运行期间是不可能被卸载的(jvm和jls规范).
    2、被系统类加载器和标准扩展类加载器加载的类型在运行期间不太可能被卸载,因为系统类加载器实例或者标准扩展类的实例基本上在整个运行期间总能直接或者间接的访问的到,其达到unreachable的可能性极小.(当然,在虚拟机快退出的时候可以,因为不管ClassLoader实例或者Class(java.lang.Class)实例也都是在堆中存在,同样遵循垃圾收集的规则).
    3、被开发者自定义的类加载器实例加载的类型只有在很简单的上下文环境中才能被卸载,而且一般还要借助于强制调用虚拟机的垃圾收集功能才可以做到.可以预想,稍微复杂点的应用场景中(尤其很多时候,用户在开发自定义类加载器实例的时候采用缓存的策略以提高系统性能),被加载的类型在运行期间也是几乎不太可能被卸载的(至少卸载的时间是不确定的).

      综合以上三点,我们可以默认前面的结论1, 一个已经加载的类型被卸载的几率很小至少被卸载的时间是不确定的.同时,我们可以看的出来,开发者在开发代码时候,不应该对虚拟机的类型卸载做任何假设的前提下来实现系统中的特定功能.
    
      【类型更新进一步分析】
    前面已经明确说过,被一个特定类加载器实例加载的特定类型在运行时是无法被更新的.注意这里说的
         是一个特定的类加载器实例,而非一个特定的类加载器类型.
    
        【测试场景四】
        说明:现在要删除前面已经放在工程输出目录下和扩展目录下的对应的MyClass类型对应的字节码
        
 1 public class Main {
 2      public static void main(String[] args) {
 3        try {
 4          MyURLClassLoader classLoader = new MyURLClassLoader();
 5          Class classLoaded1 = classLoader.loadClass("MyClass");
 6          Class classLoaded2 = classLoader.loadClass("MyClass");
 7          //判断两次加载classloader实例是否相同
 8           System.out.println(classLoaded1.getClassLoader() == classLoaded2.getClassLoader());
 9
10         //判断两个Class实例是否相同
11           System.out.println(classLoaded1 == classLoaded2);
12       } catch (Exception e) {
13          e.printStackTrace();
14       }
15    }
16 }
        输出如下:
        true
        true

        通过结果我们可以看出来,两次加载获取到的两个Class类型实例是相同的.那是不是确实是我们的自定义
       类加载器真正意义上加载了两次呢(即从获取class字节码到定义class类型…整个过程呢)?
      通过对java.lang.ClassLoader的loadClass(String name,boolean resolve)方法进行调试,我们可以看出来,第二
      次  加载并不是真正意义上的加载,而是直接返回了上次加载的结果.

       说明:为了调试方便, 在Class classLoaded2 = classLoader.loadClass("MyClass");行设置断点,然后单步跳入, 可以看到第二次加载请求返回的结果直接是上次加载的Class实例. 调试过程中的截图 最好能自己调试一下).
      
     
        【测试场景五】同一个类加载器实例重复加载同一类型
        说明:首先要对已有的用户自定义类加载器做一定的修改,要覆盖已有的类加载逻辑, MyURLClassLoader.java类简要修改如下:重新运行测试场景四中的测试代码
      
 1 public class MyURLClassLoader extends URLClassLoader {
 2     //省略部分的代码和前面相同,只是新增如下覆盖方法
 3     /*
 4     * 覆盖默认的加载逻辑,如果是D:/classes/下的类型每次强制重新完整加载
 5     *
 6     * @see java.lang.ClassLoader#loadClass(java.lang.String)
 7     */
 8     @Override
 9     public Class<?> loadClass(String name) throws ClassNotFoundException {
10      try {
11        //首先调用系统类加载器加载
12         Class c = ClassLoader.getSystemClassLoader().loadClass(name);
13        return c;
14      } catch (ClassNotFoundException e) {
15       // 如果系统类加载器及其父类加载器加载不上,则调用自身逻辑来加载D:/classes/下的类型
16          return this.findClass(name);
17      }
18   }
19 }
说明: this.findClass(name)会进一步调用父类URLClassLoader中的对应方法,其中涉及到了defineClass(String name)的调用,所以说现在类加载器MyURLClassLoader会针对D:/classes/目录下的类型进行真正意义上的强制加载并定义对应的类型信息.

        测试输出如下:
        Exception in thread "main" java.lang.LinkageError: duplicate class definition: MyClass
       at java.lang.ClassLoader.defineClass1(Native Method)
       at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
       at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
       at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
       at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
       at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
       at java.security.AccessController.doPrivileged(Native Method)
       at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
       at MyURLClassLoader.loadClass(MyURLClassLoader.java:51)
       at Main.main(Main.java:27)
      
       结论:如果同一个类加载器实例重复强制加载(含有定义类型defineClass动作)相同类型,会引起java.lang.LinkageError: duplicate class definition.
    
       【测试场景六】同一个加载器类型的不同实例重复加载同一类型
       
 1 public class Main {
 2     public static void main(String[] args) {
 3       try {
 4         MyURLClassLoader classLoader1 = new MyURLClassLoader();
 5         Class classLoaded1 = classLoader1.loadClass("MyClass");
 6         MyURLClassLoader classLoader2 = new MyURLClassLoader();
 7         Class classLoaded2 = classLoader2.loadClass("MyClass");
 8
 9         //判断两个Class实例是否相同
10          System.out.println(classLoaded1 == classLoaded2);
11       } catch (Exception e) {
12          e.printStackTrace();
13       }
14    }
15 }

      测试对应的输出如下:
      false
     
    
        【类型更新总结】   
     由不同类加载器实例重复强制加载(含有定义类型defineClass动作)同一类型不会引起java.lang.LinkageError错误, 但是加载结果对应的Class类型实例是不同的,即实际上是不同的类型(虽然包名+类名相同). 如果强制转化使用,会引起ClassCastException.(说明: 头一段时间那篇文章中解释过,为什么不同类加载器加载同名类型实际得到的结果其实是不同类型, 在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识,不同类加载器加载的类将被置于不同的命名空间).


        应用场景:我们在开发的时候可能会遇到这样的需求,就是要动态加载某指定类型class文件的不同版本,以便能动态更新对应功能.
         建议:
        1. 不要寄希望于等待指定类型的以前版本被卸载,卸载行为对java开发人员透明的.
        2. 比较可靠的做法是,每次创建特定类加载器的新实例来加载指定类型的不同版本,这种使用场景下,一般就要牺牲缓存特定类型的类加载器实例以带来性能优化的策略了.对于指定类型已经被加载的版本, 会在适当时机达到unreachable状态,被unload并垃圾回收.每次使用完类加载器特定实例后(确定不需要再使用时), 将其显示赋为null, 这样可能会比较快的达到jvm 规范中所说的类加载器实例unreachable状态, 增大已经不再使用的类型版本被尽快卸载的机会.
        3. 不得不提的是,每次用新的类加载器实例去加载指定类型的指定版本,确实会带来一定的内存消耗,一般类加载器实例会在内存中保留比较长的时间. 在bea开发者网站上找到一篇相关的文章(有专门分析ClassLoader的部分):http://dev2dev.bea.com/pub/a/2005/06/memory_leaks.html

           写的过程中参考了jvm规范和jls, 并参考了sun公司官方网站上的一些bug的分析文档。

           欢迎大家批评指正!


本博客中的所有文章、随笔除了标题中含有引用或者转载字样的,其他均为原创。转载请注明出处,谢谢!
posted @ 2011-06-16 20:05 ivaneeo 阅读(337) | 评论 (0)编辑 收藏

启动集群中所有的regionserver
./hbase-daemons.sh start regionserver
启动某个regionserver
./hbase-daemon.sh start regionserver
posted @ 2011-06-16 12:10 ivaneeo 阅读(1502) | 评论 (0)编辑 收藏

做了几天工程,对HBase中的表操作熟悉了一下。下面总结一下常用的表操作和容易出错的几个方面。当然主要来源于大牛们的文章。我在前人的基础上稍作解释。

1.连接HBase中的表testtable,用户名:root,密码:root

public void ConnectHBaseTable()
 {
  Configuration conf = new Configuration();       
        conf.set("hadoop.job.ugi", "root,root");      
  HBaseConfiguration config = new HBaseConfiguration();
  try
  {
   table = new HTable(config, "testtable");
  }catch(Exception e){e.printStackTrace();}
 }

2.根据行名name获得一行数据,存入Result.注意HBase中的表数据是字节存储的。

   下面的例子表示获得行名为name的行的famA列族col1列的数据。

      String rowId = "name";
      Get get = new Get(rowId);
      Result result = hTable.get(get);
      byte[] value = result.getValue(famA, col1);
      System.out.println(Bytes.toString(value));

3.向表中存数据

      下面的例子表示写入一行。行名为abcd,famA列族col1列的数据为"hello world!"。

      byte[] rowId = Bytes.toBytes("abcd");
      byte[] famA = Bytes.toBytes("famA");
      byte[] col1 = Bytes.toBytes("col1");
      Put put = new Put(rowId).
         add(famA, col1, Bytes.toBytes("hello world!"));
      hTable.put(put);
     

4.扫描的用法(scan):便于获得自己需要的数据,相当于SQL查询。

      byte[] famA = Bytes.toBytes("famA");
      byte[] col1 = Bytes.toBytes("col1");  

      HTable hTable = new HTable("test");  

      //表示要查询的行名是从a开始,到z结束。
      Scan scan = new Scan(Bytes.toBytes("a"), Bytes.toBytes("z"));
     

      //用scan.setStartRow(Bytes.toBytes(""));设置起始行

      //用scan.setStopRow(Bytes.toBytes(""));设置终止行

      //表示查询famA族col1列

      scan.addColumn(famA, col1);  

      //注意,下面是filter的写法。相当于SQL的where子句

      //表示famA族col1列的数据等于"hello world!"
      
SingleColumnValueFilter singleColumnValueFilterA = new SingleColumnValueFilter(
           famA, col1, CompareOp.EQUAL, Bytes.toBytes("hello world!"));
      singleColumnValueFilterA.setFilterIfMissing(true);  

      //表示famA族col1列的数据等于"hello hbase!"
      
SingleColumnValueFilter singleColumnValueFilterB = new SingleColumnValueFilter(
           famA, col1, CompareOp.EQUAL, Bytes.toBytes("hello hbase!"));
      singleColumnValueFilterB.setFilterIfMissing(true);  
      

      //表示famA族col1列的数据是两者中的一个
      FilterList filter = new FilterList(Operator.MUST_PASS_ONE, Arrays
           .asList((Filter) singleColumnValueFilterA,
                singleColumnValueFilterB));  

      scan.setFilter(filter);  

      ResultScanner scanner = hTable.getScanner(scan);  
      //遍历每个数据
      for (Result result : scanner) {
         System.out.println(Bytes.toString(result.getValue(famA, col1)));
      }

5.上面的代码容易出错的地方在于,需要导入HBase的类所在的包。导入时需要选择包,由于类可能出现在HBase的各个子包中,所以要选择好,下面列出常用的包。尽量用HBase的包

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.FilterList.Operator;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

6.下面列出HBase常用的操作

(1)时间戳到时间的转换.单一的时间戳无法给出直观的解释。

public String GetTimeByStamp(String timestamp)
 {

  long datatime= Long.parseLong(timestamp); 
     Date date=new Date(datatime);   
     SimpleDateFormat   format=new   SimpleDateFormat("yyyy-MM-dd HH:MM:ss");   
     String timeresult=format.format(date);
     System.out.println("Time : "+timeresult);
     return timeresult;
 }

(2)时间到时间戳的转换。注意时间是字符串格式。字符串与时间的相互转换,此不赘述

public String GetStampByTime(String time)
 {
  String Stamp="";
  SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  Date date;
  try
  {
   date=sdf.parse(time);
   Stamp=date.getTime()+"000";
   System.out.println(Stamp);
  }catch(Exception e){e.printStackTrace();}
  return Stamp;
 }

上面就是我的一点心得。以后碰到什么问题,再来解决。

参考文献:http://www.nearinfinity.com/blogs/aaron_mccurry/using_hbase-dsl.html

posted @ 2011-06-15 17:17 ivaneeo 阅读(493) | 评论 (0)编辑 收藏

官方Book Performance Tuning部分章节没有按配置项进行索引,不能达到快速查阅的效果。所以我以配置项驱动,重新整理了原文,并补充一些自己的理解,如有错误,欢迎指正。

配置优化

zookeeper.session.timeout
默认值:3分钟(180000ms)
说明:RegionServer与Zookeeper间的连接超时时间。当超时时间到后,ReigonServer会 被Zookeeper从RS集群清单中移除,HMaster收到移除通知后,会对这台server负责的regions重新balance,让其他存活的 RegionServer接管.
调优
这个timeout决定了RegionServer是否能够及时的failover。设置成1分钟或更低,可以减少因等待超时而被延长的failover时间。
不过需要注意的是,对于一些Online应用,RegionServer的宕机到恢复时间本身就很短的(网络闪断,crash等故障,运维可快速介入), 如果调低timeout时间,会得不偿失。因为当ReigonServer被正式从RS集群中移除时,HMaster就开始做balance了,当故障的 RS快速恢复后,这个balance动作是毫无意义的,反而会使负载不均匀,给RS带来更多负担。

hbase.regionserver.handler.count
默认值:10
说明:RegionServer的请求处理IO线程数。
调优
这个参数的调优与内存息息相关。
较少的IO线程,适用于处理单次请求内存消耗较高的Big PUT场景(大容量单次PUT或设置了较大cache的scan,均属于Big PUT)或ReigonServer的内存比较紧张的场景。
较多的IO线程,适用于单次请求内存消耗低,TPS要求非常高的场景。
这里需要注意的是如果server的region数量很少,大量的请求都落在一个region上,因快速充满memstore触发flush导致的读写锁会影响全局TPS,不是IO线程数越高越好。
压测时,开启Enabling RPC-level logging,可以同时监控每次请求的内存消耗和GC的状况,最后通过多次压测结果来合理调节IO线程数。
这里是一个案例 Hadoop and HBase Optimization for Read Intensive Search Applications,作者在SSD的机器上设置IO线程数为100,仅供参考。

hbase.hregion.max.filesize
默认值:256M
说明:在当前ReigonServer上单个Reigon的大小,单个Region超过指定值时,这个Region会被自动split成更小的region。
调优
小region对split和compaction友好,因为拆分region或compact小region里的storefile速度很快,内存占用低。缺点是split和compaction会很频繁。
特别是数量较多的小region不停地split, compaction,会使响应时间波动很大,region数量太多不仅给管理上带来麻烦,甚至引发一些Hbase的bug。
一般512以下的都算小region。

大region,则不太适合经常split和compaction,因为做一次compact和split会产生较长时间的停顿,对应用的读写性能冲击非常大。此外,大region意味着较大的storefile,compaction时对内存也是一个挑战。
当然,大region还是有其用武之地,你只要在某个访问量低峰的时间点统一做compact和split,大region就可以发挥优势了,毕竟它能保证绝大多数时间平稳的读写性能。

既然split和compaction如此影响性能,有没有办法去掉?
compaction是无法避免的,split倒是可以从自动调整为手动。
只要通过将这个参数值调大到某个很难达到的值,比如100G,就可以间接禁用自动split(RegionServer不会对未到达100G的region做split)。
再配合RegionSplitter这个工具,在需要split时,手动split。
手动split在灵活性和稳定性上比起自动split要高很多,相反,管理成本增加不多,比较推荐online实时系统使用。

内存方面,小region在设置memstore的大小值上比较灵活,大region则过大过小都不行,过大会导致flush时app的IO wait增高,过小则因store file过多读性能降低。

hbase.regionserver.global.memstore.upperLimit/lowerLimit

默认值:0.4/0.35
upperlimit说明:hbase.hregion.memstore.flush.size 这个参数的作用是 当单个memstore达到指定值时,flush该memstore。但是,一台ReigonServer可能有成百上千个memstore,每个 memstore也许未达到flush.size,jvm的heap就不够用了。该参数就是为了限制memstores占用的总内存。
当ReigonServer内所有的memstore所占用的内存综合达到heap的40%时,HBase会强制block所有的更新并flush这些memstore以释放所有memstore占用的内存。
lowerLimit说明: 同upperLimit,只不过当全局memstore的内存达到35%时,它不会flush所有的memstore,它会找一些内存占用较大的 memstore,个别flush,当然更新还是会被block。lowerLimit算是一个在全局flush前的补救措施。可以想象一下,如果 memstore需要在一段时间内全部flush,且这段时间内无法接受写请求,对HBase集群的性能影响是很大的。
调优:这是一个Heap内存保护参数,默认值已经能适用大多数场景。它的调整一般是为了配合某些专属优化,比如读密集型应用,将读缓存开大,降低该值,腾出更多内存给其他模块使用。
这个参数会给使用者带来什么影响?
比如,10G内存,100个region,每个memstore 64M,假设每个region只有一个memstore,那么当100个memstore平均占用到50%左右时,就会达到lowerLimit的限制。 假设此时,其他memstore同样有很多的写请求进来。在那些大的region未flush完,就可能又超过了upperlimit,则所有 region都会被block,开始触发全局flush。

hfile.block.cache.size

默认值:0.2
说明:storefile的读缓存占用Heap的大小百分比,0.2表示20%。该值直接影响数据读的性能。
调优:当然是越大越好,如果读比写少,开到0.4-0.5也没问题。如果读写较均衡,0.3左右。如果写比读多,果断 默认吧。设置这个值的时候,你同时要参考 hbase.regionserver.global.memstore.upperLimit ,该值是 memstore占heap的最大百分比,两个参数一个影响读,一个影响写。如果两值加起来超过80-90%,会有OOM的风险,谨慎设置。

hbase.hstore.blockingStoreFiles

默认值:7
说明:在compaction时,如果一个Store(Coulmn Family)内有超过7个storefile需要合并,则block所有的写请求,进行flush,限制storefile数量增长过快。
调优:block请求会影响当前region的读写性能,将值设为单个region可以支撑的最大store file数量会是个不错的选择。最大storefile数量可通过region size/memstore size来计算。如果你将region size设为无限大,那么你需要预估一个region可能产生的最大storefile数。

hbase.hregion.memstore.block.multiplier

默认值:2
说明:当一个region里的memstore超过单个memstore.size两倍的大小时,block该 region的所有请求,进行flush,释放内存。虽然我们设置了memstore的总大小,比如64M,但想象一下,在最后63.9M的时候,我 Put了一个100M的数据或写请求量暴增,最后一秒钟put了1万次,此时memstore的大小会瞬间暴涨到超过预期的memstore.size。 这个参数的作用是当memstore的大小增至超过memstore.size时,block所有请求,遏制风险进一步扩大。
调优: 这个参数的默认值还是比较靠谱的。如果你预估你的正常应用场景(不包括异常)不会出现突发写或写的量可控,那么保持默认值即可。如果正常情况下,你的写量 就会经常暴增,那么你应该调大这个倍数并调整其他参数值,比如hfile.block.cache.size和 hbase.regionserver.global.memstore.upperLimit/lowerLimit,以预留更多内存,防止HBase server OOM。

其他

启用LZO压缩
LZO对比Hbase默认的GZip,前者性能较高,后者压缩比较高,具体参见 Using LZO Compression对于想提高HBase读写性能的开发者,采用LZO是比较好的选择。对于非常在乎存储空间的开发者,则建议保持默认。

不要在一张表里定义太多的Column Family

Hbase目前不能良好的处理超过2-3个CF的表。因为某个CF在flush发生时,它邻近的CF也会因关联效应被触发flush,最终导致系统产生很多IO。

批量导入

在批量导入数据到Hbase前,你可以通过预先创建region,来平衡数据的负载。详见 Table Creation: Pre-Creating Regions

Hbase客户端优化

AutoFlush

HTable的setAutoFlush设为false,可以支持客户端批量更新。即当Put填满客户端flush缓存时,才发送到服务端。
默认是true。

Scan Caching

scanner一次缓存多少数据来scan(从服务端一次抓多少数据回来scan)。
默认值是 1,一次只取一条。

Scan Attribute Selection

scan时建议指定需要的Column Family,减少通信量,否则scan默认会返回整个row的所有数据(所有Coulmn Family)。

Close ResultScanners

通过scan取完数据后,记得要关闭ResultScanner,否则RegionServer可能会出现问题。

Optimal Loading of Row Keys

当你scan一张表的时候,返回结果只需要row key(不需要CF, qualifier,values,timestaps)时,你可以在scan实例中添加一个filterList,并设置 MUST_PASS_ALL操作,filterList中add FirstKeyOnlyFilterKeyOnlyFilter。这样可以减少网络通信量。

Turn off WAL on Puts

当Put某些非重要数据时,你可以设置writeToWAL(false),来进一步提高写性能。writeToWAL(false)会在Put时放弃写WAL log。风险是,当RegionServer宕机时,可能你刚才Put的那些数据会丢失,且无法恢复。

启用Bloom Filter

Bloom Filter通过空间换时间,提高读操作性能。

转载请注明原文链接:http://kenwublog.com/hbase-performance-tuning

posted @ 2011-06-15 13:39 ivaneeo 阅读(2784) | 评论 (0)编辑 收藏

We recently set up HBase and HBase-trx (from https://github.com/hbase-trx) to use multiple-column indexes with this code.  After you compile it, just copy the jar and the hbase-trx jar into your hbase’s lib folder and you should be good to to!

When you create a composite index, you can see the metadata for the index by looking at the table description.  One of the properties will read “INDEXES =>” followed by index names and ‘family:qualifier’ style column names in the index.

KeyGeneratorFactory:

package com.ir.store.hbase.indexes;

import java.util.List;

import org.apache.hadoop.hbase.client.tableindexed.IndexKeyGenerator;

public class KeyGeneratorFactory {

public static IndexKeyGenerator getInstance(List columns) {
return new HBaseIndexKeyGenerator(columns);
}
}

HBaseIndexKeyGenerator:

package com.ir.store.hbase.indexes;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.hadoop.hbase.client.tableindexed.IndexKeyGenerator;
import org.apache.hadoop.hbase.util.Bytes;

public class HBaseIndexKeyGenerator extends Object implements IndexKeyGenerator {
public static byte[] KEYSEPERATOR = "~;?".getBytes();

private int columnCount;
private List columnNames = new ArrayList();

public HBaseIndexKeyGenerator(List memberColumns) {
// For new key generators
columnNames = memberColumns;
columnCount = memberColumns.size();
}

public HBaseIndexKeyGenerator() {
// Hollow constructor for deserializing -- should call readFields shortly
columnCount = 0;
}

public void readFields(DataInput binaryInput) throws IOException {
columnCount = binaryInput.readInt();
for (int currentColumn = 0; currentColumn < columnCount; currentColumn++)
columnNames.add(Bytes.readByteArray(binaryInput));
}

public void write(DataOutput binaryOutput) throws IOException {
binaryOutput.writeInt(columnCount);
for (byte[] columnName : columnNames)
Bytes.writeByteArray(binaryOutput, columnName);
}

public byte[] createIndexKey(byte[] baseRowIdentifier, Map baseRowData) {
byte[] indexRowIdentifier = null;
for (byte[] columnName: columnNames) {
if (indexRowIdentifier == null)
indexRowIdentifier = baseRowData.get(columnName);
else indexRowIdentifier = Bytes.add(indexRowIdentifier, HBaseIndexKeyGenerator.KEYSEPERATOR, baseRowData.get(columnName));
}
if (baseRowIdentifier != null)
return Bytes.add(indexRowIdentifier, HBaseIndexKeyGenerator.KEYSEPERATOR, baseRowIdentifier);
return indexRowIdentifier;
}
}
posted @ 2011-06-11 16:21 ivaneeo 阅读(391) | 评论 (0)编辑 收藏

对于Bigtable类型的分布式数据库应用来说,用户往往会对其性能状况有极大的兴趣,这其中又对实时数据插入性能更为关注。HBase作为Bigtable的一个实现,在这方面的性能会如何呢?这就需要通过测试数据来说话了。

数据插入性能测试的设计场景是这样的,取随机值的Rowkey长度为2000字节,固定值的Value长度为4000字节,由于单行Row插入速度太快,系统统计精度不够,所以将插入500行Row做一次耗时统计。

这里要对HBase的特点做个说明,首先是Rowkey值为何取随机数,这是因为HBase是对Rowkey进行排序的,随机Rowkey将被分配到不同的region上,这样才能发挥出分布式数据库的性能优点。而Value对于HBase来说不会进行任何解析,其数据是否变化,对性能是不应该有任何影响的。同时为了简单起见,所有的数据都将只插入到一个表格的同一个Column中。

在测试之初,需要对集群进行调优,关闭可能大量耗费内存、带宽以及CPU的服务,例如Apache的Http服务。保持集群的宁静度。此外,为了保证测试不受干扰,Hbase的集群系统需要被独立,以保证不与HDFS所在的Hadoop集群有所交叉。

那么做好一切准备,就开始进行数据灌入,客户端从Zookeeper上查询到Regionserver的地址后,开始源源不断的向Hbase的Regionserver上喂入Row。

这里,我写了一个通过JFreeChart来实时生成图片的程序,每3分钟,喂数据的客户端会将获取到的耗时统计打印在一张十字坐标图中,这些图又被保存在制定的web站点中,并通过http服务展示出来。在通过长时间不间断的测试后,我得到了如下图形:

这个图形非常有特点,好似一条直线上,每隔一段时间就会泛起一个波浪,且两个高峰之间必有一个较矮的波浪。高峰的间隔则呈现出越来越大的趋势。而较矮的波浪恰好处于两高峰的中间位置。

为了解释这个现象,我对HDFS上Hbase所在的主目录下文件,以及被插入表格的region情况进行了实时监控,以期发现这些波浪上发生了什么事情。

回溯到客户端喂入数据的开始阶段,创建表格,在HDFS上便被创建了一个与表格同名的目录,该目录下将出现第一个region,region中会以family名创建一个目录,这个目录下才存在记录具体数据的文件。同时在该表表名目录下,还会生成一个“compaction.dir”目录,该目录将在family名目录下region文件超过指定数目时用于合并region。

当第一个region目录出现的时候,内存中最初被写入的数据将被保存到这个文件中,这个间隔是由选项“hbase.hregion.memstore.flush.size”决定的,默认是64MB,该region所在的Regionserver的内存中一旦有超过64MB的数据的时候,就将被写入到region文件中。这个文件将不断增殖,直到超过由“hbase.hregion.max.filesize”决定的文件大小时(默认是256MB,此时加上内存刷入的数据,实际最大可能到256+64M),该region将被执行split,立即被一切为二,其过程是在该目录下创建一个名为“.splits”的目录作为标记,然后由Regionserver将文件信息读取进来,分别写入到两个新的region目录中,最后再将老的region删除。这里的标记目录“.splits”将避免在split过程中发生其他操作,起到类似于多线程安全的锁功能。在新的region中,从老的region中切分出的数据独立为一个文件并不再接受新的数据(该文件大小超过了64M,最大可达到(256+64)/2=160MB),内存中新的数据将被保存到一个重新创建的文件中,该文件大小将为64MB。内存每刷新一次,region所在的目录下就将增加一个64M的文件,直到总文件数超过由“hbase.hstore.compactionThreshold”指定的数量时(默认为3),compaction过程就将被触发了。在上述值为3时,此时该region目录下,实际文件数只有两个,还有额外的一个正处于内存中将要被刷入到磁盘的过程中。Compaction过程是Hbase的一个大动作,Hbase不仅要将这些文件转移到“compaction.dir”目录进行压缩,而且在压缩后的文件超过256MB时,还必须立即进行split动作。这一系列行为在HDFS上可谓是翻山倒海,影响颇大。待Compaction结束之后,后续的split依然会持续进行一小段时间,直到所有的region都被切割分配完毕,Hbase才会恢复平静并等待下一次数据从内存写入到HDFS的到来。

理解了上述过程,则必然对HBase的数据插入性能为何是上图所示的曲线的原因一目了然。与X轴几乎平行的直线,表明数据正在被写入HBase的Regionserver所在机器的内存中。而较低的波峰意味着Regionserver正在将内存写入到HDFS上,较高的波峰意味着Regionserver不仅正在将内存刷入到HDFS,而且还在执行Compaction和Split两种操作。如果调整“hbase.hstore.compactionThreshold”的值为一个较大的数量,例如改成5,可以预见,在每两个高峰之间必然会等间隔的出现三次较低的波峰,并可预见到,高峰的高度将远超过上述值为3时的高峰高度(因为Compaction的工作更为艰巨)。由于region数量由少到多,而我们插入的Row的Rowkey是随机的,因此每一个region中的数据都会均匀的增加,同一段时间插入的数据将被分布到越来越多的region上,因此波峰之间的间隔时间也将会越来越长。

再次理解上述论述,我们可以推断出Hbase的数据插入性能实际上应该被分为三种情况,即直线状态、低峰状态和高峰状态。在这三种情况下得到的性能数据才是最终Hbase数据插入性能的真实描述。那么提供给用户的数据该是采取哪一个呢?我认为直线状态由于其所占时间会较长,尤其在用户写入数据的速度也许并不是那么快的情况下,所以这个状态下得到的性能数据结果更应该提供给用户。

posted @ 2011-06-10 23:33 ivaneeo 阅读(1587) | 评论 (1)编辑 收藏

HBase的写效率还是很高的,但其随机读取效率并不高

可以采取一些优化措施来提高其性能,如:

1. 启用lzo压缩,见这里

2. 增大hbase.regionserver.handler.count数为100

3. 增大hfile.block.cache.size为0.4,提高cache大小

4. 增大hbase.hstore.blockingStoreFiles为15

5. 启用BloomFilter,在HBase0,89中可以设置

6.Put时可以设置setAutoFlush为false,到一定数目后再flushCommits

 

在14个Region Server的集群上,新建立一个lzo压缩表

测试的Put和Get的性能如下:

1. Put数据:

单线程灌入1.4亿数据,共花费50分钟,每秒能达到4万个,这个性能确实很好了,不过插入的value比较小,只有不到几十个字节

多线程put,没有测试,因为单线程的效率已经相当高了

2. Get数据:

在没有任何Block Cache,而且是Random Read的情况:

单线程平均每秒只能到250个左右

6个线程平均每秒能达到1100个左右

16个线程平均每秒能达到2500个左右

有BlockCache(曾经get过对应的row,而且还在cache中)的情况:

单线程平均每秒能到3600个左右

6个线程平均每秒能达到1.2万个左右

16个线程平均每秒能达到2.5万个左右

posted @ 2011-06-10 23:14 ivaneeo 阅读(1191) | 评论 (0)编辑 收藏

仅列出标题
共67页: First 上一页 12 13 14 15 16 17 18 19 20 下一页 Last