Profil de 孔雀Glazy MazePhotosBlogListes Outils Aide

Blog


IIS7中的isapi redirect 1.2.X过滤器配置(连接IIS和AJP)

IIS7中的isapi redirect 1.2.X过滤器配置(连接IIS和AJP)

  1. 建立配置文件
    1. 在isapi_redirect.dll所在目录下建立入口配置文件(isapi_redirect.properties,必须使用该文件名),其中包含:
    2. isapi_redirect.properties
      extension_uri=/jakarta/isapi_redirect.dll
      log_file=D:\Applications\tomcat\connector\iis_jk\isapi_redirect.log
      log_level=info
      worker_file=D:\Applications\tomcat\connector\iis_jk\workers.properties
      worker_mount_file=D:\Applications\tomcat\connector\iis_jk\workers_mapping.properties
    3. 建立节点配置文件(workers.properties,文件名在isapi_redirect.properties中定义)。其中定义所有负载均衡、状态查询和ajp服务提供节点,如下:
    4. workers.properties
      worker.list=svc,dev,status
      
      #status worker
      worker.status.type=status
      
      #load balance worker
      #worker.lb.type=lb
      #worker.lb.balance_workers=dev1,dev2
      
      #service worker
      worker.svc.type=ajp13
      worker.svc.host=localhost
      worker.svc.port=9009
      
      #devel worker
      worker.dev.type=ajp13
      worker.dev.host=localhost
      worker.dev.port=8009
    5. 建立路径映射配置文件(workers_mapping.properties,文件名在isapi_redirect.properties中定义):
    6. workers_mapping.properties
      /song/*.jsp=dev
      /song/*.jspa=dev
      /jira/*=svc
      /jk=status
  2. 配置IIS 7.0服务:
    1. 建立isapi插件的iis访问虚拟目录:
    2. 虚拟目录名称对应isapi_redirect.properties中的extension_uri参数。使IIS能通过extension_uri访问到ispai_redirect.dll。 并给该虚拟目录增加执行权限:
      1. 在该虚拟目录的功能视图中选择"处理程序映射"
      2. 执行"编辑功能权限",添加"执行"权限
      3. 确认列表中的"ISAPI-dll"状态为"启用"
    3. 为站点增加ISAPI筛选器:
      1. 在站点的功能视图中选择"ISAPI筛选器",执行"添加"
      2. 添加isapi_redirect.dll作为一个ISAPI筛选器
    4. 打开站点的ISAPI/CGI限制:
      1. 选择IIS根节点中的"ISAPI和CGI限制",执行"添加"
      2. 添加isapi_redirect.dll,确认允许执行
  3. 测试。

真正的牛叉山寨~

山寨版………………CPU!!!

架构——看着纯忽悠

cpu——我晕~~

整机——太牛了……

可以玩游戏——点点点~~~

作者——admire到死~~

这就是美国加州游戏开发人员Steve Chamberlin向我们展示的至高境界的DIY。从2007年起,他就开始了“BMOW”项目(Big Mess of Wires/一堆乱麻),目标是使用加法器、计数器、或非元件、触发器等标准零部件,制作一个8位处理器,相当于二十世纪八十年代初的水平,最近终于完成了第一个作品“BMOW-1”——以后也许还会有二号、三号……

既然是手工作品,就不可能像我们常用的微处理器那样把数十亿个晶体管集成在几百平方毫米的空间内。事实上,BMOW-1的面积约有450平方厘米,是个极其复杂的大块头:基础是一块Augat绕线板,之上已经预先装好了1250个针脚,需要手工给它们镀金,然后连接2500条线,有些地方甚至要堆叠十层(可以想象一下铜互连)。Chamberlin说他最快可以每小时做25个这样的连接,也就是全部完成至少得100个小时,不吃不喝不睡觉也得干四天多。

当然这不但是个技术活,也需要金钱做后盾,单单是材料费就花了大概3000美元(得镀金呢)。

BMOW-1处理器目前的运行频率是2MHz,理论上可以跑到3MHz。虽然只相当于现代微处理器的零头,但已经可以胜任很多工作了,比如Basic语言编程,比如玩玩吃豆子、国际象棋之类的小游戏。

其它主要规格:

  • RAM:512KB
  • ROM:512KB
  • 视频:512×480分辨率、双色;128×240分辨率、256色
  • 音频:三种声音,可编程
  • 键盘:PS/2接口PC标准型
  • Debug LCD:可显示两行24个字符,调试之用
  • 功耗:10W (2.0A×5.0V)

其实这个牛得一塌糊涂的手工处理器在今年五月底就已完成,Chamberlin还带着它参加了一年一度的创意大会Maker Faire,自然是博得满堂彩。今天我们旧事重提,就是和Intel的工业级流水线对比一下,让大家细细欣赏一遍,也证明那句广告词:Impossible is nothing!

图太多了,大家自己去看吧

http://news.mydrivers.com/1/139/139180.htm

继续接上文

101 More Great Computer Quotes

Computing

  1. "I do not fear computers. I fear lack of them."
    – Isaac Asimov
  2. "A computer once beat me at chess, but it was no match for me at kick boxing."
    – Emo Philips
  3. "Computer Science is no more about computers than astronomy is about telescopes."
    – Edsger W. Dijkstra
  4. "The computer was born to solve problems that did not exist before."
    – Bill Gates
  5. "Software is like entropy: It is difficult to grasp, weighs nothing, and obeys the Second Law of Thermodynamics; i.e., it always increases."
    – Norman Augustine
  6. "Software is a gas; it expands to fill its container."
    – Nathan Myhrvold
  7. "All parts should go together without forcing. You must remember that the parts you are reassembling were disassembled by you. Therefore, if you can’t get them together again, there must be a reason. By all means, do not use a hammer."
    – IBM Manual, 1925
  8. "Standards are always out of date. That’s what makes them standards."
    – Alan Bennett
  9. "Physics is the universe’s operating system."
    – Steven R Garman
  10. "It’s hardware that makes a machine fast. It’s software that makes a fast machine slow."
    – Craig Bruce

Knowledge

  1. "Imagination is more important than knowledge. For knowledge is limited, whereas imagination embraces the entire world, stimulating progress, giving birth to evolution."
    – Albert Einstein
  2. "The greatest enemy of knowledge is not ignorance, it is the illusion of knowledge."
    – Stephen Hawking
  3. "The more you know, the more you realize you know nothing."
    – Socrates
  4. "Tell me and I forget. Teach me and I remember. Involve me and I learn."
    – Benjamin Franklin
  5. "Real knowledge is to know the extent of one’s ignorance."
    – Confucius
  6. "If people never did silly things, nothing intelligent would ever get done."
    – Ludwig Wittgenstein
  7. "Getting information off the Internet is like taking a drink from a fire hydrant."
    – Mitchell Kapor

Users

  1. "If you think your users are idiots, only idiots will use it."
    – Linus Torvalds
  2. "From a programmer’s point of view, the user is a peripheral that types when you issue a read request."
    – P.Williams
  3. "Where is the ‘any’ key?”
    – Homer Simpson, in response to the message, “Press any key"
  4. "Computers are good at following instructions, but not at reading your mind."
    – Donald Knuth
  5. "There is only one problem with common sense; it’s not very common."
    – Milt Bryce
  6. "Your most unhappy customers are your greatest source of learning."
    – Bill Gates
  7. "Let us change our traditional attitude to the construction of programs: Instead of imagining that our main task is to instruct a computer what to do, let us concentrate rather on explaining to human beings what we want a computer to do."
    – Donald E.Knuth

Internet

  1. "The Internet? We are not interested in it."
    – Bill Gates, 1993
  2. "The best way to get accurate information on Usenet is to post something wrong and wait for corrections."
    – Matthew Austern

Professionals

  1. "The most likely way for the world to be destroyed, most experts agree, is by accident. That’s where we come in; we’re computer professionals. We cause accidents."
    – Nathaniel Borenstein
  2. "Pessimists, we’re told, look at a glass containing 50% air and 50% water and see it as half empty. Optimists, in contrast, see it as half full. Engineers, of course, understand the glass is twice as big as it needs to be."
    – Bob Lewis
  3. "In a room full of top software designers, if two agree on the same thing, that’s a majority."
    – Bill Curtis
  4. "It should be noted that no ethically-trained software engineer would ever consent to write a DestroyBaghdad procedure. Basic professional ethics would instead require him to write a DestroyCity procedure, to which Baghdad could be given as a parameter."
    – Nathaniel S.Borenstein
  5. "Mostly, when you see programmers, they aren’t doing anything. One of the attractive things about programmers is that you cannot tell whether or not they are working simply by looking at them. Very often they’re sitting there seemingly drinking coffee and gossiping, or just staring into space. What the programmer is trying to do is get a handle on all the individual and unrelated ideas that are scampering around in his head."
    – Charles M.Strauss
  6. "If you think you are worth what you know, you are very wrong. Your knowledge today does not have much value beyond a couple of years. Your value is what you can learn and how easily you can adapt to the changes this profession brings so often."
    – Jose M.Aguilar

Programming

  1. "Programs must be written for people to read, and only incidentally for machines to execute."
    – Abelson and Sussman
  2. "Commenting your code is like cleaning your bathroom — you never want to do it, but it really does create a more pleasant experience for you and your guests."
    – Ryan Campbell
  3. "We have to stop optimizing for programmers and start optimizing for users."
    – Jeff Atwood
  4. "Low-level programming is good for the programmer’s soul."
    – John Carmack
  5. "It’s OK to figure out murder mysteries, but you shouldn’t need to figure out code. You should be able to read it."
    – Steve McConnell
  6. "If we wish to count lines of code, we should not regard them as ‘lines produced’ but as ‘lines spent.’"
    – Edsger Dijkstra
  7. "Programming can be fun, so can cryptography; however they should not be combined."
    – Kreitzberg and Shneiderman
  8. "Before software should be reusable, it should be usable."
    – Ralph Johnson
  9. "If you automate a mess, you get an automated mess."
    – Rod Michael
  10. "Looking at code you wrote more than two weeks ago is like looking at code you are seeing for the first time."
    – Dan Hurvitz
  11. "It is easier to change the specification to fit the program than vice versa."
    – Alan Perlis
  12. "Less than 10% of the code has to do with the ostensible purpose of the system; the rest deals with input-output, data validation, data structure maintenance, and other housekeeping."
    – Mary Shaw
  13. "If you have a procedure with ten parameters, you probably missed some."
    – Alan Perlis
  14. "How rare it is that maintaining someone else’s code is akin to entering a beautifully designed building, which you admire as you walk around and plan how to add a wing or do some redecorating. More often, maintaining someone else’s code is like being thrown headlong into a big pile of slimy, smelly garbage."
    – Bill Venners
  15. "Code generation, like drinking alcohol, is good in moderation."
    – Alex Lowe

Development

  1. "Simplicity, carried to the extreme, becomes elegance."
    – Jon Franklin
  2. "A program is never less than 90% complete, and never more than 95% complete."
    – Terry Baker
  3. "When you are stuck in a traffic jam with a Porsche, all you do is burn more gas in idle. Scalability is about building wider roads, not about building faster cars."
    – Steve Swartz
  4. "Everyone by now presumably knows about the danger of premature optimization. I think we should be just as worried about premature design — designing too early what a program should do."
    – Paul Graham
  5. "Programming without an overall architecture or design in mind is like exploring a cave with only a flashlight: You don’t know where you’ve been, you don’t know where you’re going, and you don’t know quite where you are."
    – Danny Thorpe
  6. "The best way to predict the future is to implement it."
    – David Heinemeier Hansson
  7. "We need above all to know about changes; no one wants or needs to be reminded 16 hours a day that his shoes are on."
    – David Hubel
  8. "On two occasions I have been asked, ‘If you put into the machine wrong figures, will the right answers come out?’ I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."
    – Charles Babbage
  9. "Make everything as simple as possible, but not simpler."
    – Albert Einstein
  10. "Today, most software exists, not to solve a problem, but to interface with other software."
    – IO Angell
  11. "Good specifications will always improve programmer productivity far better than any programming tool or technique."
    – Milt Bryce
  12. "The difference between theory and practice is that in theory, there is no difference between theory and practice."
    – Richard Moore

Quality

  1. "Don’t document the problem, fix it."
    – Atli Björgvin Oddsson
  2. "As a rule, software systems do not work well until they have been used, and have failed repeatedly, in real applications."
    – Dave Parnas
  3. "If the code and the comments do not match, possibly both are incorrect."
    – Norm Schryer
  4. "I think it’s a new feature. Don’t tell anyone it was an accident."
    – Larry Wall
  5. "If you don’t handle [exceptions], we shut your application down. That dramatically increases the reliability of the system."
    – Anders Hejlsberg
  6. "When debugging, novices insert corrective code; experts remove defective code."
    – Richard Pattis
  7. "In a software project team of 10, there are probably 3 people who produce enough defects to make them net negative producers."
    – Gordon Schulmeyer
  8. "I think it is inevitable that people program poorly. Training will not substantially help matters. We have to learn to live with it."
    – Alan Perlis
  9. "Program testing can be a very effective way to show the presence of bugs, but is hopelessly inadequate for showing their absence."
    – Edsger Dijkstra

Programming Languages

  1. "Manually managing blocks of memory in C is like juggling bars of soap in a prison shower: It’s all fun and games until you forget about one of them."
    – anonymous Usenet user
  2. "There’s no obfuscated Perl contest because it’s pointless."
    – Jeff Polk
  3. "Java is the most distressing thing to hit computing since MS-DOS."
    – Alan Kay
  4. "There are only two things wrong with C++: The initial concept and the implementation."
    – Bertrand Meyer
  5. "It was a joke, okay? If we thought it would actually be used, we wouldn’t have written it!"
    – Mark Andreesen, speaking of the HTML tag BLINK
  6. "Web Services are like teenage sex. Everyone is talking about doing it, and those who are actually doing it are doing it badly."
    – Michelle Bustamante
  7. "Perl: The only language that looks the same before and after RSA encryption."
    – Keith Bostic
  8. "I didn’t work hard to make Ruby perfect for everyone, because you feel differently from me. No language can be perfect for everyone. I tried to make Ruby perfect for me, but maybe it’s not perfect for you. The perfect language for Guido van Rossum is probably Python.”
    – Yukihiro Matsumoto, aka “Matz", creator of Ruby
  9. "XML is not a language in the sense of a programming language any more than sketches on a napkin are a language."
    – Charles Simonyi
  10. "BASIC is to computer programming as QWERTY is to typing."
    – Seymour Papert
  11. "It has been discovered that C++ provides a remarkable facility for concealing the trivial details of a program — such as where its bugs are."
    – David Keppel
  12. "UNIX is simple. It just takes a genius to understand its simplicity."
    – Dennis Ritchie
  13. "Some people, when confronted with a problem, think ‘I know, I’ll use regular expressions.’ Now they have two problems."
    – Jamie Zawinski

Security

  1. "I think computer viruses should count as life. I think it says something about human nature that the only form of life we have created so far is purely destructive. We’ve created life in our own image."
    – Stephen Hawking
  2. "The only truly secure system is one that is powered off, cast in a block of concrete and sealed in a lead-lined room with armed guards."
    – Gene Spafford
  3. "Being able to break security doesn’t make you a hacker anymore than being able to hotwire cars makes you an automotive engineer."
    – Eric Raymond
  4. "Companies spend millions of dollars on firewalls, encryption and secure access devices, and it’s money wasted, because none of these measures address the weakest link in the security chain."
    – Kevin Mitnick
  5. "If you think technology can solve your security problems, then you don’t understand the problems and you don’t understand the technology."
    – Bruce Schneier
  6. "Hoaxes use weaknesses in human behavior to ensure they are replicated and distributed. In other words, hoaxes prey on the Human Operating System."
    – Stewart Kirkpatrick
  7. "Passwords are like underwear: you don’t let people see it, you should change it very often, and you shouldn’t share it with strangers."
    – Chris Pirillo

Companies

  1. "I am not out to destroy Microsoft, that would be a completely unintended side effect."
    – Linus Torvalds
  2. "Yes, we have a dress code. You have to dress."
    – Scott McNealy, co-founder of Sun Microsystems
  3. "In an information economy, the most valuable company assets drive themselves home every night. If they are not treated well, they do not return the next morning."
    – Peter Chang
  4. "It’s better to wait for a productive programmer to become available than it is to wait for the first available programmer to become productive."
    – Steve McConnell
  5. "I’m not one of those who think Bill Gates is the devil. I simply suspect that if Microsoft ever met up with the devil, it wouldn’t need an interpreter."
    – Nicholas Petreley

Predictions

  1. "Two years from now, spam will be solved."
    – Bill Gates, 2004
  2. "The problem of viruses is temporary and will be solved in two years."
    – John McAfee, 1988
  3. "Computer viruses are an urban legend."
    – Peter Norton, 1988
  4. "In 2031, lawyers will be commonly a part of most development teams."
    – Grady Booch
  5. "I don’t know what the language of the year 2000 will look like, but I know it will be called Fortran."
    – CA Hoare, 1982
  6. "In the future, computers may weigh no more than 1.5 tonnes."
    – Popular mechanics, 1949
  7. "I see little commercial potential for the Internet for at least ten years."
    – Bill Gates, 1994
  8. "Before man reaches the moon, mail will be delivered within hours from New York to California, to Britain, to India or Australia."
    – Arthur Summerfield, 1959, United States Post

接上文

101 Great Computer Programming Quotes

"People always fear change. People feared electricity when it was invented, didn't they? People feared coal, they feared gas-powered engines. There will always be ignorance, and ignorance leads to fear. But with time, people will come to accept their silicon masters."

As Bill Gates once warned, computers have indeed become our silicon masters, pervading nearly every aspect of our modern lives. As a result, some of the greatest minds of our time have pondered the significance of computers and software on the human condition. Following are 101 great quotes about computers, with an emphasis on programming, since after all this is a software development site.

Computers

  1. "Computers are useless. They can only give you answers."
    (Pablo Picasso)
  2. "Computers are like bikinis. They save people a lot of guesswork."
    (Sam Ewing)
  3. "They have computers, and they may have other weapons of mass destruction."
    (Janet Reno)
  4. "That's what's cool about working with computers. They don't argue, they remember everything, and they don't drink all your beer."
    (Paul Leary)
  5. "If the automobile had followed the same development cycle as the computer, a Rolls-Royce would today cost $100, get a million miles per gallon, and explode once a year, killing everyone inside."
    (Robert X. Cringely)

Computer Intelligence

  1. "Computers are getting smarter all the time. Scientists tell us that soon they will be able to talk to us. (And by ‘they', I mean ‘computers'. I doubt scientists will ever be able to talk to us.)"
    (Dave Barry)
  2. "I've noticed lately that the paranoid fear of computers becoming intelligent and taking over the world has almost entirely disappeared from the common culture. Near as I can tell, this coincides with the release of MS-DOS."
    (Larry DeLuca)
  3. "The question of whether computers can think is like the question of whether submarines can swim."
    (Edsger W. Dijkstra)
  4. "It's ridiculous to live 100 years and only be able to remember 30 million bytes. You know, less than a compact disc. The human condition is really becoming more obsolete every minute."
    (Marvin Minsky)

Trust

  1. "The city's central computer told you? R2D2, you know better than to trust a strange computer!"
    (C3PO)
  2. "Never trust a computer you can't throw out a window."
    (Steve Wozniak)

Hardware

  1. "Hardware: The parts of a computer system that can be kicked."
    (Jeff Pesis)

Software

  1. "Most software today is very much like an Egyptian pyramid with millions of bricks piled on top of each other, with no structural integrity, but just done by brute force and thousands of slaves."
    (Alan Kay)
  2. "I've finally learned what ‘upward compatible' means. It means we get to keep all our old mistakes."
    (Dennie van Tassel)

Operating Systems

  1. "There are two major products that come out of Berkeley: LSD and UNIX. We don't believe this to be a coincidence."
    (Jeremy S. Anderson)
  2. "19 Jan 2038 at 3:14:07 AM"
    (End of the word according to Unix–2^32 seconds after January 1, 1970)
  3. "Every operating system out there is about equal… We all suck."
    (Microsoft senior vice president Brian Valentine describing the state of the art in OS security, 2003)
  4. “Microsoft has a new version out, Windows XP, which according to everybody is the ‘most reliable Windows ever.‘ To me, this is like saying that asparagus is ‘the most articulate vegetable ever.‘ “
    (Dave Barry)

Internet

  1. "The Internet? Is that thing still around?"
    (Homer Simpson)
  2. "The Web is like a dominatrix. Everywhere I turn, I see little buttons ordering me to Submit."
    (Nytwind)
  3. "Come to think of it, there are already a million monkeys on a million typewriters, and Usenet is nothing like Shakespeare."
    (Blair Houghton)

Software Industry

  1. "The most amazing achievement of the computer software industry is its continuing cancellation of the steady and staggering gains made by the computer hardware industry."
    (Henry Petroski)
  2. "True innovation often comes from the small startup who is lean enough to launch a market but lacks the heft to own it."
    (Timm Martin)
  3. "It has been said that the great scientific disciplines are examples of giants standing on the shoulders of other giants. It has also been said that the software industry is an example of midgets standing on the toes of other midgets."
    (Alan Cooper)
  4. "It is not about bits, bytes and protocols, but profits, losses and margins."
    (Lou Gerstner)
  5. "We are Microsoft. Resistance Is Futile. You Will Be Assimilated."
    (Bumper sticker)

Software Demos

  1. "No matter how slick the demo is in rehearsal, when you do it in front of a live audience, the probability of a flawless presentation is inversely proportional to the number of people watching, raised to the power of the amount of money involved."
    (Mark Gibbs)

Software Patents

  1. "The bulk of all patents are crap. Spending time reading them is stupid. It's up to the patent owner to do so, and to enforce them."
    (Linus Torvalds)

Complexity

  1. "Controlling complexity is the essence of computer programming."
    (Brian Kernigan)
  2. "Complexity kills. It sucks the life out of developers, it makes products difficult to plan, build and test, it introduces security challenges, and it causes end-user and administrator frustration."
    (Ray Ozzie)
  3. "There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies."
    (C.A.R. Hoare)
  4. "The function of good software is to make the complex appear to be simple."
    (Grady Booch)

Ease of Use

  1. "Just remember: you're not a ‘dummy,' no matter what those computer books claim. The real dummies are the people who–though technically expert–couldn't design hardware and software that's usable by normal consumers if their lives depended upon it."
    (Walter Mossberg)
  2. "Software suppliers are trying to make their software packages more ‘user-friendly'… Their best approach so far has been to take all the old brochures and stamp the words ‘user-friendly' on the cover."
    (Bill Gates)
  3. "There's an old story about the person who wished his computer were as easy to use as his telephone. That wish has come true, since I no longer know how to use my telephone."
    (Bjarne Stroustrup)

Users

  1. "Any fool can use a computer. Many do."
    (Ted Nelson)
  2. "There are only two industries that refer to their customers as ‘users'."
    (Edward Tufte)

Programmers

  1. "Programmers are in a race with the Universe to create bigger and better idiot-proof programs, while the Universe is trying to create bigger and better idiots. So far the Universe is winning."
    (Rich Cook)
  2. "Most of you are familiar with the virtues of a programmer. There are three, of course: laziness, impatience, and hubris."
    (Larry Wall)
  3. "The trouble with programmers is that you can never tell what a programmer is doing until it's too late."
    (Seymour Cray)
  4. "That's the thing about people who think they hate computers. What they really hate is lousy programmers."
    (Larry Niven)
  5. "For a long time it puzzled me how something so expensive, so leading edge, could be so useless. And then it occurred to me that a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are, in short, a perfect match."
    (Bill Bryson)
  6. "Computer science education cannot make anybody an expert programmer any more than studying brushes and pigment can make somebody an expert painter."
    (Eric Raymond)
  7. "A programmer is a person who passes as an exacting expert on the basis of being able to turn out, after innumerable punching, an infinite series of incomprehensive answers calculated with micrometric precisions from vague assumptions based on debatable figures taken from inconclusive documents and carried out on instruments of problematical accuracy by persons of dubious reliability and questionable mentality for the avowed purpose of annoying and confounding a hopelessly defenseless department that was unfortunate enough to ask for the information in the first place."
    (IEEE Grid newsmagazine)
  8. "A hacker on a roll may be able to produce–in a period of a few months–something that a small development group (say, 7-8 people) would have a hard time getting together over a year. IBM used to report that certain programmers might be as much as 100 times as productive as other workers, or more."
    (Peter Seebach)
  9. "The best programmers are not marginally better than merely good ones. They are an order-of-magnitude better, measured by whatever standard: conceptual creativity, speed, ingenuity of design, or problem-solving ability."
    (Randall E. Stross)
  10. "A great lathe operator commands several times the wage of an average lathe operator, but a great writer of software code is worth 10,000 times the price of an average software writer."
    (Bill Gates)

Programming

  1. "Don't worry if it doesn't work right. If everything did, you'd be out of a job."
    (Mosher's Law of Software Engineering)
  2. "Measuring programming progress by lines of code is like measuring aircraft building progress by weight."
    (Bill Gates)
  3. "Writing code has a place in the human hierarchy worth somewhere above grave robbing and beneath managing."
    (Gerald Weinberg)
  4. "First learn computer science and all the theory. Next develop a programming style. Then forget all that and just hack."
    (George Carrette)
  5. "First, solve the problem. Then, write the code."
    (John Johnson)
  6. "Optimism is an occupational hazard of programming; feedback is the treatment."
    (Kent Beck)
  7. "To iterate is human, to recurse divine."
    (L. Peter Deutsch)
  8. "The best thing about a boolean is even if you are wrong, you are only off by a bit."
    (Anonymous)
  9. "Should array indices start at 0 or 1? My compromise of 0.5 was rejected without, I thought, proper consideration."
    (Stan Kelly-Bootle)

Programming Languages

  1. "There are only two kinds of programming languages: those people always bitch about and those nobody uses."
    (Bjarne Stroustrup)
  2. "PHP is a minor evil perpetrated and created by incompetent amateurs, whereas Perl is a great and insidious evil perpetrated by skilled but perverted professionals."
    (Jon Ribbens)
  3. "The use of COBOL cripples the mind; its teaching should therefore be regarded as a criminal offense."
    (E.W. Dijkstra)
  4. ""It is practically impossible to teach good programming style to students that have had prior exposure to BASIC. As potential programmers, they are mentally mutilated beyond hope of regeneration."
    (E. W. Dijkstra)
  5. "I think Microsoft named .Net so it wouldn't show up in a Unix directory listing."
    (Oktal)
  6. "There is no programming language–no matter how structured–that will prevent programmers from making bad programs."
    (Larry Flon)
  7. "Computer language design is just like a stroll in the park. Jurassic Park, that is."
    (Larry Wall)

C/C++"

  1. "Fifty years of programming language research, and we end up with C++?"
    (Richard A. O'Keefe)
  2. "Writing in C or C++ is like running a chain saw with all the safety guards removed."
    (Bob Gray)
  3. "In C++ it's harder to shoot yourself in the foot, but when you do, you blow off your whole leg."
    (Bjarne Stroustrup)
  4. "C++ : Where friends have access to your private members."
    (Gavin Russell Baker)
  5. "One of the main causes of the fall of the Roman Empire was that–lacking zero–they had no way to indicate successful termination of their C programs."
    (Robert Firth)

Java

  1. "Java is, in many ways, C++–."
    (Michael Feldman)
  2. "Saying that Java is nice because it works on all OSes is like saying that anal sex is nice because it works on all genders."
    (Alanna)
  3. "Fine, Java MIGHT be a good example of what a programming language should be like. But Java applications are good examples of what applications SHOULDN'T be like."
    (pixadel)
  4. "If Java had true garbage collection, most programs would delete themselves upon execution."
    (Robert Sewell)

Open Source

  1. "Software is like sex: It's better when it's free."
    (Linus Torvalds)
  2. "The only people who have anything to fear from free software are those whose products are worth even less."
    (David Emery)

Code

  1. "Good code is its own best documentation."
    (Steve McConnell)
  2. "Any code of your own that you haven't looked at for six or more months might as well have been written by someone else."
    (Eagleson's Law)
  3. "The first 90% of the code accounts for the first 90% of the development time. The remaining 10% of the code accounts for the other 90% of the development time."
    (Tom Cargill)

Software Development

  1. "Good programmers use their brains, but good guidelines save us having to think out every case."
    (Francis Glassborow)
  2. "In software, we rarely have meaningful requirements. Even if we do, the only measure of success that matters is whether our solution solves the customer's shifting idea of what their problem is."
    (Jeff Atwood)
  3. "Considering the current sad state of our computer programs, software development is clearly still a black art, and cannot yet be called an engineering discipline."
    (Bill Clinton)
  4. "You can't have great software without a great team, and most software teams behave like dysfunctional families."
    (Jim McCarthy)

Debugging

  1. "As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs."
    (Maurice Wilkes discovers debugging, 1949)
  2. "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are–by definition–not smart enough to debug it."
    (Brian Kernighan)
  3. "If debugging is the process of removing bugs, then programming must be the process of putting them in."
    (Edsger W. Dijkstra)

Quality

  1. "I don't care if it works on your machine! We are not shipping your machine!"
    (Vidiu Platon)
  2. "Programming is like sex: one mistake and you're providing support for a lifetime."
    (Michael Sinz)
  3. "There are two ways to write error-free programs; only the third one works."
    (Alan J. Perlis)
  4. "You can either have software quality or you can have pointer arithmetic, but you cannot have both at the same time."
    (Bertrand Meyer)
  5. “If McDonalds were run like a software company, one out of every hundred Big Macs would give you food poisoning, and the response would be, ‘We're sorry, here's a coupon for two more.' “
    (Mark Minasi)
  6. "Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live."
    (Martin Golding)
  7. "To err is human, but to really foul things up you need a computer."
    (Paul Ehrlich)
  8. "A computer lets you make more mistakes faster than any invention in human history–with the possible exceptions of handguns and tequila."
    (Mitch Radcliffe)

Predictions

  1. "Everything that can be invented has been invented."
    (Charles H. Duell, Commissioner, U.S. Office of Patents, 1899)
  2. "I think there's a world market for about 5 computers."
    (Thomas J. Watson, Chairman of the Board, IBM, circa 1948)
  3. "It would appear that we have reached the limits of what it is possible to achieve with computer technology, although one should be careful with such statements, as they tend to sound pretty silly in 5 years."
    (John Von Neumann, circa 1949)
  4. "But what is it good for?"
    (Engineer at the Advanced Computing Systems Division of IBM, commenting on the microchip, 1968)
  5. "There is no reason for any individual to have a computer in his home."
    (Ken Olson, President, Digital Equipment Corporation, 1977)
  6. "640K ought to be enough for anybody."
    (Bill Gates, 1981)
  7. "Windows NT addresses 2 Gigabytes of RAM, which is more than any application will ever need."
    (Microsoft, on the development of Windows NT, 1992)
  8. "We will never become a truly paper-less society until the Palm Pilot folks come out with WipeMe 1.0."
    (Andy Pierson)
  9. "If it keeps up, man will atrophy all his limbs but the push-button finger."
    (Frank Lloyd Wright)
    "

语录:101条伟大的计算机编程名言

“人们总是害怕改变。电被发明出来的时候他们害怕电,是不是?他们害怕煤,害怕蒸汽机车。无知无所不在,并导致恐惧。但随着时间推移,人们终究会接受最新的科技。”

正如比尔盖茨曾经警告过一样,计算机已经真正成为我们的最新科技,几乎遍布我们日常生活的每一方面。所以,我们这个时代的某些最伟大的头脑开始思索起计算机和软件对于人类的重要性来了。以下就是101条有关计算机的伟大名言,并且,既然我们这个网站是一个软件开发网站,我们尤其关注编程方面的。

    计算机
  1. “计算机没什么用。他们只会告诉你答案。”
    (巴勃罗·毕加索,画家)
  2. “计算机就跟比基尼一样,省去了人们许多的胡思乱想。”
    (萨姆·尤因,作家)
  3. “他们拥有计算机,他们也还可能拥有其他的大规模杀伤性武器。”
    (珍内特·雷诺,美国前女司法部长)
  4. “跟计算机工作酷就酷在这里,它们不会生气,能记住所有东西,还有,它们不会喝光你的啤酒。”
    (保罗·利里,吉他手)
  5. “如果汽车能赶上计算机的发展周期的话,一辆今天的劳斯莱斯仅值100美元,每加仑要跑100万英里,每年还得爆炸一次,把里面的人杀个精光。”
    (Robert X.Cringely,技术作家)
    计算机智能
  6. “计算机总是越来越智能的。科学家告诉我们说不久它们就能跟我们对话了。(这里的“它们”,我指的是“计算机”。我怀疑科学家永远都不能跟我们对话。)”
    (Dave Barry,幽默作家)
  7. “我最近注意到,在共同文化中,那种对计算机变得智能化并最终掌控世界的妄想恐惧症几乎彻底消失了。据我所知,这跟MS-DOS的发布基本是同步的。”
    (Larry DeLuca)
  8. “计算机会不会思考这个问题就像问潜水艇会不会游泳一样。”
    (Edsger W.Dijkstra,图灵奖获得者)
  9. “活了一百年却只能记住30M字节是荒谬的。你知道,这比一张压缩盘还要少。人类境况正在变得日趋退化。”
    (Marvin Minsky,人工智能研究的奠基人)
    信任
  10. “这座城市的中央计算机告诉你的?R2D2,你不该相信一台陌生的计算机!”
    (C3PO,星球大战中的翻译机器人)
  11. “永远不要相信一台不能扔掉一扇窗户的计算机
    (斯蒂夫·沃兹尼亚克,苹果联合创始人)
    译者:暗指微软的wINDOWS操作系统
    硬件
  12. “硬件:计算机系统中可被踢的部分。”
    (Jeff Pesis)
    软件
  13. “今天大部分的软件都很像上百万块砖堆叠在一起组成的埃及金字塔,缺乏结构完整性,只能靠强力和成千上万的奴隶完成。”
    (阿伦·凯,图灵奖获得者,面向对象创始人)
  14. “我终于明白‘向上兼容性’是怎么回事了。这是指我们得保留所有原有错误。”
    (Dennie van Tassel)
    操作系统
  15. “有两样重要产品出自伯克利:LSD和BSD。我们不相信这是个巧合。”
    (Jeremy S.Anderson)
    译者:LSD是一种药力至强的迷幻剂,BSD(Berkeley Software Distribution,伯克利软件套件)是Unix的衍生系统。
  16. “2038年1月19日,凌晨3点14分07秒”
    UNIX中的世界末日–1970年1月1号之后的2^32秒)
    译者:word跟world同音,UNIX用4个字节(WORD)表示时间,所以最多只能计时2^32秒
  17. “每个操作系统都差不多… 我们都一样的烂。”
    (微软的高级副总裁布莱恩·瓦伦蒂尼这样描述操作系统的安全状况,2003)
  18. “微软有出了个新版本,Windows XP,据大家说是‘有史以来最稳定的Windows’, 对我而言, 这就好像是在说芦笋是‘有史以来发音最清脆的蔬菜一样’ “
    (Dave Barry)
    互联网
  19. “互联网?那个东西还在吗?”
    (Homer Simpson)
  20. “网络就像是个母夜叉。我每转到一处都会看见小个的按钮命令我提交。”
    (Nytwind)
    译者注:Submit:提交,另一层意思是要求屈服
  21. “想想看吧,已经有一百万只猴子坐在一百万台打字机旁,可Usenet就是比不上莎士比亚。”
    (Blair Houghton)
    软件产业
  22. “计算机软件产业最为惊人的成就,是其持续不断地放弃硬件产业的惊人成果和稳定性。”
    (Henry Petroski)
  23. “真正的创新经常来自于那些贴近市场、但无力拥有市场的的小型初创公司。”
    (Timm Martin)
  24. “人们常说,伟大的科学学科就像是站在其它巨人肩膀上的巨人。人们也说过,软件产业正如站在其他侏儒脚上的侏儒。”
    (Alan Cooper,交互设计之父)
  25. “这无关比特、字节和协议,而关乎利润和损益。”
    (郭士纳,IBM前CEO)
  26. “我们是微软。反抗是徒劳的。你会被同化的。”
    (保险杠贴纸)
    软件演示
  27. “不管演示在彩排的时候有多好,一旦在观众面前展示时,演示不出错的几率与观众人数成反比,与投入的金钱总额成正比。”
    (Mark Gibbs)
    软件专利
  28. “专利大多数都是垃圾。浪费时间去阅读这些专利是愚蠢的。只有专利持有人才会这么干,还得强迫自己才会看。”
    (Linus Torvalds,LINUX创始人)
    复杂性
  29. “控制复杂性是计算机编程的本质。”
    (Brian Kernigan)
  30. “复杂性杀死一切。它把程序员的生活给搞砸了,它令产品难以规划、创建和测试,带来了安全挑战,并导致最终用户和管理员沮丧不已。”
    (Ray Ozzie)
  31. “进行软件设计有两种方式。一种是让它尽量简单,让人看不出明显的不足。另一种是弄得尽量复杂,让人看不出明显的缺陷。”
    (C.A.R.Hoare)
  32. “好的软件的作用是让复杂的东西看起来简单。”
    (Grady Booch,UML创始人之一)
    易用性
  33. “不管那些计算机书籍如何宣称,只需记住,你并非‘傀儡’。真正的傀儡是那些无法设计出易于使用的硬件和软件的那些人,尽管他们是技术专家,因为这是普通消费者赖以生活的东西。”
    (Walter Mossberg,科技专栏记者)
  34. “软件供应商在努力尝试让他们的软件更‘易于操作’… 迄今为止,他们最好的办法就是翻出所有的老手册,然后在封面盖上‘易于操作’这几个字。”
    (比尔·盖茨)
  35. “有个老套的故事说有人希望他的计算机能像他的电话机一样好用。他的愿望实现了,因为我已经不知道该如何使用自己的电话了。”
    (Bjarne Stroustrup,C++之父)
    用户
  36. “任何一个傻瓜都会用电脑。很多都会。”
    (Ted Nelson)
  37. “只有两个行业把客户称为‘用户’。”
    (Edward Tufte,信息设计大师)
    译者注:一个是计算机设计,另一个是毒品交易,computer design and drug dealing
    程序员
  38. “程序员在跟宇宙赛跑,他们在努力开发出更大更好的傻瓜程序,而宇宙则努力培养出更大更好的白痴。到目前为止,宇宙领先。”
    (Rich Cook)
  39. “你们当中很多人都知道程序员的美德。当然啦,有三种:那就是懒惰、急躁以及傲慢。”
    (Larry Wall,Perl发明者)
  40. “程序员的问题是你无法预料他在做什么,直到为时已晚。”
    (Seymour Cray,超级计算机之父)
  41. “那就是这些自认为痛恨计算机的人的真实面目。他们实际上真正痛恨的是糟糕的程序员。”
    (拉瑞·尼文,科幻作家)
  42. “很长时间以来我一直困惑不已,为什么一些又贵又先进的东西会一点用都没有。直到我突然想起,计算机不就是一台愚蠢之至却拥有难以置信的做聪明事能力的机器嘛,而程序员不就是聪明绝顶却拥有难以置信的干蠢事的能力的人嘛。一句话,他们简直就是天生绝配。”
    (比尔·布莱森,旅游文学作家)
  43. “不像学学涂涂画画也能让某人成为专家级画家,计算机科学教育不会让任何人成为一名编程大师。”
    (埃里克·雷蒙,开源运动领袖)
  44. “一个程序员是经历以下事情后仍能证明自己是严格的专家的人:他可以历经数不清的捶打,可取材于无关紧要的文档,用上面的争议数据作出模糊假设,并以此计算出测微精度的无数片面理解的答案,并由一个不可靠、脑袋充满质疑、公开宣称要让一个倒霉透顶、没有指望、毫无防备,要求第一时间获得信息的部门狼狈不堪、令人生厌的人使用一台准确度有问题的仪器去实施。”
    (IEEE网格新闻杂志)
  45. “运气好的黑客能用几个月的时间 - 生产出一个小规模的开发团体(比如说,7-8人)历尽艰辛一起工作了一年多才能做出来的东西。IBM经常报告说某些程序员的生产力要比其它工人高百倍,甚至更多。”
    (Peter Seebach,黑客)
  46. “最好的程序员跟好的程序员相比可不止好那么一点点。这种好不是一个数量级的,取决于标准怎么定:概念创造性、速度、设计的独创性或者解决问题的能力。”
    (兰德尔·E·斯特劳斯,科技作家)
  47. “伟大的车工值得给他几倍于普通车工的薪水,但一个伟大的软件代码作家,其价值则要等同于一个普通的软件写手的价格的1万倍。”
    (比尔·盖茨)
    编程
  48. “就算它工作不正常也别担心。如果一切正常,你早该失业了。”
    (Mosher的软件工程定律)
  49. “靠代码行数来衡量开发进程就好比用重量来衡量飞机制造的进度。”
    (比尔·盖茨)
  50. “写代码的社会地位比盗墓的高,比管理的低。”
    (杰拉尔·德温伯格,软件与系统思想家)
  51. “首先学习计算机科学及理论。接着形成自己编程的风格。然后把这一切都忘掉,尽管改程序就是了。”
    (George Carrette,杰出软件工程师,开源推广者)
  52. “先解决问题再写代码。”
    (John Johnson)
  53. “乐观主义是编程行业的职业病;用户反馈则是治疗方法。”
    (Kent Beck)
  54. “迭代者为人,递归者为神。”
    (L.Peter Deutsch)
  55. “布尔值最好的一点是,就算你错了,也顶多错了一位而已。”
    (无名氏)
  56. “数组的下标是从0开始好还是从1开始好呢?我的0.5的折衷方案,以我之见,没有经过适当考虑就被否决掉了。”
    (Stan Kelly-Bootle)
    编程语言
  57. “只有两种编程语言:一种是天天挨骂的,另一种是没人用的。”
    (Bjarne Stroustrup,C++之父)
  58. “PHP是不合格的业余爱好者创建的,他们犯做了个小恶;Perl是娴熟而堕落的专家创建的,他们犯了阴险狡诈的大恶。”
    (Jon Ribbens)
  59. “COBOL的使用摧残大脑;其教育应被视为刑事犯罪。”
    (E.W.Dijkstra)
  60. “把良好的编程风格教给那些之前曾经接触过BASIC的学生几乎是不可能的。作为可能的程序员,他们已精神残废,无重塑的可能了。”
    (E.W.Dijkstra)
  61. “我想微软之所以把它叫做.Net,是因为这样它就不会在Unix的目录里显示出来了。”
    (Oktal)
  62. “There is no programming language – no matter how structured – that will prevent programmers from making bad programs。”
    (Larry Flon)
  63. “计算机语言设计犹如在公园里漫步。我是说侏罗纪公园。”
    (Larry Wall)
    C/C++
  64. “搞了50年的编程语言的研究,我们难道就以C++告终啦?”
    (Richard A.O'Keefe)
  65. “写C或者C++就像是在用一把卸掉所有安全防护装置的链锯。”
    (Bob Gray)
  66. “在C++里你想搬起石头砸自己的脚更为困难了,不过一旦你真的做了,整条腿都要报销。”
    (Bjarne Stroustrup)
  67. “C++ : 友人可造访你的私有成员之地也。”
    (Gavin Russell Baker)
    译者:Friends:C++的友元,是一种定义在类外部的普通函数,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。
  68. “罗马帝国灭亡的其中一个主要原因是他们没有0 - 这样他们就没法给自己的C程序指明成功退出的路径了。”
    (Robert Firth)
    Java
  69. “Java从许多方面来说就是C++–。”
    (Michael Feldman)
  70. “说Java好就好在运行于多个操作系统之上,就好像说肛交好就好在不管男女都行。”
    (Alanna)
  71. “好吧,Java也许是编程语言的好榜样。但Java应用则是应用程序的坏榜样。”
    (pixadel)
  72. “要是Java真的有垃圾回收的话,大部分程序在执行的时候就会把自己干掉了。”
    (Robert Sewell)
    开源
  73. “软件就像性事:免费/自由更好。”
    (Linus Torvalds)
  74. “唯一对免费软件感到害怕的人,是自己的产品还要不值钱的人。”
    (David Emery)
    代码
  75. “好代码本身就是最好的文档。”
    (Steve McConnell)
  76. “你自己的代码如果超过6个月不看,再看的时候也一样像是别人写的。”
    (伊格尔森定律)
  77. “前面90%的代码要占用开发时间的前90%。剩下的10%的代码要占用开发时间的另一90%。”
    (Tom Cargill)
    软件开发
  78. “好的程序员会用脑,但是好的向导救我们于样样都要想到。”
    (Francis Glassborow)
  79. “在软件里面,我们鲜有有意义的需求。就算有,衡量成功的唯一尺度也取决于我们的解决方案是否解决了客户对问题是什么的观念的转变。”
    (Jeff Atwood)
  80. “想想我们计算机程序的糟糕现状吧,很显然软件开发仍是黑箱艺术,还不能称之为工程学科。”
    (Bill Clinton,前美国总统)
  81. “没有伟大的团队就没有伟大的软件,可大部分的软件团队举止就像是支离破碎的家庭。”
    (吉姆·麦卡锡,微软VC++总监)
    调试
  82. “一旦我们开始编程,就会惊讶地发现让程序正常没想象中那么简单。调试不可避免。那一刻我认记忆犹新,当时我就意识到,从今往后我生活的大部分时间都要花在寻找自己程序的错误上面了。”
    (莫里斯·威尔克斯《调试探索》, 1949)
  83. “调试难度本来就是写代码的两倍。因此,如果你写代码的时候聪明用尽,根据定义,你就没有能耐去调试它了。”
    (Brian Kernighan)
  84. “如果调试是除虫的过程,那么编程就一定是把臭虫放进来的过程。”
    (Edsger W.Dijkstra)
    质量
  85. “我才不管它能不能在你的机器上运行呢!我们又没装到你的机器上!”
    (Vidiu Platon,罗马尼亚的微软最佳学生合作伙伴MSP)
  86. “编程就像性一样:一时犯错,终生维护。”
    (Michael Sinz)
  87. “有两种写出无错程序的办法;只有第三种有用。”
    (Alan J.Perlis)
  88. “软件质量与指针算法不可兼得。”
    (Bertrand Meyer)
  89. “如果麦当劳像软件公司那样运作的话,每一百个巨无霸就会有一个令你食物中毒,而他们的回应是,‘真对不起,这是一张额外附送两个的赠券。’”
    (Mark Minasi)
  90. “永远要这样写代码,好像最终维护你代码的人是个狂暴的、知道你住在哪里的精神病患者。”
    (Martin Golding)
  91. “是人都会犯错,不过要想把事情彻底搞砸还得请电脑出马。”
    (Paul Ehrlich)
  92. “计算机比人类历史上的任何发明都更快速地导致你犯更多的错误–可能除了手枪和龙舌兰酒是例外。”
    (Mitch Radcliffe)
    预测
  93. “能发明的东西都发明出来了。”
    (查尔斯·杜埃尔, 美国专利局局长,1899年)
  94. “我认为全球市场约需5台计算机。”
    (托马斯·沃森, IBM董事长, 约1948年)
  95. “看上去我们已经到达了利用计算机技术可能获得的极限了,尽管下这样的结论得小心,因为不出五年这听起来就会相当愚蠢。”
    (约翰·冯·诺伊曼,约1949年)
  96. “但这又有什么好处呢?”
    (IBM先进计算机系统部的工程师对微芯片的评论, 1968年)
  97. “我们没有理由让每一个人在家都拥有一台电脑。”
    (肯·奥尔森,数据设备公司(DEC)总裁,1977年)
  98. “640K对每一个人来说都已足够。”
    (比尔·盖茨,1981年)
  99. “Windows NT的RAM寻址空间可达2G,这比任何应用程序所需都要多。”
    (微软, 谈及Windows NT的开发时所言, 1992年)
  100. “我们永远也无法真正成为无纸化社会,直到掌上电脑一族发布擦我1.0(WipeMe 1.0)为止。”
    (安迪·皮尔逊,商界领袖)
    译者注:意思是说难道你大便不用纸吗?
  101. “长此以往,除了按键的手指外,人类的肢体将全部退化。”
    (弗兰克·劳埃德·赖特,建筑师)

大型网站架构演变和知识体系 zz

这篇文章很实用,尤其在自己白手起家搞网站的时候

之前也有一些介绍大型网站架构演变的文章,例如LiveJournal的、ebay的,都是非常值得参考的,不过感觉他们讲的更多的是每次演变的结果,而没有很详细的讲为什么需要做这样的演变,再加上近来感觉有不少同学都很难明白为什么一个网站需要那么复杂的技术,于是有了写这篇文章的想法,在这篇文章中将阐述一个普通的网站发展成大型网站过程中的一种较为典型的架构演变历程和所需掌握的知识体系,希望能给想从事互联网行业的同学一点初步的概念,文中的不对之处也请各位多给点建议,让本文真正起到抛砖引玉的效果。

架构演变第一步:物理分离webserver和数据库

最开始,由于某些想法,于是在互联网上搭建了一个网站,这个时候甚至有可能主机都是租借的,但由于这篇文章我们只关注架构的演变历程,因此就假设这个时候已经是托管了一台主机,并且有一定的带宽了,这个时候由于网站具备了一定的特色,吸引了部分人访问,逐渐你发现系统的压力越来越高,响应速度越来越慢,而这个时候比较明显的是数据库和应用互相影响,应用出问题了,数据库也很容易出现问题,而数据库出问题的时候,应用也容易出问题,于是进入了第一步演变阶段:将应用和数据库从物理上分离,变成了两台机器,这个时候技术上没有什么新的要求,但你发现确实起到效果了,系统又恢复到以前的响应速度了,并且支撑住了更高的流量,并且不会因为数据库和应用形成互相的影响。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

这一步架构演变对技术上的知识体系基本没有要求。

架构演变第二步:增加页面缓存

好景不长,随着访问的人越来越多,你发现响应速度又开始变慢了,查找原因,发现是访问数据库的操作太多,导致数据连接竞争激烈,所以响应变慢,但数据库连接又不能开太多,否则数据库机器压力会很高,因此考虑采用缓存机制来减少数据库连接资源的竞争和对数据库读的压力,这个时候首先也许会选择采用squid等类似的机制来将系统中相对静态的页面(例如一两天才会有更新的页面)进行缓存(当然,也可以采用将页面静态化的方案),这样程序上可以不做修改,就能够很好的减少对webserver的压力以及减少数据库连接资源的竞争,OK,于是开始采用squid来做相对静态的页面的缓存。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

前端页面缓存技术,例如squid,如想用好的话还得深入掌握下squid的实现方式以及缓存的失效算法等。

架构演变第三步:增加页面片段缓存

增加了squid做缓存后,整体系统的速度确实是提升了,webserver的压力也开始下降了,但随着访问量的增加,发现系统又开始变的有些慢了,在尝到了squid之类的动态缓存带来的好处后,开始想能不能让现在那些动态页面里相对静态的部分也缓存起来呢,因此考虑采用类似ESI之类的页面片段缓存策略,OK,于是开始采用ESI来做动态页面中相对静态的片段部分的缓存。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

页面片段缓存技术,例如ESI等,想用好的话同样需要掌握ESI的实现方式等;

架构演变第四步:数据缓存

在采用ESI之类的技术再次提高了系统的缓存效果后,系统的压力确实进一步降低了,但同样,随着访问量的增加,系统还是开始变慢,经过查找,可能会发现系统中存在一些重复获取数据信息的地方,像获取用户信息等,这个时候开始考虑是不是可以将这些数据信息也缓存起来呢,于是将这些数据缓存到本地内存,改变完毕后,完全符合预期,系统的响应速度又恢复了,数据库的压力也再度降低了不少。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

缓存技术,包括像Map数据结构、缓存算法、所选用的框架本身的实现机制等。

架构演变第五步:增加webserver

好景不长,发现随着系统访问量的再度增加,webserver机器的压力在高峰期会上升到比较高,这个时候开始考虑增加一台webserver,这也是为了同时解决可用性的问题,避免单台的webserver down机的话就没法使用了,在做了这些考虑后,决定增加一台webserver,增加一台webserver时,会碰到一些问题,典型的有:

1、如何让访问分配到这两台机器上,这个时候通常会考虑的方案是Apache自带的负载均衡方案,或LVS这类的软件负载均衡方案;

2、如何保持状态信息的同步,例如用户session等,这个时候会考虑的方案有写入数据库、写入存储、cookie或同步session信息等机制等;

3、如何保持数据缓存信息的同步,例如之前缓存的用户数据等,这个时候通常会考虑的机制有缓存同步或分布式缓存;

4、如何让上传文件这些类似的功能继续正常,这个时候通常会考虑的机制是使用共享文件系统或存储等;

在解决了这些问题后,终于是把webserver增加为了两台,系统终于是又恢复到了以往的速度。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

负载均衡技术(包括但不限于硬件负载均衡、软件负载均衡、负载算法、linux转发协议、所选用的技术的实现细节等)、主备技术(包括但不限于ARP欺骗、linux heart-beat等)、状态信息或缓存同步技术(包括但不限于Cookie技术、UDP协议、状态信息广播、所选用的缓存同步技术的实现细节等)、共享文件技术(包括但不限于NFS等)、存储技术(包括但不限于存储设备等)。

架构演变第六步:分库

享受了一段时间的系统访问量高速增长的幸福后,发现系统又开始变慢了,这次又是什么状况呢,经过查找,发现数据库写入、更新的这些操作的部分数据库连接的资源竞争非常激烈,导致了系统变慢,这下怎么办呢,此时可选的方案有数据库集群和分库策略,集群方面像有些数据库支持的并不是很好,因此分库会成为比较普遍的策略,分库也就意味着要对原有程序进行修改,一通修改实现分库后,不错,目标达到了,系统恢复甚至速度比以前还快了。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

这一步更多的是需要从业务上做合理的划分,以实现分库,具体技术细节上没有其他的要求;

但同时随着数据量的增大和分库的进行,在数据库的设计、调优以及维护上需要做的更好,因此对这些方面的技术还是提出了很高的要求的。

架构演变第七步:分表、DAL和分布式缓存

随着系统的不断运行,数据量开始大幅度增长,这个时候发现分库后查询仍然会有些慢,于是按照分库的思想开始做分表的工作,当然,这不可避免的会需要对程序进行一些修改,也许在这个时候就会发现应用自己要关心分库分表的规则等,还是有些复杂的,于是萌生能否增加一个通用的框架来实现分库分表的数据访问,这个在ebay的架构中对应的就是DAL,这个演变的过程相对而言需要花费较长的时间,当然,也有可能这个通用的框架会等到分表做完后才开始做,同时,在这个阶段可能会发现之前的缓存同步方案出现问题,因为数据量太大,导致现在不太可能将缓存存在本地,然后同步的方式,需要采用分布式缓存方案了,于是,又是一通考察和折磨,终于是将大量的数据缓存转移到分布式缓存上了。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

分表更多的同样是业务上的划分,技术上涉及到的会有动态hash算法、consistent hash算法等;

DAL涉及到比较多的复杂技术,例如数据库连接的管理(超时、异常)、数据库操作的控制(超时、异常)、分库分表规则的封装等;

架构演变第八步:增加更多的webserver

在做完分库分表这些工作后,数据库上的压力已经降到比较低了,又开始过着每天看着访问量暴增的幸福生活了,突然有一天,发现系统的访问又开始有变慢的趋势了,这个时候首先查看数据库,压力一切正常,之后查看webserver,发现apache阻塞了很多的请求,而应用服务器对每个请求也是比较快的,看来是请求数太高导致需要排队等待,响应速度变慢,这还好办,一般来说,这个时候也会有些钱了,于是添加一些webserver服务器,在这个添加webserver服务器的过程,有可能会出现几种挑战:

1、Apache的软负载或LVS软负载等无法承担巨大的web访问量(请求连接数、网络流量等)的调度了,这个时候如果经费允许的话,会采取的方案是购买硬件负载,例如F5、Netsclar、Athelon之类的,如经费不允许的话,会采取的方案是将应用从逻辑上做一定的分类,然后分散到不同的软负载集群中;

2、原有的一些状态信息同步、文件共享等方案可能会出现瓶颈,需要进行改进,也许这个时候会根据情况编写符合网站业务需求的分布式文件系统等;

在做完这些工作后,开始进入一个看似完美的无限伸缩的时代,当网站流量增加时,应对的解决方案就是不断的添加webserver。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

到了这一步,随着机器数的不断增长、数据量的不断增长和对系统可用性的要求越来越高,这个时候要求对所采用的技术都要有更为深入的理解,并需要根据网站的需求来做更加定制性质的产品。

架构演变第九步:数据读写分离和廉价存储方案

突然有一天,发现这个完美的时代也要结束了,数据库的噩梦又一次出现在眼前了,由于添加的webserver太多了,导致数据库连接的资源还是不够用,而这个时候又已经分库分表了,开始分析数据库的压力状况,可能会发现数据库的读写比很高,这个时候通常会想到数据读写分离的方案,当然,这个方案要实现并不容易,另外,可能会发现一些数据存储在数据库上有些浪费,或者说过于占用数据库资源,因此在这个阶段可能会形成的架构演变是实现数据读写分离,同时编写一些更为廉价的存储方案,例如BigTable这种。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

数据读写分离要求对数据库的复制、standby等策略有深入的掌握和理解,同时会要求具备自行实现的技术;

廉价存储方案要求对OS的文件存储有深入的掌握和理解,同时要求对采用的语言在文件这块的实现有深入的掌握。

架构演变第十步:进入大型分布式应用时代和廉价服务器群梦想时代

经过上面这个漫长而痛苦的过程,终于是再度迎来了完美的时代,不断的增加webserver就可以支撑越来越高的访问量了,对于大型网站而言,人气的重要毋庸置疑,随着人气的越来越高,各种各样的功能需求也开始爆发性的增长,这个时候突然发现,原来部署在webserver上的那个web应用已经非常庞大了,当多个团队都开始对其进行改动时,可真是相当的不方便,复用性也相当糟糕,基本是每个团队都做了或多或少重复的事情,而且部署和维护也是相当的麻烦,因为庞大的应用包在N台机器上复制、启动都需要耗费不少的时间,出问题的时候也不是很好查,另外一个更糟糕的状况是很有可能会出现某个应用上的bug就导致了全站都不可用,还有其他的像调优不好操作(因为机器上部署的应用什么都要做,根本就无法进行针对性的调优)等因素,根据这样的分析,开始痛下决心,将系统根据职责进行拆分,于是一个大型的分布式应用就诞生了,通常,这个步骤需要耗费相当长的时间,因为会碰到很多的挑战:

1、拆成分布式后需要提供一个高性能、稳定的通信框架,并且需要支持多种不同的通信和远程调用方式;

2、将一个庞大的应用拆分需要耗费很长的时间,需要进行业务的整理和系统依赖关系的控制等;

3、如何运维(依赖管理、运行状况管理、错误追踪、调优、监控和报警等)好这个庞大的分布式应用。

经过这一步,差不多系统的架构进入相对稳定的阶段,同时也能开始采用大量的廉价机器来支撑着巨大的访问量和数据量,结合这套架构以及这么多次演变过程吸取的经验来采用其他各种各样的方法来支撑着越来越高的访问量。

看看这一步完成后系统的图示:

这一步涉及到了这些知识体系:

这一步涉及的知识体系非常的多,要求对通信、远程调用、消息机制等有深入的理解和掌握,要求的都是从理论、硬件级、操作系统级以及所采用的语言的实现都有清楚的理解。

运维这块涉及的知识体系也非常的多,多数情况下需要掌握分布式并行计算、报表、监控技术以及规则策略等等。

说起来确实不怎么费力,整个网站架构的经典演变过程都和上面比较的类似,当然,每步采取的方案,演变的步骤有可能有不同,另外,由于网站的业务不同,会有不同的专业技术的需求,这篇blog更多的是从架构的角度来讲解演变的过程,当然,其中还有很多的技术也未在此提及,像数据库集群、数据挖掘、搜索等,但在真实的演变过程中还会借助像提升硬件配置、网络环境、改造操作系统、CDN镜像等来支撑更大的流量,因此在真实的发展过程中还会有很多的不同,另外一个大型网站要做到的远远不仅仅上面这些,还有像安全、运维、运营、服务、存储等,要做好一个大型的网站真的很不容易,写这篇文章更多的是希望能够引出更多大型网站架构演变的介绍。

枯燥的东西 zz

素材来自《猫头鹰与上帝的对话》,主要是一些围绕基督教上帝的思辨性讨论,全文没头没尾,也肯定有整理不当乃至于错误的地方。所有的讨论早就烂大街了,反正整理完了就发出来。

全能者(Omnipotence)

拉丁单词,Omni即全部,potence即能够。上帝能否造出自己也举不起的石头?由此引发对“不可能”的思考:

一、逻辑意义上的不可能

方的圆,大于整体的部分……上帝能否突破逻辑的法则?强的回答是,可以;折中的回答是,逻辑是上帝神圣属性或本质的一部分;弱的回答是不可以。设想这样一个问题:上帝能自杀么?

二、时限意义上的不可能
  1. 上帝能改变过去么?即便是基督教内部的许多思想家,如安瑟伦、哲罗姆、托马斯等,也否认这一点。
  2. 上帝能随意改变未来么?考虑一下上帝的许诺。祂能在做出某种许诺之后又反悔么?
    1. 如果可以反悔,则上帝口出无信,即便是人类有错在先也无法为此辩护。土师Jepthah许诺如果他从战场胜利归来的时候,将把第一个出门迎接他的家人献给上帝,后来他忍痛献出了自己的独生女作为祭奠。凡人尚且如此遵守诺言,上帝更应该言出必信,哪怕人间罪恶滔天,上帝的任何许诺都应该兑现。
    2. 如果不能反悔,则上帝必须限制自身随意更改未来的能力——此时的上帝就不再全能了。一种反驳是,能够做到而不去做,并不意味着不再全能。

以上第二小点实质上是一种道德意义上的不可能。

三、道德意义上的不可能

上帝能残暴地杀害一个善良的人么?强的回答是,可以——造物主有权杀死任何被造物,例如天降洪水淹死了诺亚方舟外的任何人——包括无辜的婴儿。另一个角度的说法是,不应该随意用人类的道德来批判上帝。

四、共相上的不可能

柏拉图认为,造物者(demiurge)洞察了先在的蓝图、形式或说共相(universals),并把先在的质料(matter)纳入其中,这就是创造的过程。柏拉图说的当然不是基督教中的上帝,但可以给我们以启示。无论从什么角度来理解“可能性”,深层次的思考是,究竟是上帝创造了可能性,还是先在的可能性限制着上帝。

全知者(Omniscience)

用反逻辑、反事实的荒谬问题(四条边的三角形如何定义?明天下午的三倍是多少?儿子通常比父亲大几岁?)来拷问上帝也许有点过分了,全知也许意味着上帝知道任何具有可知性的事情。虽然很多命题我们可以用无意义或者谬误来打发,但对于“本句话是假的”这句话到底是真是假这样的问题,不知上帝有何见教。但这类责难或许也不够有力,人类自己就“有可能”通过某些思考来解决或者消解掉悖论(多值逻辑、分层论……),更不用说上帝了。因此,还是关注一下更常见的辩论吧:

一、自由问题

通常的说法是,“上帝赋予了人类自由意志”。如果全知的上帝能够预测任何人的任何行为,这句话中的“自由”在上帝眼中还成其为“自由”么?人类曾经因罪触怒上帝降下灾祸,如果上帝早就预知了人类的罪恶并且这些人还都是祂自己造的,祂有啥好怒的?或者设想:上帝是一个忘情投入的剧作家,被自己创作出的人物和情节深深触动、大喜大悲。

二、超越时间的上帝

通常的说法是,上帝是外在于时间的,古往今来在上帝眼中统统表现为“永恒的现在 ”(Eternal Now)。立刻产生一个问题:如果一个先天的盲人无法理解色彩的话,外在于时间的上帝能够“感受、理解、知道”何谓时间么?祂能够真正了解和知道人类的“ 时间感”(覆水难收的过去、扑朔迷离的未来、沧桑的记忆、伤感的怀旧……)么?剧作家创作了一切,但只要他从不亲自上台表演自己写的剧本,就无法体会演员的种种。上帝是如此地关注、关爱着世界并且有所作为,因此理应在时间之内。似乎只能这么解释了——上帝想在时间外就可以在时间外,想在时间内就可以在时间内。

至善者(Ominibenevolent)

至善的根本表现就是上帝之爱——既不是君王居高临下之爱,也不是对等回报式的爱,而是真正的博爱。希腊文中eros之爱,主要指因为对象的可爱性质所激发的爱心,然而上帝之爱是agape,普遍、无条件、主动给予、永不转移的爱,归根结底,上帝就是爱。

这部分的辩论主要围绕道德标准来进行——人类通常理解的道德是非观,能往上帝身上套吗?或者上帝才是道德是非的最高、最终、唯一标准?依仗人类的道德观,很容易发现上帝尤其是旧约中的耶和华有邪恶色彩。将上帝纳入世俗道德评判体系,明显降格了上帝的地位。因此正统神学观点都倾向于说,上帝才是道德的判据。“ 因为虐杀一个善良的人是恶的,上帝不会做这样的事情”,这句话置上帝于人类道德观之下,似乎不符合正统神学的逻辑。似乎可以推论,没什么事情能够确保上帝绝不会做出不符合人类道德观的行为。如果人类的道德观来源于万能的造物主,我们有理由相信多数情况下上帝的行为和人类的道德观是一致的,但假使祂偏要做出不符合人类道德观的行为,我们既无可奈何,也没资格批判。上帝就是爱,造你是爱你,助你是爱你,杀你也是爱你,这样的“至善”,在非信徒的眼中是很难给予赞美的。

永恒性(Eternity)

亚里斯多德提出了质料因和形式因(动力因和目的因没有那么基本),任何事物都是质料和形式的结合,质料是被动的潜能,形式是能动的现实。

在亚里斯多德哲学的影响下,基督教神学中所谓的“存在大链条”(Great chain of Being)言明,上帝是不含任何潜能的纯现实,位于最高等级;下面是四个等级的天使序列,然后是人,最高的肉体化存在及最低的精神化存在。再下面是三个等级的生命形式,最底层是物质,不含任何实现性的纯潜能。

由此我们可以分析一下上帝永恒的内涵:

首先是单一性,祂不是质料和形式的合一,而是纯形式;其次是独存性,不依赖于任何别的事物而存在;最后是不变性,会变化的必不永恒,永恒的必不变化,变化和时间内在相关,因此上帝必在时间之外。

按照一般的哲学理解,一切事物(概念)的规定性在与该物(概念)与他物(概念)的相互关系当中。基督教神学同样沿袭的是这种思路,例如上帝之为创世主在于祂和世界的关系之上,这种关系就是,上帝创造了世界。如果本质寓于关系,关系的变化理应带来本质的变化。体现了上帝和世界之间关系的创世活动,本身就是一种带有时间属性和关系属性的变化,它理应带来上帝本质的变化。而按照上帝的永恒性,上帝永不发生任何变化……

人格性(Personality)

上帝在旧约中呈现出人格的多面性,有时候是万能的救主,有时候是可敬的圣者,有时候是专横的暴君;新约中的上帝的人格形象更单纯一点,就是慈父,就是爱的化身。

上帝人格性的系统哲学阐述始于近、现代,权威是生于1878年的德国人马丁•布伯。其关系哲学认为,人对世界有两种基本人生关系,“我—它”、“我—你”。人和上帝的关系是对“我—你”的统摄,上帝不是超然物外的神秘存在、抽象原理、理念等,而是必然介入人类的“永恒的你”,只有通过“我—永恒的你”的途径才能真正认识上帝。

和罗素合写了巨著《数学原理》的英国人怀特海创立了过程哲学,成为革新传统上帝观念的旗帜。这种学说认为,正统神学本质上是一种实体神学,把单一性、不变性、独存性、超时间性等僵化规定充作上帝最重要最完美的属性。过程哲学反对上帝的这些形而上属性,认为世界不是“实体 ”的聚集,而是“过程”的聚集,上帝寓于同人类的交互关系和过程当中。总之,这是一种新的上帝观,以后我们还会碰到。

本体论证明

正统神学家认为这是一种理想的证明思路,它不依赖于经验;另一些哲学家认为这类思路属于逻辑诡辩。本体论证明的主要代表人物是十一世纪的安瑟伦,以及十七世纪的笛卡尔。其大致逻辑是,只存在于心灵观念中的上帝并不完美,因此只要上帝是完美的,那就必然既存在于心灵也存在于现实。“不存在”是一种不完美的属性,这个属性不可能附加在完美的上帝身上,因此上帝必然存在。“存在”是上帝内禀的性质,就像“有三个角”是三角形的内禀性质一样。

笛卡尔同时代的法国人迦桑迪反驳说,任何事物首先要存在,其次才能谈论它的属性,不存在的事物既没有完满性,也没有不完满性。加在上帝概念上的完满性并非是什么必然存在的东西,而是我们从不完满世界的诸多理想中抽象出来的。

康德认为,假如删除宾词(存在)保留主词(上帝)会导致矛盾,那么宾词(存在)必然属于主词(上帝);然而如果把主词、宾词全部删除,则没有任何矛盾(让“ 上帝”以及“上帝存在”的说法整个地见鬼去吧)。更釜底抽薪地说,“存在”不是一个实在的宾词,它不能给被定义的概念增添什么实在的属性。例如正二十面体,它也许存在,也许不存在,无论如何,这一概念的诸属性(三维、二十个面、每个面全等)已经被全部定义好了。用数学证明出存在正十面体,这个新增加的“ 存在”并不是“正二十面体”实在属性的一部分。“存在”不过是一个判断中的系动词罢了,所有的存在命题都不是分析判断,而是综合判断。

二十世纪美国分析哲学家马尔科姆站在安瑟伦一边,他的思路是,很多事物都存在,但无所谓完满,可见“存在”本身不是完满性的体现,自然也不是上帝的内禀属性;但,必然存在的事物高于偶在的事物,“必然存在”是完满性的体现,可以作为上帝的内禀属性,这才是安瑟伦的真意。康德的反驳只能对抗普通的“存在命题 ”,不能对抗“必然存在命题”,这两类命题是有区别的。“上帝存在”这个判断暗含了在“存在”与“不存在”这两种可能性中选择了前者,然而“上帝必然存在 ”则根绝了“不存在”这种可能性。“上帝是必然存在的”,和“上帝是全能的、全知的……”之类的命题,具有同样的先验地位。

和安瑟伦同时代的法国僧侣高尼罗曾经用安瑟伦的思路来证明某种想象中无以伦比的海岛仙山必然存在。安瑟伦的回答是,上帝是一个自存、无限的概念,不能简单类比于什么海岛仙山。然而,和马尔科姆同时代的马乔里•黑特比高尼罗更狡猾,他用安瑟伦的思路来证明魔鬼的存在。

宇宙论论证

托马斯•阿奎那指明了五条大道:从事物的运动推论到第一推动者;从因果关系的无穷序列推论出第一因;从偶然的存在物推论出必然的存在者;从万事万物的等级推论出完善性;从世界的目的性推论出智慧的存在者。第二、三条被看作经典的宇宙论论证。

第二条,因果序列的论证思路,其前提是世界是可用因果关系来理解的并且由上帝这个第一因给出了最终的理解,显然不可知论者是不会答应的。其次,休谟对传统的因果关系早已作出了批判,认为因果关系不过是对不同时间发生的一些事情作一种习惯性的联想罢了,是人类思维整理的产物。一些当代哲学家根据物理学的发展,认为在微观领域应该放弃传统因果模式,代之以概率,也有主张用系统性、整体性观念代替线性因果关系的。詹姆士用实用主义来消解因果关系,认为事物的根据最终归因于人自身的意愿与需要。最后,即使必定有第一因,凭什么它就是上帝呢?

第三条,大意是一切现实事物都是偶在的,必然有某个必然的存在物作为其产生的根据或者存在的起点。这同第二种思路异曲同工,因此也将遭遇类似的反驳。

托马斯之外,还存在凯拉姆式(即伊斯兰教经院哲学)的宇宙论论证,其大意是万物有其时间上的开端,宇宙也有其时间上的开端,而那就是上帝。这一思路的当代支持者会拿宇宙大爆炸学说来当证据。然而科学理论并不会关注“奇点的存在根据”这样的哲学问题,“奇点之前、之外”在科学上都是无意义的说法,“宇宙的存在需要一个原因即上帝,上帝的存在不需要原因”同“宇宙的存在不需要原因”相比,根据奥卡姆剃刀原则,采信后者。

目的论论证

演绎式的目的论论证的典型即前述托马斯的第五条,其哲学渊源来自亚里斯多德。万事有其目的(据说水的目的就是低处),如箭有其目的并需要一位射箭者一般,万事万物需要一位上帝作指挥。这一思路论证力很弱,更值得关注的是归纳式的目的论论证,又称作设计论论证,盛于十八世纪。

设计论论证的代表人物是英国哲学家威廉•佩利。大意是,在海边杂乱的鹅卵石当中捡到一块精密的钟表,即使是不知道钟表原理的人甚至干脆就是没见过钟表的人,也不会认为这是自然产物,可以看出这个小怪物理应是按照某种目的而精心设计出来的被造物,因此必然存在一个智慧的设计者。同理,宇宙世界比钟表要精妙得多,因此必然存在一个有目的、有智慧的设计者,即上帝。

休谟跳出来了。首先,设计论论证是一种经验论证的思路,而在怀疑论的休谟看来,人类不可能获得有关上帝的经验。其次,钟表和宇宙之间的类比链条很脆弱,有什么根据可以阻止我们把宇宙类比为某种巨大而珍奇的植物或者动物呢?类比论证从本性上说就不是必然性的推理,也不可能有什么必然性的结论。再次,喜欢类比,不妨就滥用它吧。例如,钟表以及其他精密的被造物往往是人群合作的结果,即使存在宇宙的设计者,凭什么就是单一、万能的上帝呢?也许是很多神仙?或者甚至是魔鬼?精密的人类创造物凝聚了人类智慧的发展,最初的人造品都是粗糙的,或者我们可以联想到宇宙开初的混沌来自于一个笨拙的上帝而不是什么全知全能的伟大上帝。如果钟表可以随意的类比为宇宙,干脆把人和上帝类比一下算了,上帝也有七情六欲吃喝拉撒何如?另外,设计论论证中,说钟表精密是对比自然(杂乱的海滩鹅卵石)而言的,后面又反过来说宇宙、自然比钟表要精密的多——自然到底是杂乱的还是有秩序(精密)的,取决于设计论者们的随心所欲罢了。

道德论论证

这类思路多以不系统的形式散见于个别论著,没有形成大量研究资料或公认代表人物,也不是一种独立而成熟的证明方式,更多的是一种旁证。

常见的形式是,从道德律的客观性出发证明存在神圣的道德立法者,即上帝。或者根据人类所追求的道德理想的完善性崇高性,来证明作为道德主宰的上帝的存在。再者是根据人类基本道德理念的一致性,来证明道德的共同源泉,即上帝。然而所谓道德的客观性、一致性,真正坚信的人并不多,而且道德问题往往是笼统的而不是刚性的,是应然的而不是实然的,难有什么强有力的论证,因此这里不再赘述。

意志论论证

最著名的是数学天才帕斯卡的打赌论。他反对人类可能通过理性认识上帝的本质,上帝的存在无法获得彻底的证明,因此信还是不信,就像一场赌博。如果上帝不存在而信,没有太多损失,如果上帝存在而不信,却要下地狱,还是信吧。这个赌局,你的抵押是有限的,但可能的收益——永恒的生命和福祉——是无限的,不试图去搏一搏那无限的收益,是欠缺理智的。

十九世纪末著名的实用主义者威廉•詹姆斯认为,选择可以是有生命力的或者僵死的,有强制性的或者可回避的,价值重大的或无足轻重的。是否信仰上帝,就是有生命力、有强制性、价值重大的选择。理性的有限不足以使我们在这个选择面前产生倾向,中止选择、等待证据几乎类同于选择不信。因此我们必须依赖于情感和意志做出选择。冒丧失真理的危险,还是冒走入谬误的危险?还是选择后者吧,去相信上帝。

批判者认为,显而易见,实用主义式的功利心无法导向神圣的、超越世俗的信仰,而真正的信仰必须是神圣而超越的。权衡利弊绝不是信仰的正道。这在道德领域也是类似的,靠权衡、计算来选择遵守某些道德规则的人,不会被看做真正高尚的人。伦理的本性不是规则主义的而是美学主义的,高尚的人以德为美而不是以德为利。同样,真正的信仰者以信仰为真理,而不是搞投机。

上帝的否证——罪恶的存在

罪恶分为两种,自然的灾难,和人类的邪恶。如果上帝是至善的,就不应该有这些罪恶,如果上帝是全知的,就必能察觉所有罪恶,如果上帝是全能的,就有能力让所有罪恶消失。但,罪恶是存在的,因此不存在同时满足至善、全能、全知这三个属性的上帝。

针对这条否证的思路,出现了以下种种回应,往往被称作神正论。

罪恶虚幻说

诞生于十九世纪末的基督教科学派的观点,认为唯有善、健康是真实的,疾病、痛苦、罪恶都是幻觉。这一极端教派同时遭到宗教界和非宗教界的反对。

奥古斯丁神正论

恶是善之匮乏、人之堕落。疾病和伤害,就是健康的匮乏;恢复健康,并不是说疾病和伤害跑到别的什么地方去了,当它们不存在于健康的身心之中时,也不存在于任何别处。邪恶也就是善的匮乏,用现代的语言来比喻,上帝创造了热运动(测量读数就是温度值),温度低并不代表上帝创造了什么“热不运动”,而仅仅是热运动的匮乏。善也是这样的,上帝创造的世界只有单纯的善,恶不过是某些地方匮乏善的表现罢了。也就是说恶没有自存性,而是从善那里获得规定性。

把恶叫做善的匮乏,很像是一种语言游戏。杀人放火、拐骗偷盗,这些行为是真实存在的,不管我们叫它什么名字。上帝没有阻止这些东西的出现,似乎总归是要负点责任的。

于是奥古斯丁要说了,最初的恶来自于亚当夏娃的堕落,疾病、灾祸是上帝对堕落之人的惩罚。

如果自然的恶是上帝对人的惩罚,那么无人岛上的火山,是打算惩罚谁呢?人诞生以前的地震、水灾,是打算惩罚谁呢?也许那些自然现象依然有,但既然没有人,就无所谓灾了。可动物呢?难道动物也有罪,需要上帝创造这些自然现象来惩罚它们?大概奥古斯丁不需要为这类问题费神,那个时代地球年龄、物种历史和今天的科学观念完全是两回事。

人类道德的恶引出了著名的自由意志问题。人有自由意志,因此要对自己的罪负责,不能怪上帝,这是奥古斯丁的观点。然而,上帝为什么不创造出永不堕落犯罪的人呢?毕竟,自由意志和永不堕落犯罪是可以相容的,即使失去了堕落犯罪的自由,至少还有做小善还是做大善、用什么方式行善等诸多自由。

伊里奈乌神正论

比奥古斯丁更早的哲学家,其观点是,罪恶是人类走向道德成熟、精神完善这一漫漫旅程中的必经阶段。在他看来,上帝造人不是一个瞬间活动,而是一个发展的过程;其次,人类也不是奥古斯丁理解的那样首先是完善的然后才堕落了,人类原初的无罪、清白并非是道德意义上的成熟或完善。最后,罪恶不是堕落,而是必由之路。

该思想的当代阐释者约翰•希克认为,现成赋予人类的、不需要人类抉择取舍的善,比不上在困难和考验之下、通过自由意志的选择和取舍最终获得的善。上帝故意将人置于一种不完善的状态,通过自由意志和道德奋斗,最终实现彻底完善的人性。对于偏离道德的人,上帝也将一视同仁给予爱心和信任,继续在来生为他们提供机会,直到把他们引入天国。

显然,这一派的神正论明显偏离了传统的造人、原罪、地狱惩罚说,遭到保守基督教学者的否定。

全能的上帝观也要出面反对了,既然全能,为什么不能创造一个既使道德进步成为可能、又没有如许多的罪恶的世界呢?手段和目的何以冲突至如此地步?也许白日梦般的极乐世界不值得珍爱,但如此多罪恶的世界是不是过分了?

过程神学神正论

戴维•格里芬1976年出版《上帝、力量与罪恶:过程的神正论》标志着过程神学的形成。其历史渊源是过程哲学。该哲学站在有机动态的出发点理解存在,反对过去笛卡尔式的主体、客体二元论,主张“一个现实实有(事件)是如何生成的”也就构成了“那现实实有是什么”,存在就是由生成构成的,谓之过程原理。

以格里芬为代表的过程神学离开了正统的基督教,它反对了上帝的全能性,描绘了某种古怪的过程化了的上帝,祂不是主宰而是吸引或劝导着创造活动,祂承担创造的风险,分担人类的各种情绪。善恶问题同和谐、强度之类的概念挂钩。其所谓善,更多的是审美意义上容纳了负面的某种善,而不是传统道德上只有正面的善。过程神学中的上帝似乎不是圣经中的上帝,也不是罪人的上帝,而是圣人、天才们的上帝。

宗教经验

在围绕基督教的无数争论中,几乎都是理性、逻辑、思维的较量,不相干的旁观者几乎要产生一种错觉——这些复杂争论的思路、内涵乃是把握基督教信仰的关键。而实质上,在真正的信徒眼中,宗教经验高于宗教教义,因为这是对信仰对象的直接见证或者内在直观,而教义是间接论证或外在表达,故有宗教经验是宗教信仰之内核的说法。宗教经验带来的神奇感、神秘感、化一感、无时间感、愉悦或者安宁感、无法言传感,带来的对上帝的依赖感、敬畏感、向往感,是信徒真正的信仰源泉,而神学论证、哲学沉思,不过是内在信仰的派生物罢了。关于宗教经验的理解,有情感论、感觉论、超验论等,无论如何,它是内在的以及个体化的,难以用理性滔滔不绝地分析批判,只好打住。

迈蒙尼德的否定描述理论

摩西•本•迈蒙尼德是中世纪犹太教哲学家,对宗教语言做了深入讨论,强调要从否定的角度入手描述上帝。譬如说人是二足动物,是一种肯定性的描述,刻画了人的某个本质属性;说人不是三足动物,也给予人以某种程度的规定性,但并未触及人的本质属性。前一种描述蕴含了后一种,反之则不然。用一系列肯定性的属性来描述上帝,会误导我们以为上帝是诸属性的合成物,并自以为了解到有关上帝本质的知识。而上帝其实是一种超越的、单一的存在,祂不包含任何构成性的因素、属性,其本质也在人类理解之外。因此,我们应该用否定的方式来描述上帝,所谓否定不是指词语本身的表述形式,而是对用来描述上帝的那些宾词必须从否定的意义上来理解。例如说上帝是存在着的,应理解为上帝是不可能不存在的;说上帝永恒的,应理解为上帝的存在是无因的,等等。

逻辑实证主义的意义标准

一个命题有无意义,取决于其“可证实性”。如果发现了外星人,那么“外星人存在”被证实为真,如果宇宙是有限的并且彻底搜索过之后没有发现外星人,那么“外星人存在”被证实为假。尽管我们目前既没有发现外星人也没有能力彻底搜索宇宙,但“外星人存在”是有意义的命题,因为它具有“可证实性”,我们知道在什么条件下它可以被证实为真或者证实为假。相反,“物质是第一性”或者“精神是第一性”,“柏拉图的理念世界是存在的”,“存在的本质是虚无”……这类命题统统没有可证实性,是形而上学,在逻辑实证主义眼中毫无意义。这套意义标准在二十世纪五六十年代的宗教领域引出了一场寓言论战。

顺便说一句,假设把证实主义或者证伪主义的原则概括为一句话,那么这句话本身能否得到证实或者证伪?这个意义标准似乎把自己也列入了无意义的行列当中……

无论如何,逻辑实证主义乃至于证伪主义的意义标准似乎最好限缩在自然科学领域,在人类复杂多样化的语言现象中,还有别的标准值得关注,例如象征主义、功能主义等等。

隐身花匠的寓言

约翰•威兹德姆提出了这一经典寓言:两个人来到长期无人照管的花园,惊讶地发现有几棵花木在杂草丛中生机勃勃,甲认为有陌生而好心的花匠一直以来都在照看这些花。询问邻里后发现没人来过,甲认为花匠是趁大伙都睡着之后的夜里来照看花的。乙认为即使是夜里干活久而久之也会被邻居们听见的,再说照看花的人怎么可能做到不踩倒任何杂草呢?甲又举证说花园里能察觉出秩序感、美感,一定有人照看,既然没人发现,他必定是个隐身人。两人继续搜寻各种迹象,有时候一些迹象似乎表明真的有花匠来过,有时候一些迹象又倾向于否认这一点。直到两人充分了解了花园的所有细节并坦诚理智地交换所有看法之后,甲还是相信有花匠,乙还是不信。此时,花匠的假设不再是一个经验可以判定的命题了,失去了可证实性。甲的关于存在隐身花匠的解释,和乙的根本不存在花匠的解释,没有实质区别,只有感受方式的区别。威兹德姆认为,当前无神论有神论的争论也大致如此,双方面对同一个世界,分享了所有经验,交换了所有看法,结果还是一方信另一方不信。双方的区别只是感觉方式上的,用不同的命题或语言来表达不同的感受,但指向的却是同一个世界。双方的命题都不是事实的陈述,也都不可证实。

后来人继续提出了探险家寓言、牛津疯子寓言、游击队员寓言、旅行者寓言等,试图将有神论和无神论之间的争论同构成自己编出来的寓言故事,后出现的寓言总是试图指出前面的寓言在同构方面存在误差,并导致了结论上的误差。类比、比喻、同构似乎从原理上就不可能增加证明力,其作用无非是使问题更加浅白、清晰化,但由于信息的压缩、损失,误差也应该是无法避免的。因此这类讨论进路好像没有太大的价值。

(全文完)

Oracle基本数据类型存储格式浅析

Oracle基本数据类型存储格式浅析(一)——字符类型

前一阵看完文档,对oracle的基本数据类型的存储格式有了一些了解,最近有做了一些测试进行了验证。打算整理总结一下,这一篇主要说明字符类型的存储格式。主要包括char、varchar2和long等几种类型。

SQL> create table test_char (char_col char(10), varchar_col varchar2(10), long_col long);
表已创建。
SQL> insert into test_char values ('abc', '123', ',fd');
已创建 1 行。
SQL> commit;
提交完成。
SQL> select rowid from test_char;
ROWID
------------------
AAAB3LAAFAAAAAgAAA

根据rowid的定义规则,第7~9位是表示的是数据文件,F表示5,而10~15位表示的是在这个数据文件中的第几个BLOCK,g表示 32。(rowid编码相当于64进制。用A~Z a~z 0~9 + /共64个字符表示。A表示0,B表示1,……,a表示26,……,0表示52,……,+表示62,/表示63。)

我们根据计算的结果去dump这个block。

SQL> ALTER SYSTEM DUMP DATAFILE 5 BLOCK 32;
系统已更改。

打开产生的trace文件:

data_block_dump,data header at 0x3421064
===============
tsiz: 0x1f98
hsiz: 0x14
pbl: 0x03421064
bdba: 0x01400020
     76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x1f82
avsp=0x1f6e
tosp=0x1f6e
0xe:pti[0] nrow=1 offs=0
0x12:pri[0] offs=0x1f82
block_row_dump:
tab 0, row 0, @0x1f82
tl: 22 fb: --H-FL-- lb: 0x1  cc: 3
col  0: [10]  61 62 63 20 20 20 20 20 20 20
col  1: [ 3]  31 32 33
col  2: [ 3]  2c 66 64
end_of_block_dump
End dump data blocks tsn: 5 file#: 5 minblk 32 maxblk 32

观察dump出来的结果,可以发现以下几点:

  1. 对于每个字段,除了保存字段的值以外,还会保存当前字段中数据的长度。而且,oracle显然没有把字段的长度定义或类型定义保存在block中,这些信息保存在oracle的数据字典里面。
  2. 根据dump的结果,可以清楚的看到,字符类型在数据库中是以ascii格式存储的。
    SQL> select chr(to_number('61', 'xx')) from dual;
    CH
    --
    a
    
  3. char类型为定长格式,存储的时候会在字符串后面填补空格,而varchar2和long类型都是变长的。
SQL> SELECT DUMP(CHAR_COL, 16) D_CHAR FROM TEST_CHAR;
D_CHAR
-------------------------------------------------------------
Typ=96 Len=10: 61,62,63,20,20,20,20,20,20,20
SQL> SELECT DUMP(VARCHAR_COL, 16) D_VARCHAR2 FROM TEST_CHAR;
D_VARCHAR2
-------------------------------------------------------------
Typ=1 Len=3: 31,32,33
SQL> SELECT DUMP(LONG_COL, 16) D_VARCHAR2 FROM TEST_CHAR;
SELECT DUMP(LONG_COL, 16) D_VARCHAR2 FROM TEST_CHAR
            *
ERROR 位于第 1 行:
ORA-00997: 非法使用 LONG 数据类型

由于DUMP不支持LONG类型,因此我们使用了alter system dump block的方式,通过比较两种方式得到的结果,发现DUMP()函数不但方便,结果清晰,而且指出了进行DUMP的数据类型,在以后的例子中,除非必要的情况,否则都会采用DUMP()函数的方式进行说明。

下面看一下插入中文的情况,首先看一下数据库的字符集

SQL> select name, value$ from sys.props$ where name like '%CHARACTERSET%';
NAME                           VALUE$
------------------------------ ------------------------------
NLS_CHARACTERSET               ZHS16GBK
NLS_NCHAR_CHARACTERSET         AL16UTF16
SQL> insert into test_char values ('定长', '变长', null);
已创建 1 行。
SQL> SELECT DUMP(CHAR_COL, 16) D_CHAR FROM TEST_CHAR;
D_CHAR
----------------------------------------------------------------
Typ=96 Len=10: 61,62,63,20,20,20,20,20,20,20
Typ=96 Len=10: b6,a8,b3,a4,20,20,20,20,20,20
SQL> SELECT DUMP(VARCHAR_COL, 16) D_VARCHAR2 FROM TEST_CHAR;
D_VARCHAR2
----------------------------------------------------------------
Typ=1 Len=3: 31,32,33
Typ=1 Len=4: b1,e4,b3,a4

根据dump结果,可以清楚的看出,普通英文字符和标点用一个字节表示,而中文字符或中文标点需要两个字节来表示。

下面,对比一下nchar和nvarchar2与char、varchar2类型有什么不同。

SQL> create table test_nchar (nchar_col nchar(10), nvarchar_col nvarchar2(10));
表已创建。
SQL> insert into test_nchar values ('nchar定长', 'nvarchar变长');
已创建 1 行。

从这里已经可以看出一些不同了,如果按照刚才中文的计算方法,'nvarchar变长'的长度是8+2*2=12已经超过了数据类型定义的大小,可是为什么插入成功了?

还是dump一下看看结果吧。

SQL> select dump(nchar_col, 16) from test_nchar;
DUMP(NCHAR_COL,16)
--------------------------------------------------------------
Typ=96 Len=20: 0,6e,0,63,0,68,0,61,0,72,5b,9a,95,7f,0,20,0,20,0,20
SQL> select dump(nvarchar_col, 16) from test_nchar;
DUMP(NVARCHAR_COL,16)
--------------------------------------------------------------
Typ=1 Len=20: 0,6e,0,76,0,61,0,72,0,63,0,68,0,61,0,72,53,d8,95,7f

这下就明白了,虽然仍然是采用ascii码存储,但是nchar使用的AL16UTF16字符集,编码长度变为2个字节。这样中文使用两个字节,对于可以用一个字节就表示的英文字符,采用了高位补0的方式凑足2位,这样,对于采用AL16UTF16字符集的nchar类型,无论中文还是英文都用2位字符表示。因此'nvarchar变长'的长度是10,并没有超过数据类型的限制。

Oracle基本数据类型存储格式浅析(二)——数字类型

这篇文章主要描述NUMBER类型的数据和如何在数据库中存储的。

Oracle的NUMBER类型最多由三个部分构成,这三个部分分别是最高位表示位、数据部分、符号位。其中负数包含符号位,正数不会包括符号位。另外,数值0比较特殊,它只包含一个数值最高位表示位80,没有数据部分。

正数的最高位表示位大于80,负数的最高位表示位小于80。其中一个正数的最高位是个位的话,则最高位表示位为C1,百位、万位依次为C2、C3,百分位、万分为依次为C0、BF。一个负数的最高位为个位的话,最高位表示位为3E,百位、万位依次为3D、3C,百分位、万分位依次为3F、40。

数据部分每一位都表示2位数。这个两位数可能是从0到99,如果是数据本身是正数,则分别用二进制的1到64表示,如果数据本身是负数,则使用二进制65到2表示。

符号位用66表示。

上面的这些是我通过DUMP结果总结出来的,对于上面提到的这些关系常数,Oracle之所以这样选择是有道理的,我们后面根据例子也可以推导出来,而且会进一步说明为什么会采用这种方式表示。这里列出的意思是使大家先对NUMBER类型数据有一个大概的了解。

下面我们通过一个例子详细说明:

SQL> CREATE TABLE TEST_NUMBER (NUMBER_COL NUMBER);
表已创建。
SQL> INSERT INTO TEST_NUMBER VALUES (0);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (1);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (2);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (25);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (123);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (4100);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (132004078);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (2.01);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (0.3);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (0.00000125);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (115.200003);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-1);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-5);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-20032);
已创建 1 行。
SQL> INSERT INTO TEST_NUMBER VALUES (-234.432);
已创建 1 行。
SQL> COMMIT;
提交完成。
SQL> COL D_NUMBER FORMAT A50
SQL> SELECT NUMBER_COL, DUMP(NUMBER_COL, 16) D_NUMBER FROM TEST_NUMBER;
NUMBER_COL D_NUMBER
---------- --------------------------------------------------
         0 Typ=2 Len=1: 80
         1 Typ=2 Len=2: c1,2
         2 Typ=2 Len=2: c1,3
        25 Typ=2 Len=2: c1,1a
       123 Typ=2 Len=3: c2,2,18
      4100 Typ=2 Len=2: c2,2a
132004078 Typ=2 Len=6: c5,2,21,1,29,4f
      2.01 Typ=2 Len=3: c1,3,2
        .3 Typ=2 Len=2: c0,1f
.00000125 Typ=2 Len=3: be,2,1a
115.200003 Typ=2 Len=6: c2,2,10,15,1,4
        -1 Typ=2 Len=3: 3e,64,66
        -5 Typ=2 Len=3: 3e,60,66
    -20032 Typ=2 Len=5: 3c,63,65,45,66
  -234.432 Typ=2 Len=6: 3d,63,43,3a,51,66
已选择15行。

下面根据例子得到的结果,对每行进行说明。首先说明两点基本的。DUMP函数返回的TYPE=2表示DUMP的数据类型是NUMBER,LENGTH=N表示数值在数据库中存储的长度是N。

  1. DUMP(0)的结果是0x80,在前面已经提到,0只有高位表示位,没有数据位。由于0的特殊,既不属于正数,也不属于负数,因此使用高位表示位用 80表示就足够了,不会和其它数据冲突,Oracle出于节省空间的考虑将后面数据部分省掉了。但是为什么Oracle选择0x80表示0呢?我们知道正数和负数互为相反数,每个正数都有一个对应的负数。因此如果我们要使用编码表示数值,则表示正数和负数的编码应该各占一半,这样才能保证使Oracle表示数据范围是合理的。而0x80的二进制编码是1000 0000,正好是一个字节编码最大值的一半,因此,Oracle选择0x80来表示0,是十分有道理的。
  2. DUMP(1)的结果是0xc102,0xc1表示了最高位个位,0x2表示数值是1。首先,Oracle为什么用C1表示个位呢?其实,道理和刚才的差不多。采用科学计数法,任何一个实数S都可以描述为A.B×10n,A表示整数部分,B表示小数部分,而N表示10的指数部分。当S大于1时,N大于等于0,S小于1时,N小于0。也就是说,采用指数的方式表示,N大于0和N小于0的情况各占一半左右时,Oracle所表示的范围最广。因此,Oracle选择了C1表示个位是最高位的情况。
    SQL> SELECT TO_CHAR(ROUND(TO_NUMBER('81', 'XXX') + (TO_NUMBER('FF', 'XXX') - TO_NUMBER('81', 'XXX') + 1)/2), 'XX') FROM DUAL;
    TO_
    ---
    C1
    

    为什么ORACLE使用0x2表示1,而不直接使用0x1表示1呢?Oracle每个字节表示2位数,因此对于这个2位数,出现的可能是0~99共100 种可能,问题出在0这里。Oracle底层是用C语言实现的,我们知道二进制0在C语言中用作字符串终结符,Oracle为了避免这个问题,因此使用了 0x1表示0,并依次类推,使用0x64表示99。

  3. DUMP(2)的结果是0xc103。
  4. DUMP(25)的结果是0xc11a。前面提到,数据部分是以2位为最小单位保存的。因此对于25来说,最高位表示位仍然是个位,个位上的值是25,根据上面推出的规则,25在存储为0xc11a。
    SQL> SELECT TO_CHAR(25 + 1, 'xx') FROM DUAL;
    TO_
    ---
    1a
    
  5. DUMP(123)的结果是0xc20218。由于123最高为是百位,所以最高位表示位为0xc2,百位上是1,用0x02表示,个位上是23,用0x18表示。
  6. DUMP(4100)的结果是0xc22a。

    注意一点,如果数字最后数位上如果是0,Oracle出于节省空间的考虑不会存储。比如:4100只保存百位上的41,12000000只保存百位位上的12,512000只保存万位上的51和百位上的20。

  7. DUMP(132004078)的结果是0xc5022101294f。最高位是亿位,因此用0xC5表示,亿位上是1用0x02表示,百位位上是32用0x21表示,万位上是0用0x01表示,百位上是40用0x29表示,个位上78用0x4F表示。

    注意:中间数位上的0不能省略。

  8. DUMP(2.01)的结果是0xc10302。最高位是个位用0xC1表示,个位上是2用0x03表示,百分位上是1用0x02表示。

    注意:个位下面一位是百分位不是十分位。

  9. DUMP(0.3)的结果是0xc01f。最高位是百分位,使用0xC0表示,百分位上是30用0x1F表示。
  10. DUMP(0.00000125)的结果是0xbe021a。最高位是百万分位,用0xBE表示,最高位上的1用0x02表示,25用0x1a表示。
  11. DUMP(115.200003)的结果是0xc20210150104。
  12. DUMP(-1)的结果是0x3e6466。最高位个位,用0x3E表示,64表示个位上是1,66是符号位,表示这个数是负数。

    负数和正数互为相反数,负数的最高位表示位和它对应的相反数的最高位相加的值是FF。1的最高位表示位是C1,-1的最高位表示位是3E。负数中1用64 表示。负数中的数值和它相反数的数据相加是0x66,也就是符号位。正数1用0x02表示,负数1用0x64表示,二者相加是0x66。负数多个一个标识位,用0x66表示。由于正数的表示范围是0x01到0x64,负数的表示范围是0x65到0x02。因此,不会在表示数字时出现的0x66表示。

  13. DUMP(-5)的结果是0x3e6066。0x3e表示最高位是个位,0x60表示个位上是5,0x66是符号标识位。0x3E加0xC1是0xFF。0x60加0x06的结果是0x66。
  14. DUMP(-20032)的结果是0x3c63654566。最高位是万位,正数的万位是0xC3,因此负数的万位是0x3C。万位上是2,正数用 0x03表示,负数为0x63,百位上是0,正数用0x01表示,负数使用0x65表示,个位上是32,正数用0x21表示,负数使用0x45表示。 0x66是负数表示位。
  15. DUMP(-234.432)的结果是0x3d63433a5166。

根据Oracle的存储特性,还可以推出Oracle的number类型的取值范围。

Oracle的concept上是这样描述的:

The following numbers can be stored in a NUMBER column: Positive numbers in the range 1 x 10^-130 to 9.99...9 x 10^125 with up to 38 significant digits. Negative numbers from -1 x 10^-130 to 9.99...99 x 10^125 with up to 38 significant digits. Zero.

下面来推导出取值范围。

来看符号位,0xC1表示个位。

SQL> select to_number('ff', 'xxx') - to_number('c1', 'xxx') from dual;
TO_NUMBER('FF','XXX')-TO_NUMBER('C1','XXX')
-------------------------------------------
                                         62

由于Oracle是两位、两位存储的,因此最高位相当于62×2=124,而且最高位上最大值是99,因此正数的最大值为9.999……×10^125。

SQL> select to_number('c1', 'xxx') - to_number('80', 'xxx') from dual;
TO_NUMBER('C1','XXX')-TO_NUMBER('80','XXX')
-------------------------------------------
                                         65

最高位相当于65×2=130,因此正数的最小值为1×10^-130。

负数和正数在各使用了一半的编码,因此具有相同的极值范围。

Oracle基本数据类型存储格式浅析(三)——日期类型(一)

这篇文章描述DATE类型的数据在Oracle中是以何种格式存放的。

下面通过一个例子进行说明。

SQL> create table test_date (date_col date);
表已创建。
SQL> insert into test_date values (to_date('2000-1-1 0:0:0', 'yyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> insert into test_date values (to_date('1-1-1 0:0:0', 'yyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> insert into test_date values (to_date('-1-1-1 0:0:0', 'syyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> insert into test_date values (to_date('-101-1-1 0:0:0', 'syyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> insert into test_date values (to_date('-4712-1-1 0:0:0', 'syyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> insert into test_date values (to_date('9999-12-31 23:59:59', 'syyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> insert into test_date values (sysdate);
已创建 1 行。
SQL> insert into test_date values (to_date('-4713-1-1 0:0:0', 'syyyy-mm-dd hh24:mi:ss'));
insert into test_date values (to_date('-4713-1-1 0:0:0', 'syyyy-mm-dd hh24:mi:ss'))
                                      *
ERROR 位于第 1 行:
ORA-01841: (全)年度值必须介于 -4713 和 +9999 之间,且不为 0
SQL> insert into test_date values (to_date('0000-1-1 0:0:0', 'yyyy-mm-dd hh24:mi:ss'));
insert into test_date values (to_date('0000-1-1 0:0:0', 'yyyy-mm-dd hh24:mi:ss'))
                                      *
ERROR 位于第 1 行:
ORA-01841: (全)年度值必须介于 -4713 和 +9999 之间,且不为 0
SQL> col dump_date format a80
SQL> select to_char(date_col, 'syyyy-mm-dd hh24:mi:ss'), dump(date_col) dump_date from test_date;
TO_CHAR(DATE_COL,'SY DUMP_DATE
-------------------- ---------------------------------------
2000-01-01 00:00:00 Typ=12 Len=7: 120,100,1,1,1,1,1
0001-01-01 00:00:00 Typ=12 Len=7: 100,101,1,1,1,1,1
-0001-01-01 00:00:00 Typ=12 Len=7: 100,99,1,1,1,1,1
-0101-01-01 00:00:00 Typ=12 Len=7: 99,99,1,1,1,1,1
-4712-01-01 00:00:00 Typ=12 Len=7: 53,88,1,1,1,1,1
9999-12-31 23:59:59 Typ=12 Len=7: 199,199,12,31,24,60,60
2004-12-15 13:56:19 Typ=12 Len=7: 120,104,12,15,14,57,20
已选择7行。

通过最后两条语句已经可以看出Oracle的DATE类型的取值范围是公元前4712年1月1日至公元9999年12月31日。而且根据日期的特定,要不然是公元1年,要不然是公元前1年,不会出现0年的情况。

日期类型长度是7,7个字节分别表示世纪、年、月、日、时、分和秒。

由于不会出现0的情况,月和日都是按照原值存储的,月的范围是1~12,日的范围是1~31。

由于时、分、秒都会出现0的情况,因此存储时采用原值加1的方式。0时保存为1,13时保存为14,23时保存为24。分和秒的情况与小时类似。小时的范围是0~23,在数据库中以1~24保存。分和秒的范围都是0~59,在数据库中以1~60保存。

年和世纪的情况相对比较复杂,可分为公元前和公元后两种情况。由于最小的世纪的值是-47(公元前4712年),最大值是99(公元9999年)。为了避免负数的产生,oracle把世纪加100保存在数据库中。公元2000年,世纪保存为120,公元9999年,世纪保存为199,公元前101年,世纪保存为99(100+(-1)),公元前4712年,世纪保存为53(100+(-47))。

注意,对于公元前1年,虽然已经是公元前了,但是表示世纪的前两位的值仍然是0,因此,这时的保存的世纪的值仍然是100。世纪的范围是-47~99,保存的值是53~199。

年的保存与世纪的保存方式类似,也把年的值加上100进行保存。对于公元2000年,年保持为100,公元1年保存为101,公元2004年保存为 104,公元9999年保存为199,公元前1年,保存为99(100+(-1)),公元前101年,保存为99(100+(-1)),公元前4712年保存为88(100+(-12))。对于公元前的年,保存的值总是小于等于100,对于公元后的年,保存的值总是大于等于100。年的范围是0~99,保存的值是1~199。

注意:一般的世纪,都包含了100年,而对于0世纪,由于包含公元前和公元后两部分且不包含0年,因此包含了198年。

Oracle基本数据类型存储格式浅析(三)——日期类型(二)

这篇文章描述TIMESTAMP类型的数据在Oracle中是以何种格式存放的。

下面通过一个例子进行说明。

SQL> create table test_time (col_time timestamp);
表已创建。
SQL> insert into test_time values (to_timestamp('0001-1-1 0:0:0.0', 'syyyy-mm-dd hh24:mi:ss.ff'));
已创建 1 行。
SQL> insert into test_time values (to_timestamp('2000-1-1 0:0:0.0', 'syyyy-mm-dd hh24:mi:ss.ff'));
已创建 1 行。
SQL> insert into test_time values (to_timestamp('9999-12-31 23:59:59.999999', 'syyyy-mm-dd hh24:mi:ss.ff'));
已创建 1 行。
SQL> insert into test_time values (to_timestamp('-0001-1-1 0:0:0.0', 'syyyy-mm-dd hh24:mi:ss.ff'));
已创建 1 行。
SQL> insert into test_time values (to_timestamp('-0100-3-4 13:2:3.234015', 'syyyy-mm-dd hh24:mi:ss.ff'));
已创建 1 行。
SQL> insert into test_time values (systimestamp);
已创建 1 行。
SQL> insert into test_time values (to_timestamp('2000-1-1 0:0:0.123456789', 'syyyy-mm-dd hh24:mi:ss.ff9'));
已创建 1 行。
SQL> commit;
提交完成。
SQL> select to_char(col_time, 'syyyy-mm-dd hh24:mi:ss.ff9') time, dump(col_time) dump_time
  2  from test_time;
TIME                           DUMP_TIME
------------------------------ ----------------------------------------------------
0001-01-01 00:00:00.000000000 Typ=180 Len=7: 100,101,1,1,1,1,1
2000-01-01 00:00:00.000000000 Typ=180 Len=7: 120,100,1,1,1,1,1
9999-12-31 23:59:59.999999000 Typ=180 Len=11: 199,199,12,31,24,60,60,59,154,198,24
-0001-01-01 00:00:00.000000000 Typ=180 Len=7: 100,99,1,1,1,1,1
-0100-03-04 13:02:03.234015000 Typ=180 Len=11: 99,100,3,4,14,3,4,13,242,201,24
2004-12-15 16:14:52.738000000 Typ=180 Len=11: 120,104,12,15,17,15,53,43,252,252,128
2000-01-01 00:00:00.123457000 Typ=180 Len=11: 120,100,1,1,1,1,1,7,91,205,232
已选择7行。

与DATE类型对比可以发现,对于TIMESTAMP类型,如果不包含微秒信息或者微秒值为0,那么存储结果和DATE完全相同。当微秒值为0时,Oracle为了节省空间,不会保存微秒信息。

如果毫秒值不为0,Oracle把微秒值当作一个9位数的数字来保存。

比如999999000,保存为59,154,198,24。234015000保存为13,242,201,24。

SQL> select to_char(999999000, 'xxxxxxxxxx') from dual;
TO_CHAR(999
-----------
   3b9ac618
SQL> select to_number('3b', 'xxx') one, to_number('9a', 'xxx') two,
  2  to_number('c6', 'xxx') three, to_number('18', 'xxx') four from dual;
       ONE        TWO      THREE       FOUR
---------- ---------- ---------- ----------
        59        154        198         24
SQL> select to_char(234015000, 'xxxxxxxx') from dual;
TO_CHAR(2
---------
  df2c918
SQL> select to_number('d', 'xxx') one, to_number('f2', 'xxx') two,
  2  to_number('c9', 'xxx') three, to_number('18', 'xxx') four from dual;
       ONE        TWO      THREE       FOUR
---------- ---------- ---------- ----------
        13        242        201         24

另外,注意一点,不指定精度的情况下,TIMESTAMP默认取6位。长度超过6位,会四舍五入到6位。如果希望保存9位的TIMESTAMP,必须明确指定精度。

SQL> alter table test_time modify (col_time timestamp(9));
表已更改。
SQL> insert into test_time values (to_timestamp('2000-1-1 0:0:0.123456789', 'syyyy-mm-dd hh24:mi:ss.ff9'));
已创建 1 行。
SQL> select to_char(col_time, 'syyyy-mm-dd hh24:mi:ss.ff9') time, dump(col_time) dump_time
  2  from test_time;
TIME                           DUMP_TIME
------------------------------ ---------------------------------------------------
0001-01-01 00:00:00.000000000 Typ=180 Len=7: 100,101,1,1,1,1,1
2000-01-01 00:00:00.000000000 Typ=180 Len=7: 120,100,1,1,1,1,1
9999-12-31 23:59:59.999999000 Typ=180 Len=11: 199,199,12,31,24,60,60,59,154,198,24
-0001-01-01 00:00:00.000000000 Typ=180 Len=7: 100,99,1,1,1,1,1
-0100-03-04 13:02:03.234015000 Typ=180 Len=11: 99,100,3,4,14,3,4,13,242,201,24
2004-12-15 16:14:52.738000000 Typ=180 Len=11: 120,104,12,15,17,15,53,43,252,252,128
2000-01-01 00:00:00.123457000 Typ=180 Len=11: 120,100,1,1,1,1,1,7,91,205,232
2000-01-01 00:00:00.123456789 Typ=180 Len=11: 120,100,1,1,1,1,1,7,91,205,21
已选择8行。
Oracle基本数据类型存储格式浅析(三)——日期类型(三)

如果直接在SQL语句中对SYSDATE或由TO_DATE函数生成日期进行DUMP操作,会发现得到的结果与DUMP数据库中保存的日期的结果不一样。

SQL> truncate table test_date;
表已截掉。
SQL> insert into test_date values (to_date('2004-12-17 16:42:42', 'syyyy-mm-dd hh24:mi:ss'));
已创建 1 行。
SQL> col dump_date format a65
SQL> select to_char(date_col, 'syyyy-mm-dd hh24:mi:ss') dat, dump(date_col) dump_date from test_date;
DAT                  DUMP_DATE
-------------------- ---------------------------------------------------------
2004-12-17 16:42:42 Typ=12 Len=7: 120,104,12,17,17,43,43
SQL> select to_char(to_date('2004-12-17 16:42:42', 'syyyy-mm-dd hh24:mi:ss'), 'syyyy-mm-dd hh24:mi:ss') dat,
  2  dump(to_date('2004-12-17 16:42:42', 'syyyy-mm-dd hh24:mi:ss')) dump_date from dual;
DAT                  DUMP_DATE
-------------------- ---------------------------------------------------------
2004-12-17 16:42:42 Typ=13 Len=8: 212,7,12,17,16,42,42,0

存储在数据库中的DATE类型是12,而直接在SQL中使用的DATE类型是13。而且二者的长度以及表示方式都不相同。这两种类型的不同指出主要体现在两点:一:时、分、秒的表示不同;二、世纪和年的表示不同。

SQL中使用DATE的时分秒没有采用加1存储方式,而且原值存储。

SQL中使用DATE没有采用世纪、年的方式保持,而是采用了按数值保存的方式。第一位表示低位,第二位表示高位。低位表示最大的值是255。如上面的例子中,212+7×256=2004。

SQL> select to_char(to_date('-2004-12-17 16:42:42', 'syyyy-mm-dd hh24:mi:ss'), 'syyyy-mm-dd hh24:mi:ss') dat,
  2  dump(to_date('-2004-12-17 16:42:42', 'syyyy-mm-dd hh24:mi:ss')) dump_date from dual;
DAT                  DUMP_DATE
-------------------- ---------------------------------------------------
-2004-12-17 16:42:42 Typ=13 Len=8: 44,248,12,17,16,42,42,0
SQL> select dump(to_date('-1-1-1', 'syyyy-mm-dd')) from dual;
DUMP(TO_DATE('-1-1-1','SYYYY-MM-D
---------------------------------
Typ=13 Len=8: 255,255,1,1,0,0,0,0

对于公元前的日期,Oracle从255,255开始保存。公元前的年的保存的值和对应的公元后的年的值相加的和是256,255。如上例中的公元2004年和公元前2004年的值相加:212+44=256,7+248=255。

SQL中DATE类型最后还包括一个0,似乎目前没有使用。

Oracle基本数据类型存储格式浅析(三)——日期类型(四)

本文对TIMESTAMP WITH LOCAL TIME ZONE和TIMESTAMP WITH TIME ZONE类型的存储格式进行简单的说明。

SQL> CREATE TABLE TEST_TIMESTAMP(TIME1 TIMESTAMP(9), TIME2 TIMESTAMP(6) WITH LOCAL TIME ZONE,
  2  TIME3 TIMESTAMP(4) WITH TIME ZONE);
表已创建。
SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。
SQL> SELECT * FROM TEST_TIMESTAMP;
TIME1
----------------------------------------------------
TIME2
----------------------------------------------------
TIME3
----------------------------------------------------
11-1月 -05 11.08.15.027000000 下午
11-1月 -05 11.08.15.027000 下午
11-1月 -05 11.08.15.0270 下午 +08:00
SQL> SELECT DUMP(TIME1, 16), DUMP(TIME2, 16), DUMP(TIME3, 16) FROM TEST_TIMESTAMP;
DUMP(TIME1,16)
-------------------------------------------------------------
DUMP(TIME2,16)
-------------------------------------------------------------
DUMP(TIME3,16)
-------------------------------------------------------------
Typ=180 Len=11: 78,69,1,b,18,9,10,1,9b,fc,c0
Typ=231 Len=11: 78,69,1,b,18,9,10,1,9b,fc,c0
Typ=181 Len=13: 78,69,1,b,10,9,10,1,9b,fc,c0,1c,3c

可以发现,如果客户端和数据库中的时区是一致的,那么TIMESTAMP和TIMESTAMP WITH LOCAL TIME ZONE存储的数据是完全一样的。

TIMESTAMP WITH TIME ZONE则略有不同,它保存的是0时区的时间,和所处的时区信息。

修改客户端主机的时区,由东8区(+8区)改为0时区。

SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。

修改客户端主机的时区,改为西5区(-5时区)。

SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。

修改客户端主机的时区,改为西12区(-12时区)。

SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。

修改客户端主机的时区,改为东13区(+13时区)。

SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。

修改客户端主机的时区,改为西3.5区(-3.5时区)。

SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。

修改客户端主机的时区,改为东9.5区(+9.5时区)。

SQL> INSERT INTO TEST_TIMESTAMP VALUES (SYSTIMESTAMP, SYSTIMESTAMP, SYSTIMESTAMP);
已创建 1 行。
SQL> COMMIT;
提交完成。

修改客户端主机的时区,改回东8区(+8时区)。

SQL> SELECT * FROM TEST_TIMESTAMP;
TIME1
-----------------------------------------------
TIME2
-----------------------------------------------
TIME3
-----------------------------------------------
11-1月 -05 11.08.15.027000000 下午
11-1月 -05 11.08.15.027000 下午
11-1月 -05 11.08.15.0270 下午 +08:00
11-1月 -05 03.11.43.746000000 下午
11-1月 -05 11.11.43.746000 下午
11-1月 -05 03.11.43.7460 下午 +00:00
11-1月 -05 10.14.08.987000000 上午
11-1月 -05 11.14.08.987000 下午
11-1月 -05 10.14.08.9870 上午 -05:00
11-1月 -05 03.15.01.732000000 上午
11-1月 -05 11.15.01.732000 下午
11-1月 -05 03.15.01.7320 上午 -12:00
12-1月 -05 04.20.21.522000000 上午
11-1月 -05 11.20.21.522000 下午
12-1月 -05 04.20.21.5220 上午 +13:00
11-1月 -05 02.15.16.567000000 下午
12-1月 -05 01.45.16.567000 上午
11-1月 -05 02.15.16.5670 下午 -03:30
12-1月 -05 03.16.54.992000000 上午
12-1月 -05 01.46.54.992000 上午
12-1月 -05 03.16.54.9920 上午 +09:30
已选择7行。
SQL> SELECT DUMP(TIME1, 16), DUMP(TIME2, 16), DUMP(TIME3, 16) FROM TEST_TIMESTAMP;
DUMP(TIME1,16)
-------------------------------------------------------------
DUMP(TIME2,16)
-------------------------------------------------------------
DUMP(TIME3,16)
-------------------------------------------------------------
Typ=180 Len=11: 78,69,1,b,18,9,10,1,9b,fc,c0
Typ=231 Len=11: 78,69,1,b,18,9,10,1,9b,fc,c0
Typ=181 Len=13: 78,69,1,b,10,9,10,1,9b,fc,c0,1c,3c
Typ=180 Len=11: 78,69,1,b,10,c,2c,2c,77,e,80
Typ=231 Len=11: 78,69,1,b,18,c,2c,2c,77,e,80
Typ=181 Len=13: 78,69,1,b,10,c,2c,2c,77,e,80,14,3c
Typ=180 Len=11: 78,69,1,b,b,f,9,3a,d4,6c,c0
Typ=231 Len=11: 78,69,1,b,18,f,9,3a,d4,6c,c0
Typ=181 Len=13: 78,69,1,b,10,f,9,3a,d4,6c,c0,f,3c
Typ=180 Len=11: 78,69,1,b,4,10,2,2b,a1,6f,0
Typ=231 Len=11: 78,69,1,b,18,10,2,2b,a1,6f,0
Typ=181 Len=13: 78,69,1,b,10,10,2,2b,a1,6f,0,8,3c
Typ=180 Len=11: 78,69,1,c,5,15,16,1f,1d,16,80
Typ=231 Len=11: 78,69,1,b,18,15,16,1f,1d,16,80
Typ=181 Len=13: 78,69,1,b,10,15,16,1f,1d,16,80,21,3c
Typ=180 Len=11: 78,69,1,b,f,10,11,21,cb,bb,c0
Typ=231 Len=11: 78,69,1,c,2,2e,11,21,cb,bb,c0
Typ=181 Len=13: 78,69,1,b,12,2e,11,21,cb,bb,c0,11,1e
Typ=180 Len=11: 78,69,1,c,4,11,37,3b,20,b8,0
Typ=231 Len=11: 78,69,1,c,2,2f,37,3b,20,b8,0
Typ=181 Len=13: 78,69,1,b,12,2f,37,3b,20,b8,0,1d,5a
SQL> SELECT TO_NUMBER('1C', 'XXX'), TO_NUMBER('3C', 'XXX') FROM DUAL;
TO_NUMBER('1C','XXX') TO_NUMBER('3C','XXX')
--------------------- ---------------------
                   28                    60
SQL> SELECT TO_NUMBER('14', 'XXX'), TO_NUMBER('3C', 'XXX'), TO_NUMBER('143C', 'XXXXXXX') FROM DUAL;
TO_NUMBER('14','XXX') TO_NUMBER('3C','XXX')
--------------------- ---------------------
                   20                    60
SQL> SELECT TO_NUMBER('3C', 'XXX') , TO_NUMBER('1E', 'XXX'), TO_NUMBER('5A', 'XXX') FROM DUAL;
TO_NUMBER('3C','XXX') TO_NUMBER('1E','XXX') TO_NUMBER('5A','XXX')
--------------------- --------------------- -------------------
                   60                    30                  90

可以看出,修改时区会导致系统TIMESTAMP时间发生变化,但是对于TIMESTAMP WITH LOCAL TIME ZONE类型,总是将系统的时间转化到数据库服务器上时区的时间进行存储。

TIMESTAMP WITH TIME ZONE保存的是当前时间转化到0时区的对应的时间,并通过最后两位来保存时区信息。

第一位表示时区的小时部分。0时区用0x14表示。东n区在这个基础上加n,西n区在这个基础上减n。我们所处的东8区表示为0x1C。西5区表示为0xF。

第二位表示时区的分钟部分。标准是0x3C,即60分钟。对于东时区的半区,在这个基础上加上30分钟,如果是西时区,则减去30分钟。

Oracle基本数据类型存储格式浅析(四)——ROWID类型(一)

Oracle的ROWID用来唯一标识表中的一条记录,是这条数据在数据库中存放的物理地址。

Oracle的ROWID分为两种:物理ROWID和逻辑ROWID。索引组织表使用逻辑ROWID,其他类型的表使用物理ROWID。其中物理 ROWID在Oracle的8版本中进行了扩展,Oracle7及以下版本使用约束ROWID,Oracle8及以上版本使用扩展ROWID。本文描述物理扩展ROWID,由于约束ROWID仅仅是为了兼容早期版本,因此不做讨论。

SQL> create table test_rowid (id number, row_id rowid);
表已创建。
SQL> insert into test_rowid values (1, null);
已创建 1 行。
SQL> update test_rowid set row_id = rowid where id = 1;
已更新 1 行。
SQL> commit;
提交完成。
SQL> select rowid, row_id from test_rowid;
ROWID              ROW_ID
------------------ ------------------
AAABnRAAGAAAACWAAA AAABnRAAGAAAACWAAA

Oracle的物理扩展ROWID有18位,每位采用64位编码,分别用A~Z、a~z、0~9、+、/共64个字符表示。A表示0,B表示1,……Z表示25,a表示26,……z表示51,0表示52,……,9表示61,+表示62,/表示63。

ROWID具体划分可以分为4部分。

  1. OOOOOO:前6位表示DATA OBJECT NUMBER,将起转化位数字后匹配DBA_OBJECTS中的DATA_OBJECT_ID,可以确定表信息。

    如上面例子中的DATA OBJECT NUMBER是AAABnR,转化位数字是1×64×64 +39×64 + 17。

    SQL> select owner, object_name from dba_objects
      2  where data_object_id = 1*64*64 + 39*64 + 17;
    OWNER                          OBJECT_NAME
    ------------------------------ -----------------------------
    YANGTK                         TEST_ROWID
    
  2. FFF:第7到9位表示相对表空间的数据文件号。

    上面的例子中是AAG,表示数据文件6。

    SQL> select file_name, tablespace_name from dba_data_files where relative_fno = 6;
    FILE_NAME                                     TABLESPACE_NAME
    --------------------------------------------- ---------------
    E:ORACLEORADATATESTYANGTK01.DBF           YANGTK
    
  3. BBBBBB:第10到15位表示这条记录在数据文件中的第几个BLOCK中。

    上面的例子是AAAACW,转化位数字是2×64+22,表示这条记录在数据文件中的第150个BLOCK。

  4. RRR:最后3位表示这条记录是BLOCK中的第几条记录。

上面的例子是AAA,表示第0条记录(总是从0开始计数)。

SQL> alter system dump datafile 6 block 150;
系统已更改。
SQL> select row_id, dump(row_id, 16) dump_rowid from test_rowid;
ROW_ID             DUMP_ROWID
------------------ -------------------------------------------------
AAABnRAAGAAAACWAAA Typ=69 Len=10: 0,0,19,d1,1,80,0,96,0,0
找到对应的dump文件,可以发现类型的信息
*** 2004-12-21 17:58:26.000
*** SESSION ID13.91) 2004-12-21 17:58:26.000
Start dump data blocks tsn: 6 file#: 6 minblk 150 maxblk 150
buffer tsn: 6 rdba: 0x01800096 (6/150)
scn: 0x0000.2e389c16 seq: 0x01 flg: 0x06 tail: 0x9c160601
frmt: 0x02 chkval: 0xc97d type: 0x06=trans data
Block header dump:  0x01800096
Object id on Block? Y
seg/obj: 0x19d1  csc: 0x00.2e389c0f  itc: 2  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01
Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0003.009.00000057  0x0080004b.0042.56  --U-    1  fsc 0x0000.2e389c16
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
data_block_dump,data header at 0x651105c
===============
tsiz: 0x3fa0
hsiz: 0x14
pbl: 0x0651105c
bdba: 0x01800096
     76543210
flag=--------
ntab=1
nrow=1
frre=-1
fsbo=0x14
fseo=0x3f89
avsp=0x3f7b
tosp=0x3f7b
0xeti[0] nrow=1 offs=0
0x12ri[0] offs=0x3f89
block_row_dump:
tab 0, row 0, @0x3f89
tl: 17 fb: --H-FL-- lb: 0x1  cc: 2
col  0: [ 2]  c1 02
col  1: [10]  00 00 19 d1 01 80 00 96 00 00
end_of_block_dump
End dump data blocks tsn: 6 file#: 6 minblk 150 maxblk 150

有时需要查看表的DUMP信息,但是很难准确定位表中数据开始于哪个BLOCK,根据ROWID中包含的信息就可以方便的找到起始BLOCK。

下面简单描述一下ROWID类型是如何存储的。

SQL> select row_id, dump(row_id, 16) dump_rowid from test_rowid;
ROW_ID             DUMP_ROWID
------------------ -------------------------------------------------
AAABnRAAGAAAACWAAA Typ=69 Len=10: 0,0,19,d1,1,80,0,96,0,0

前4位表示ROWID的前6位,也就是DATA_OBJECT_ID信息。数据以数值的格式保存。

SQL> select to_number('19d1', 'xxxxxx') from dual;
TO_NUMBER('19D1','XXXXXX')
--------------------------
                      6609
SQL> select 1*64*64 + 39*64 + 17 from dual;
1*64*64+39*64+17
----------------
            6609

这里存在一个问题,根据ROWID的取值范围,OBJECT_DATA_ID最大的值是64的6次方,而根据DUMP,oracle只用了4位保存,因此取值范围是256的4次方。

SQL> set numwid 12
SQL> select power(64, 6), power(256, 4), power(64, 6)/power(256, 4) from dual;
POWER(64,6) POWER(256,4) POWER(64,6)/POWER(256,4)
------------ ------------ ------------------------
68719476736   4294967296                       16

可见,OBJECT_DATA_ID的最大值是4294967296,当超过这个值时会出现重复的情况。(当然,现实中不大可能)。

后面4位比较特殊,是数据文件号和BLOCK数的“和”值构成。

数据文件的数值乘64后保存在5、6位上。

SQL> select to_number('0180', 'xxxx') from dual;
TO_NUMBER('0180','XXXX')
------------------------
                     384
SQL> select 6*64 from dual;
        6*64
------------
         384

同时,6位BLOCK的值,也保存在这4位上,并与数据文件转存结果相加。仍然是以数字格式存放。

SQL> select to_number('96', 'xxx') from dual;
TO_NUMBER('96','XXX')
---------------------
                  150
SQL> select 2*64 + 22 from dual;
   2*64+22
----------
       150

由于采用两位保存数据文件的值,且最小单位是64,因此,ROWID中可以保存的数据文件数是1024,超过1024会造成ROWID的重复。

SQL> select 256*256/64 from dual;
256*256/64
----------
      1024

由于BLOCK的值和数据文件共用这4位,因此BLOCK的第3位最大值应小于64,这样才能保证ROWID的不重复。因此BLOCK值的最大值应该是4194304。

SQL> select 64*256*256 from dual;
64*256*256
----------
   4194304

最后两位保存BLOCK中记录的值。这个值的最大值是65536。

SQL> select 256*256 from dual;
   256*256
----------
     65536

Oracle基本数据类型存储格式浅析(四)——ROWID类型(二)

Oracle的文档上没有介绍逻辑ROWID的编码规则,而且通过DUMP的结果也很难反推出编码规则。因此,本文只简单讨论一下逻辑ROWID的存储。

下面来看例子。

SQL> create table test_index (id number primary key, name varchar2(20)) organization index;
表已创建。
SQL> insert into test_index values (1, 'a');
已创建 1 行。
SQL> commit;
提交完成。
SQL> col dump_rowid format a60
SQL> select rowid, dump(rowid) dump_rowid from test_index;
ROWID                       DUMP_ROWID
--------------------------- ----------------------------------------
*BAFAB4wCwQL+               Typ=208 Len=10: 2,4,1,64,7,140,2,193,2,254

逻辑ROWID的DUMP结果前两位都是2和4,最后一位都是254,(我还没有发现其他的情况),由于逻辑ROWID和主键的值有关,所以长度是不定的,因此应该是用来表示开始和结束的。

第3、4位和物理ROWID一样,表示的是相对表空间的数据文件号乘以64的值。

第5、6位表示这条记录在数据文件的第几个BLOCK中。

从第7位开始到DUMP结果的倒数第二位,表示主键的值。首先是主键中第一个字段的长度,这里是2,然后是主键的值,由于是NUMBER类型,因此193,2表示数值1。如果是多个字段组成的主键,第一个字段之后是第二个字段的长度,然后是第二个字段的值……。

SQL> select (1*256 + 64)/64 from dual;
(1*256+64)/64
-------------
            5
SQL> select 7*256 + 140 from dual;
7*256+140
----------
      1932
SQL> alter system dump datafile 5 block 1932;
系统已更改。

找到相应的dump文件,可以发现刚才插入的记录。

Dump file fracleadmintest4udumptest4_ora_3828.trc
Thu Dec 23 00:17:53 2004
ORACLE V9.2.0.4.0 - Production vsnsta=0
vsnsql=12 vsnxtr=3
Windows 2000 Version 5.1 Service Pack 1, CPU type 586
Oracle9i Enterprise Edition Release 9.2.0.4.0 - Production
With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options
JServer Release 9.2.0.4.0 - Production
Windows 2000 Version 5.1 Service Pack 1, CPU type 586
Instance name: test4
Redo thread mounted by this instance: 1
Oracle process number: 9
Windows thread id: 3828, image: ORACLE.EXE
*** 2004-12-23 00:17:53.361
*** SESSION ID8.82) 2004-12-23 00:17:53.301
Start dump data blocks tsn: 5 file#: 5 minblk 1932 maxblk 1932
buffer tsn: 5 rdba: 0x0140078c (5/1932)
scn: 0x0000.00e9f122 seq: 0x01 flg: 0x02 tail: 0xf1220601
frmt: 0x02 chkval: 0x0000 type: 0x06=trans data
Block header dump:  0x0140078c
Object id on Block? Y
seg/obj: 0x1e48  csc: 0x00.e9f113  itc: 2  flg: E  typ: 2 - INDEX
     brn: 0  bdba: 0x1400789 ver: 0x01
     inc: 0  exflg: 0
Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
0x02   0x0005.008.000000e7  0x00800226.005c.24  --U-    1  fsc 0x0000.00e9f122
Leaf block dump
===============
header address 71963236=0x44a1264
kdxcolev 0
KDXCOLEV Flags = - - -
kdxcolok 0
kdxcoopc 0x90: opcode=0: iot flags=I-- is converted=Y
kdxconco 1
kdxcosdc 0
kdxconro 1
kdxcofbo 38=0x26
kdxcofeo 8026=0x1f5a
kdxcoavs 7988
kdxlespl 0
kdxlende 0
kdxlenxt 0=0x0
kdxleprv 0=0x0
kdxledsz 0
kdxlebksz 8036
row#0[8026] flag: K----, lock: 2
col 0; len 2; (2):  c1 02
tl: 5 fb: --H-FL-- lb: 0x0  cc: 1
col  0: [ 1]
Dump of memory from 0x044A31C7 to 0x044A31C8
44A31C0          61010100                        [...a]        
----- end of leaf block dump -----
End dump data blocks tsn: 5 file#: 5 minblk 1932 maxblk 1932

可以看到,根据DUMP结果的3、4、5、6位可以定位记录的物理位置。

需要注意的是,索引组织表以主键的顺序存储数据,因此插入、更新和删除数据都可能造成一条记录的物理位置发生变化,这时通过ROWID中的 DATAFILE和BLOCK的信息可能就无法正确定位到记录的物理位置。当根据逻辑ROWID访问索引组织表时,首先会根据DATAFILE和 BLOCK信息去找到相应的BLOCK,检查数据是否在这个BLOCK中,如果不在,就通过逻辑ROWID中的主键信息去通过索引扫描,找到这条记录。这就是Oracle文档在提到的physical guess。

下面看一个由字符串和日期组成联合主键的例子。

SQL> create table test_index2 (id char(4), time date,
  2  constraint pk_test_index2 primary key (id, time)) organization index;
表已创建。
SQL> insert into test_index2 values ('1', sysdate);
已创建 1 行。
SQL> col dump_rowid format a75
SQL> select rowid, dump(rowid) dump_rowid from test_index2;
ROWID                        DUMP_ROWID
---------------------------- ------------------------------------------------------------------
*BAFAB5QEMSAgIAd4aAwXASMT/g  Typ=208 Len=20: 2,4,1,64,7,148,4,49,32,32,32,7,120,104,12,23,1,35,19,254

可以看出,第7位是字段id的长度4,然后是字符串1和三个空格的ASCII码,这是字符串的存储格式,后面跟着的7是字段time长度,后面七位是日期的存储格式。在逻辑ROWID中,数值、字符和日期类型的存储格式都和它们本身的存储格式一致,这里不在赘述。

一般情况下,使用一位来表示长度,但是如果长度超过了127(16进制DUMP的结果是7F),则长度开始用两位表示。第一位以8开头,这个8只是标识位,表明长度字段现在由两位来表示。例如长度128表示位8080,而支持的最大值3800表示为8ED8。

Oracle基本数据类型存储格式浅析(五)——RAW类型

和其他数据类型相比,RAW类型的存储显得直观多了,它和SELECT时数据展示的值完全一样。(SELECT时是按照16进制展示的)

SQL> create table test_raw (id number, raw_date raw(10));
表已创建。
SQL> insert into test_raw values (1, hextoraw('ff'));
已创建 1 行。
SQL> drop table test_raw;
表已丢弃。
SQL> create table test_raw (raw_col raw(10));
表已创建。
SQL> insert into test_raw values (hextoraw('ff'));
已创建 1 行。
SQL> insert into test_raw values (hextoraw('0'));
已创建 1 行。
SQL> insert into test_raw values (hextoraw('23fc'));
已创建 1 行。
SQL> insert into test_raw values (hextoraw('fffffffffff'));
已创建 1 行。
SQL> insert into test_raw values (hextoraw('ffffffffffffffffffff'));
已创建 1 行。
SQL> insert into test_raw values (utl_raw.cast_to_raw('051'));
已创建 1 行。
SQL> select raw_col, dump(raw_col, 16) dump_raw from test_raw;
RAW_COL              DUMP_RAW
-------------------- -----------------------------------------------
FF                   Typ=23 Len=1: ff
00                   Typ=23 Len=1: 0
23FC                 Typ=23 Len=2: 23,fc
0FFFFFFFFFFF         Typ=23 Len=6: f,ff,ff,ff,ff,ff
FFFFFFFFFFFFFFFFFFFF Typ=23 Len=10: ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
303531               Typ=23 Len=3: 30,35,31
已选择6行。

RAW类型的存储很简单,对比字段的查询结果和DUMP的结果就一目了然了。

需要注意的是,两种转化为RAW的函数之间的差别。当使用HEXTORAW时,会把字符串中数据当作16进制数。而使用UTL_RAW.CAST_TO_RAW时,直接把字符串中每个字符的ASCII码存放到RAW类型的字段中。

SQL> insert into test_raw values ('gg');
insert into test_raw values ('gg')
                             *
ERROR 位于第 1 行:
ORA-01465: 无效的十六进制数字
SQL> insert into test_raw values (hextoraw('gg'));
insert into test_raw values (hextoraw('gg'))
                                      *
ERROR 位于第 1 行:
ORA-01465: 无效的十六进制数字
SQL> insert into test_raw values (utl_raw.cast_to_raw('gg'));
已创建 1 行。
SQL> select raw_col, dump(raw_col, 16) dump_raw from test_raw;
RAW_COL              DUMP_RAW
-------------------- ----------------------------------------------
FF                   Typ=23 Len=1: ff
00                   Typ=23 Len=1: 0
23FC                 Typ=23 Len=2: 23,fc
6767                 Typ=23 Len=2: 67,67
0FFFFFFFFFFF         Typ=23 Len=6: f,ff,ff,ff,ff,ff
FFFFFFFFFFFFFFFFFFFF Typ=23 Len=10: ff,ff,ff,ff,ff,ff,ff,ff,ff,ff
303531               Typ=23 Len=3: 30,35,31
已选择7行。

用COMET技术实现WEB实时推送应用 Ⅲ

最后的补完:

增加了并发同步控制。主要是使用了java.util.concurrent包实现连接池的同步操作。

public class ContinuationPool extends ConcurrentHashMap<Long, TalkContinuation> { }

把连接对象和消息池分离。这样可以单独锁定消息池而不影响更新连接对象。同时每个连接的消息池可以一次接收/容纳/返回多个消息,从而实现连接切换和并发操作中不丢失消息。

public final class TalkContinuation {
public List<MessageBean> pop(long seconds) throws TalkContinuationTimeoutException {
synchronized (data) {
if (data.size() > 0) {
List<MessageBean> r = new ArrayList<MessageBean>(data);
data.clear();
continuation = null;
return r;
}
}
if (continuation != null && !continuation.isPending()
&& !continuation.suspend(seconds * 1000))
// timeout, remove the connection from pool;
synchronized (data) {
throw new TalkContinuationTimeoutException(data);
}
synchronized (data) {
List<MessageBean> r = new ArrayList<MessageBean>(data);
data.clear();
continuation = null;
return r;
}
}

public void push(MessageBean message) {
synchronized (data) {
data.add(message);
}
if (continuation != null && continuation.isPending())
continuation.resume();
}

public void update() {
synchronized (data) {
if (continuation == null)
continuation = ContinuationSupport.getContinuation(
WebContextFactory.get().getHttpServletRequest(), null);
}
}
}

通过超时从连接池中清理断开的连接。

public final class TalkContinuationTimeoutException extends Throwable {
public List<MessageBean> getData() {
return data;
}
};

Service层逻辑实现可以简单的通过调用同步对象的子操作完成。

public boolean sendMessage(MessageBean message) throws Exception {
TalkContinuation c = continuationPool.get(message.getToId());
if (c == null) {
return false;
}
c.push(message);
return true;
}

public List<MessageBean> getMessage(long hostId) throws Exception {
TalkContinuation c = continuationPool.get(hostId);
if (c == null) {
c = new TalkContinuation();
continuationPool.put(hostId, c);
}
c.update();
try {
return c.pop(timeoutSeconds * 1000);
} catch (TalkContinuationTimeoutException e) {
continuationPool.remove(hostId);
return e.getData();
}
}

呈现层只需要修改使之能一次呈现返回的多个消息即可。

onRecvMessage: function(msgs) {
if (msgs) {
var l = msgs.length;
var list = $("msgList");
for (var i = 0; i < l; i++) {
var msg = msgs[i];
var li = document.createElement("li");
li.appendChild(document.createTextNode(msg.fromId + " 对 " + msg.toId + " 说 (" + msg.timestamp + "):" + msg.content));
list.appendChild(li);
}
}
}

以上,一个简单但是性能较好的系统基本完成了。

用COMET技术实现WEB实时推送应用 Ⅱ

首先是基本类型:

消息数据类型:

public class MessageBean extends Bean {
    long fromId, toId;
    String content;
    Date timestamp;
}

连接池定义:

public class ContinuationPool extends HashMap<Long, Continuation> { }

IM核心服务类接口:

public interface TalkService {
    public boolean sendMessage(MessageBean message) throws Exception;
    public MessageBean getMessage(long hostId) throws Exception;
}

接口中仅仅包含两个基本的消息通讯服务:sendMessage/getMessage。

最后是核心服务类:

import org.directwebremoting.WebContextFactory;
import org.mortbay.util.ajax.Continuation;
import org.mortbay.util.ajax.ContinuationSupport;

public class TalkServiceContinuationImpl implements TalkService {
    /**
     * connection timeout and create new timeout seconds.
     * default 0, means connection will never timeout.
     */
    private int timeoutSeconds = 0;
    private ContinuationPool continuationPool;

    public boolean sendMessage(MessageBean message) throws Exception {
        Continuation c;
        synchronized (continuationPool) {
            c = continuationPool.get(message.getToId());
        }
        if (c != null) {
            // Push change out to clients viewing the page
            c.setObject(message);
            if (c.isPending())
                c.resume();
            return true;
        } else
            return false;
    }
    public MessageBean getMessage(long hostId) throws Exception {
        Continuation c = ContinuationSupport.getContinuation(WebContextFactory.get().getHttpServletRequest(), null);
        synchronized (continuationPool) {
            continuationPool.put(hostId, c);
        }
        if (!c.isPending())
            c.suspend(timeoutSeconds * 1000);
        synchronized (continuationPool) {
            continuationPool.remove(hostId);
        }
        return (MessageBean)c.getObject();
    }
}

sendMessage向负责根据消息的源/目的用户转发消息,getMessage生成一个listen并等待到获取消息返回或者超时。

感想:Live Write的Paste from Visual Studio插件真好用~^_^

用COMET技术实现WEB实时推送应用 Ⅰ

呃。无聊,写个民工技巧。

需求很简单,做一个类似web版gtalk的网页即时通讯系统。要求就是第一实时性要好(消息延时小),第二性能要好(能支持大量用户)——典型的又要马儿跑的好又要马儿不吃草。

查了一下,就只有两条路:轮询或者长连接。轮询是老路,想想就知道性能好不了,而且实时性和性能是直接相关成反比的,也就是相互矛盾的。长连接在NIO出现以后,理论上是可以解决这个问题的。

研究了一下长连接(COMET——我最讨厌JAVA的就是名词太多而且毫无意义-_-)。首先Jetty在这个上面还是有优势的——性能好,开发简单。但是问题是用Jetty的SelectChannelConnector之后我不知道还能不能用Apache做前台(美女?)。因为不知道怎么在AJP上面走NIO。如果不行的话,难道用单机做服务器?寒一下。不过这个没办法。

Jetty的Continuation机制可以很好的和DWR结合,实现方便的request/response流程。很省力。于是先按照IBM的GPS Tracker Sample搭了一个类似的Demo。IBM那篇文章把DWR Reverse AJAX吹得天花乱坠,搭完一看,赤果果的新瓶旧酒。不过是一个Timeout可以很长(因为长连接了)的轮询而已。跑的倒是很好,但是很明显实时性和性能都一般。而且每次response都会给页面加一截script,ugly!

然后用dwr的continuation机制(实际上就是封装了jetty的continuation,只是增加了其他java容器的兼容性,当不是在jetty内运行时直接使用servlet模式,所以后来换成直接用jetty版本的continuation),原理是开一个continuation模式的dwr request作为listener,当其他用户发送消息给这个listener(另一个dwr request)的时候,resume这个suspend的continuation,发送的消息作为response返回给listener,listener呈现消息后再发起下一个continuation listener继续监听。这样的好处是continuation的suspend timeout可以设置的很长,中间有数据(消息)收到可以直接打断suspend以返回消息,然后继续监听。如果没有消息,则除了一个continuation的连接以外不耗费资源。这样性能和实时性都比较好。

启动正常,但是发送数据的时候发现问题:同一个client对同一个jetty发起的continuation是共享的,也就是只有一个。因此有一个continuation在监听时,消息发不出去。必须等到这个continuation超时才能处理下一个dwr request(也就是消息发送request)。出现两个问题:

  1. 消息发送request必然是在两个listener continuation超时之间被处理,所以是找不到正确的目的continuation的。
  2. 就算能找到,为了保证实时性,timeout必须很短。极大的影响性能。

现在的实现是同一个jetty开两个NIO SelectChannelConnector,一个对应listener,一个对应message sender。这样suspend的listener和接收message request的实际上是两个线程,可以正确的互操作(主要是对同一个continuation的suspend/resume,以及 setObject/getObject)。

经测试,timeout设置不影响任何实时性(设置为10分钟,消息可以实时发送到对方客户端)。而长时间suspending的continuation理论上性能应该很好。

由于跳过了dwr reverse ajax而使用jetty内嵌的continuation机制,dwr仅仅用于传统的request/response,理论上应该没有浏览器兼容问题。实际测试中,IE/FF均能正确的运行测试程序,不同浏览器间消息发送也没有问题。但是IE无法刷新页面(一刷新就长时间没有回应)。我认为是IE对continuation的实现造成的,可能是如果有一个长连接开着,ie页面刷新时就会试图先等他超时了再获取新内容。


剩下的几个问题:

  1. IE长连接刷新问题(见上文)。
  2. 物理连接切断的主动检测问题:如果浏览器物理切断连接,比如按escape或者关闭浏览器,服务端能否检测到pending的dwr request被切断,以清理连接池中的对应continuation?如果不能检测,那就只能等这个连接超时又得不到刷新的时候自然清理。这样timeout也不能太长,否则连接池中的僵尸连接太多。不过我认为这是长连接实现很难解决的问题,只能等超时。
  3. 同步问题:由于continuation的suspend/resume/setObject/getObject操作是在不同的线程进行,因此无法做成线程安全的原子操作。因此如果有消息在一个listener的continuation更新过程(continuation被从连接池中remove,返回response给client side listener等待其发送下一个request建立新的continuation并插入连接池)中到达,那么必然无法找到正确的接收连接,发送也就会失败。我认为这也是理论上无法解决的,同时对一个超时超过几分钟的长连接来说,这个问题产生的概率很小,影响也不大,可以无视。
  4. 集群问题:纯用Jetty搭建WEB SERVER就算单机性能能达到要求,能否建立负载均衡集群?如果按常规模式用Apache做WEB SERVER集群,如何实现长连接的传递?

吃饭去了,回来贴代码~^_^

仰慕一下

世界顶尖Linux内核黑客合照2007版(点击看大图,有名字标识)。好奇,那个Mingming Cao mm是什么来头。

烂MSDN,牛Wiki

被几个API的声明搞得昏头转向半天。MSDN的定义居然跑不通,找到一个网站,上面几乎有全部的API在.Net下移植封装的声明。的确是厉害。搞定了回头看看才发现是个WiKi,怪不得能做出这么耗费人力的事情来。果然是众人拾柴火焰高啊~

强烈推荐一下这个网站:PINVOKE.NET。顺路严重鄙视MSDN!


好玩的

在Location Finder上面找自己……

My Windows Live Local Scratch Pad

Microsoft Redwest Building D

Homestead Studio Suites Hotel
15805 NE 28th St, Bellevue, WA 98008

以下是找到的从住的旅店到办公室的路径。嘿嘿。

Time Mile Instruction For Toward
Summary:  1.9 miles (5 minutes)
9:00 AM 0.0 Depart Homestead Studio Suites Hotel [15805 NE 28th St, Bellevue, WA  98008, (425) 885-6675] on NE 28th St (West) 87 yds 
9:00 AM 0.1 Turn RIGHT (North) onto 156th Ave NE 0.8 mi 
9:02 AM 0.8 Turn LEFT (West) onto NE 40th St 164 yds 
9:03 AM 0.9 Turn RIGHT (North) onto Ramp 0.5 mi WA-520
9:03 AM 1.4 Keep RIGHT to stay on Ramp 0.1 mi NE 51st St
9:04 AM 1.5 Turn LEFT (West) onto NE 51st St 0.3 mi 
9:04 AM 1.8 Turn RIGHT (North) onto 148th Ave NE 153 yds 
9:05 AM 1.9 Arrive near Redmond  

SUMMARY
Driving distance:  1.9 miles
Trip duration:  5 minutes
Driving time:  5 minutes
Cost:  $0.16

赞M$的2005系列

SQL Server 2005有了自定义聚类。
口水好久的东东啊……虽然相信用起来还是一如既往的烂~

PowerToy新功能完全图解教程

PowerToy新功能完全图解教程

此文来自Easy Start To The Day

HTML模块完全图解教程

[Q] HTML模块实现功能
HTML模块允许用户使用一个自定义模块,在该模块之内用户可以随意使用HTML来排版, 个性化等,例如弄一个专门的每周绘画作品展示等等...




[Q] 如何添加HTML模块
使用该模块的前提是IE6或更高版本, 该模块不支持中文版本. 所有选项包括提示只显示英文.

[Steps]
1. 登陆您的MSN Spaces, 点击自定义[Customize]
2. 在浏览器地址栏[Address bar]的URL后面添加参数 &powertoy=sandbox 按Enter或者点击转到[Go]


3. 点击自定义[Customize]->模块[Modules]
4. 在下拉列表中找到PowerToy: Custom HTML项, 选择添加[Add]


5. 选择保存[Save]按钮




[Q] 如何使用该模块
该模块共有三大部分
1. HTML文本框 [非RTE] 在这里输入你喜欢的HTML代码 为了不扼杀你的创意 你喜欢输什么就输什么 
2. 模块标题 [Module Name TextBox]
3. 是否显示边框复选框[Show Border CheckBox] 不显示边框一般是为Plain Black/Red/Blue/Green服务的
4. 保存[Save]按钮 回复[Revert]按钮-回到上次保存状态 不作保存




[Q] 使用该模块还有什么其他问题?
1. 该模块无RTE, 完全符合喜欢HTML编辑的用户 :)
2. 该模块只支持512个字符, 因此不能输入大量的HTML代码, 使用部分受限.
3. 该模块同样会过滤大量HTML标签
4. 用户应当自行权衡是否使用边框 视觉效果等应自行解决
5. 我放进去一个图片或者别的东西竟然右边出去了!!! Answer: 大哥大姐, 本来让你自定义, 如果不怕难看就让他出去吧 自定义嘛 那就尽量不要让他出去喽


界面设计模块完全图解教程


 

[Q] 界面设计模块实现功能
界面设计模块允许用户使用一个自定义模块,在该模块之内用户可以随意调整整个Spaces的文字颜色 背景色等等一系列属性 个性十足 今天你Spaces了吗 这才是真正的自定义!


[Q] 如何添加界面设计模块
使用该模块的前提是IE6或更高版本, 该模块不支持中文版本. 所有选项包括提示只显示英文.

[Steps]
1. 登陆您的MSN Spaces, 点击自定义[Customize]
2. 在浏览器地址栏[Address bar]的URL后面添加参数 &powertoy=tweakomatic 按Enter或点击转到[Go]


3. 点击自定义[Customize]->模块[Modules]
4. 在下拉列表中找到PowerToy: Tweak UI项, 选择添加[Add]


5. 选择保存[Save]按钮


[Q] 如何使用该模块
该模块共有5大部分
1. 背景色[Background Color] 包括内部[Inner] 和 外部[Outer]

     A. 内部[Inner] Spaces内部各模块空隙处的背景颜色 3个两位十六进制正整数 00-FF 如:00CCFF
     B. 外部[Outer] Spaces右边空白处的背景颜色[大背景色] 3个两位十六进制正整数 00-FF 如:00CCFF



2. 背景图片[Background Image] 包括位置[Position] , 重复[Repeat] 和显示[Display] 依据各个主题[Theme]的不同 有些是有背景而有些是没有背景图片的 对于有背景图片的 我们可以:

     A. 位置[Position] Spaces背景图片的位置, 依次为默认[Default], 左上[Top Left], 中上[Top Center], 右上[Top Right], 左中[Center Left], 中中[Center Center], 右中[Center Right], 左下[Bottom Left], 中下[Bottom Center], 右下[Bottom Right] 这个不需要细讲了吧 崩溃了
     B. 重复[Repeat] Spaces背景图片重复的方式 不明白? 就是Windows桌面墙纸不是经常有中央,平铺以及拉伸什么的嘛, 就是差不多那个意思. 这里依次有默认[Default], 重复[Repeat], 不重复[No Repeat], 纵[Y]向重复[Repeat-Y], 横[X]向重复[Repeat-X]. 如果你背景是大图片, 就不要重复了, 小图片重阿重的才有效果 总体来说 可能我翻译不恰当 重复你就当成平铺好了 这样更好理解

    C. 显示[Display] 是否显示背景图片 默认[Default]是显示的, 隐藏[Hide]则不显示

3. 文字颜色[Font Color] 包括链接/链接图标[Links/Bullets] 和 文字[Text]

     A. 链接/链接图标[Links/Bullets]  所有超链接以及链接符号的颜色 3个两位十六进制正整数 00-FF 如:00CCFF
     B. 文字[Text] 所有非链接普通文本的颜色 3个两位十六进制正整数 00-FF 如:00CCFF

4. 模块背景[Module Background] 包括颜色[Color] 和 透明度[Transparent]

     A. 颜色[Color]  各个模块的背景颜色 3个两位十六进制正整数 00-FF 如:00CCFF
     B. 透明度[Transparent] 各个模块背景的透明度设置 20-100的整数值 分别为 20%-100%不透明 使用这个对整体视觉冲击比较大

5. 模块边框[Module Borders] 包括宽度[Width], 风格[Style] 和 颜色[Color]

     A. 宽度[Width]  各个模块边框的宽度 0-9 建议值为0或1 2以上就不要弄拉 大哥大姐 弄那么粗的边框真的很难看啊 不信弄个9试试? 嘿 还试试就试试? 郁闷
     B. 风格[Style] 各个模块边框的风格设置  用过.Net开发Web或者网页经常用的就知道有什么区别 当然 大家多试几次都能看出来 依次有默认[Default]-默认, 无[None]-不显示边框, [Dotted]-小点点, [Dashed]-小虚线, [Solid]-实线, [Double]-实线, [Groove]-凹按钮, [Ridge]凸按钮, [Inset], [Win-inset], [Outset]-没啥大的区别? 主要是用在这里不合适 不明显 不说了 郁闷
     B. 颜色[Color] 各个模块边框的颜色设置 3个两位十六进制正整数 00-FF 如:00CCFF



6. 保存[Save]按钮 回复[Revert]按钮-回到上次保存状态 不作保存

 

[Q] 使用该模块还有什么其他问题?
1. 该模块使用应当具备一定的视觉素养 否则任意修改都将造成超级大花脸的诞生 切记!
2. 该模块建议查询颜色代码值[如: 99FFDD] 不支持Red/rgb(205,10,36)等颜色单位
3. 怎么这么难看阿 救命啊 救命? 请参考问题一 哈哈 吓你的阿 将所有选项留空 按保存 他就又回到默认设置了阿
4.  一旦在自定义中去掉了PowerToy: Tweak UI项目 所有将回归原位...


视频音乐模块完全图解教程
 
  

相关教程: HTML模块完全图解 界面设计模块完全图解


[Q] 视频音乐模块实现功能
视频音乐模块允许用户使用一个自定义模块,在该模块之内用户可以随意使用发布视频,音乐, 包括自动播放等等.


[Q] 如何添加视频音乐模块
使用该模块的前提是IE6或更高版本, 该模块不支持中文版本. 所有选项包括提示只显示英文.

[Steps]
1. 登陆您的MSN Spaces, 点击自定义[Customize]
2. 在浏览器地址栏[Address bar]的URL后面添加参数 &powertoy=musicvideo 按Enter或点击转到[Go]


3. 点击自定义[Customize]->模块[Modules]
4. 在下拉列表中找到PowerToy: Windows Media Player项, 选择添加[Add]


5. 选择保存[Save]按钮


[Q] 如何使用该模块
该模块共有7个部分
1. URL文本框 [URL Textbox] 在这里输入你想要播放的音乐/视频地址 大哥大姐 别找那些没用的还有隐藏的非
事实的地址
2. 起始播放秒数 [Position in sec Textbox] 输入整数,单位秒 代表播放开始时间
3. 播放次数 [Times to play Textbox] 输入整数 
4. 播放速率 [Rate to play Textbox] 输入整数或小数 例如2.5, 代表播放速度是正常速度的2.5倍
5. 自动播放 [Auto Start CheckBox] 选择则表示将自动播放
6. 显示模式 [Display Mode Selector]
共四种模式, 分别为: 不可见[Invisible], 无[None], 迷你[Mini], 完全[Full]

     A. 不可见 [Invisible] 选择该模式隐藏整个模块,一般用于播放音乐, 建议选中自动播放, 否则无法自动开始
     B. 无 [None] 该模式将不显示播放器的控制栏, 建议选中自动播放[5]或者允许右键[7], 否则无法播放
     C. 迷你 [Mini] 该模式将隐藏部分播放器控制栏 如进度条快进/快退, 前一段/后一段等
     D. 完全 [Full] 该模式显示所有播放器控制栏

7. 右键菜单 [Right Click Menus Checkbox] 选择表示允许播放器右键菜单, 可以从中选择播放以及其他属性 不选则不显示 可以初级隐藏播放文件的地址[当然,可以从源文件中查到]


8. 保存[Save]按钮 回复[Revert]按钮-回到上次保存状态 不作保存




[Q] 使用该模块还有什么其他问题?
1. 试了大半天, 发现该模块只支持WMA, WMV, WAV, AVI, MPG, MPEG, MP3格式, 看见没QuickTime/Real都不支持阿 什么叫垄断 什么叫排他? 这就叫...
2. 使用该模块应该视网络环境/速率适当使用 切不可盲目使用造成部分用户长时间等待 得不偿失
3. 使用该模块应该注意视频/音乐版权问题 无论在世界还是在中国 用户应当有版权意识
4. 请确认你的电脑已经安装Windows Media Player播放器, 注意: Real[One] Player以及QuickTime插件是不支持的
5. 无法代替Flash