Archive

Archive for the ‘life is fun’ Category

北极光创投邓锋:红海竞争将越来越多,而胜负取决于创始人特质


北极光创投邓锋:红海竞争将越来越多,而胜负取决于创始人特质

2017-07-15 邓锋 捕手志

 

 

有人评价,邓锋先生总能较为全面地看待一个问题,而且还能提出一些建设性意见。这与他过去的经历有着密不可分的关系,作为一位出色的投资人与成功创业者,他早年创办的NetScreen(网屏技术)在纳斯达克上市,后以42亿美金成功出售。之后他回国创办了北极光创投,成功投资了一批公司,包括美团网、汉庭酒店、WIFI万能钥匙、酷我、百合网、纷享销客等。

这一期,捕Sir要与你分享邓锋先生的一篇文章,文中他详细回顾了自己早年创办NetScreen公司的细节,分享了这些年来他在陪伴创业者成长的过程中,所观察提炼出的优秀创业者的特质,以及大多数创业者在早期都会感到困惑的一个问题。

 红海竞争将越来越多,而胜负取决于创始人特质

作者|邓锋   编辑|潘宇波

文章来源:北极光创投、盛景网联

*转载请留言后台

创业经历

我大学毕业后,自己就跑去国外读研究生,后去了Intel,做了几年工程师。1997年11月我在美国硅谷和几个清华同学一起创办了一个信息安全的企业——NetScreen,花了4年的时间将公司送上了纳斯达克,2004年以42亿美金把公司卖给了另一家大的互联网公司Juniper(瞻博网络)。

当时,互联网泡沫已经破灭了,所以我们能在较短的时间内取得这样一个成绩,还是挺不错的。到公司卖掉时,我们的产品一共销售到了110多个国家,团队大概1000多人,营业额一年有近6亿美金。

表面上看去,你可能会觉得我们整个创业过程很顺利,但实际上公司从成立到上市的4年时间中也经历了很多不为人知的波折。我们创业时,几个人一共放弃了差不多100多万美金的股票期权,所以当时我们想,只要能挣到200万美金就算值了。当公司做到1年零9个月时,有一个上市公司要来收购我们,出价是4.5亿美金,我当时挺高兴的,觉得不到2年就做到4.5亿美金,远超我们当初的设想,所以当然要卖了。

于是,我们就兴高采烈地配合人家做了尽职调查,结果谁知到了正式签合同那天对方突然不签了,我们这才发现对方已经买下了竞争对手。当时我们就傻了,公司没卖成,还把信息都告诉了别人,在员工面前觉得一点面子都没有。后来,经过一番安抚,才让我们的员工继续好好工作。

三个月后,又一家纳斯达克上市公司找我们,又是谈收购的事。

这次,我就不敢和员工讲了。对方觉得我们公司不错,出价9亿美金,我当时想:幸亏上次没卖,3个月就翻倍啊!这次我们直到尽职调查做完,签了Definitive Agreement(最终合同)后才和员工说这次收购的事。那时候虽然还没有完成交割,但在法律上等于对方已经购买了我们公司,员工也都为公司卖了个更高的价钱而高兴,但厄运又来到了。

我们都不曾想到,几乎在签合同的同时股票市场突然暴跌,而且买我们的这家公司是当时受打击最严重的公司之一。我们签了合同一个多星期后,高兴劲儿还没过去,公司股票一天就下跌了20%,签合同不到一个月,股票价值还剩不到原来的1/3,这就是说原来的9亿美金变成3亿美金。这时候所有员工都觉得,犯一次错误并不算什么,但在这么短的时间内连续犯同样的错误,实在是太糟糕了!

那时硅谷的所有公司都在到处挖人,我的每个员工手里都拿到了不少Offer,好在我原来在清华是做辅导员的,就和员工谈心,一谈就是14个小时。硅谷的高科技公司说到根本还是靠人,关键员工如果留不住,公司马上就没了。我就和员工说,虽然我们和这家公司领了结婚证,不过还没进洞房嘛,可以想办法往回退。好在收购我们的这家公司整个团队都很好,也没在这方面太为难我们,所以我们就顺利退出来了。

经过这两次收购后,我最终决定谁也不卖了,自己去上市。团队也都愿意再相信我一次,所以大家就都奔着上市的目标前进。因为我们的收入不断增长,技术产品也一直很好,当我们开始找华尔街的投行时,高盛觉得我们不错,答应带着我们上市。员工们很高兴,意气风发,又重新找回了创业的激情,但意料之外的事又发生了。

在我们还差三天就要报美国证监会的时,突然做审计的E&Y(安永)说:「抱歉,我们不能给你们出好的审计报告,你们公司有实质性的弱点。虽然你们的业绩非常不错,但是财务一塌糊涂,管理极其混乱。」高盛一看就说那算了,他们也选择不带我们上了,这使得我又没办法和员工交代了。

在硅谷,员工真的是老大,在这种情况下,我们也得和员工交代。我们开掉了财务部门所有的人,重新招人,这是一件很痛苦的事,我们花了一年的时间才把财务给调整过来。然后我们又和高盛聊了一次,高盛认为我们公司真不错,这么大的问题很快都改过来了,而且现在一切变得极其规范,所以愿意和我们合作。

很快一切准备就绪,马上就要上市了,但谁知道又突然发生了9·11,纳斯达克从5000点跌到1400点。可是已经和员工说好了上市,上市的路线图都设计好了,没办法我们只能咬着牙,甭管是不是9·11该上还得上。

2001年12月11号,公司终于上市了。

我们是9·11之后第一家上市的公司,所有华尔街投资经理没别的公司可投,就我们这么一家,所以我们得到了很多投资,最后竟有了30倍的超购,当天公司的市值达到了26亿美金。这里我想说,有些企业你不要看表面,说4年时间成长又快又好,但这中间它一定经历了各种的起起伏伏。

创业,有时候真的是靠技术、产品、聪明、勤奋;有时候看不清楚,靠的就是信念,外加一些运气,总之是各个方面糅合在一起的结果。很多时候,我们都不能预料到明天公司又会发生什么事情,但我们必须要一步步往前

 成功者的特质

现在大家都把企业做多大、有没有上市、收入利润多少、创始人有多少钱当成是一个成功创业者的标准,其实不尽然。我看到有很多企业做得很大,但创始人未必很幸福,也没有得到社会的尊重;也有很多我认为他的企业没做得很大,也没有多么赚钱,但是他的心态很好,大家很认可他。

这些年,我也在想如何定义一个企业的成功?

后来,我认为要做一个成功的企业就要看你是否能平衡好与客户、员工、投资人这三方的关系,并使得他们与你合作能感到快乐。如果只是为了赚钱,虽然能给股东带来不错的回报,但这未必能让员工感到快乐。如果企业能够提供客户所喜欢的服务或产品,在业界有品牌能得到尊重,公司的员工流失率很低,大家感觉工作环境是愉快的,每个人不仅能获得物质上的回报还有精神上的满足,在我看来这会是一家成功的企业,不管它规模大小、上市与否

一个企业做到最后就是人的问题,而能解决这个问题的只有创始人,他(她)对企业的发展最为重要。投资人看企业的时候,最主要的就是看企业的创始人,毕竟中国的商业环境正在逐渐成熟,之前靠一些特权、批文,可以走在灰色地带,但这种赚钱的机会将越来越少,越来越多的机会是在阳光下、在成熟市场的环境下竞争,红海竞争的局面也会越来越多。

在这种情况下创始人的重要性将会更为突出,创始人的特质也会更重要。我个人认为有些特质是在做企业之前必须有的,如果你做企业之后再去培养的话已经晚了。比如,我们世界观的形成、思维方式、做事行为方式,这其实是在自己年轻的时候就已经基本形成了。所以,投资人大多数的时候是在选人而不是在培养人,以下是我理解的成功创业者所具备的特质:

1)要具备快速学习的能力。大多数创业者刚开始创业时,可能只有一方面很强,其它方面都能可能是缺点。做早期投资,也存在两种不同的思维方式:一种是看这个创业者有多少缺点;一种看这个创业者有多少优点。

创业者能走多远多快,决定着企业能做多大。比如说一个工程师技术能力很强,没有管理团队的能力,没有用技术去定义一款产品的能力,没有做市场营销的能力,更谈不到去制订战略,在一个大公司里训练很多年然后出来创业也未必能成功。真正好的创业者从跨国企业中高管出来的很少,大多数都是草根创业,在学习中不断挑战自我,变成技术的观察者或管理营销专家

2)具备持续创新的能力非常重要。如果一个企业没有创新的基因,企业是很难做得很远,也很难做大的。有些创业者认为自己的创意属机密,其实好的点子不能成就一个企业,一个伟大的企业一定要不断的创新,如果建立不了壁垒,别人可以很快超越你。创新是做出优秀企业非常重要的基因。

3)创业者要具备「赢」的雄心。创业者一定要有雄心,一定要敢于挑战,不惧怕权威,甚至面对大企业要有必胜的信念。胆子要大,要有野心。如果没有「我要赢」这种雄心,碰到困难就往后缩,企业是做不了的。

4)创业者要有理想。理想不等于激情,激情可能能持续一年或者更长时间,但未必能坚持很长时间。一些优秀创业者的理想不是「我要赚钱成为中国的首富」,他们都有着超越物质财富回报的理想,之所以选择创业完全来自于他们强烈的兴趣爱好。

5)要能坚持不懈。马云讲过今天很残酷,明天更残酷,后天很美好。有时候企业要靠你的才干往前走,有时候靠运气,创业者总要能坚信些什么才行,毕竟周围有很多诱惑,能够坚持下来最后做成的概率会高一些。在企业最困难的时候没有掉头,坚持往下做,最后做出来了,今天中国最优秀的创业者都是这样的。

6)具备责任感。创业者能够坚持、能够成功,很重要的是来自于他的责任。对家人、亲人、朋友、员工及投资人的责任,上下游可能也是依靠这个企业成长而成长的,创业者必须要付起这个责任,这件事不干好对不起他们。

7)胸怀是最终成事的重要因素。我们最不愿意投资自私的创业者,把自己利益放在企业之上,这样的企业发展再好,技术再创新也不投,因为它绝对是做不成长久的。创业者学习能力可以不断培养,胸怀等特质是培养不了的。

8)有智商还要有情商。企业做得越大情商越高。真正优秀的创业者具有很强的领导力,他不是技术专家,不是营销专家,但他有很向心的领导力把这些人吸引过来,把企业做大做强。

在公司运营当中,虽然你也不是公司的每个战略决定都要告诉员工,但你一定要将自己的真实想法与团队分享,让他们和你同喜同忧。千万别装酷,别装得自己什么都行。我们公司经营4年就成功上市了,这个过程并不是一帆风顺,而是经历了三起三落。低谷的时候我会和员工开诚布公,对他们说,很抱歉,我们真的犯错误了。

 

融资后的六个注意事项

2005年,我从硅谷回国,创立了北极光创投。截至目前,我们有幸与很多优秀的创业者合作,在陪伴创业者成长的过程中,我们发现一个相对明显的问题——有不少创业者,在拿到天使轮或者Pre-A轮融资后,作为企业的创始CEO或创始团队成员,不知道应该注意些什么?其实,我认为六点是值得很多创业者注意的:

1)现金流

在当前的市场环境下,这尤其是CEO的第一大要务。有很多本身不错的公司,因为花钱速度太快,结果自己败在了现金流失控的问题上。再好的企业,如果现金流突然断了,团队也没有办法稳定。

创始人对公司员工负责、对公司股东负责的首要任务是把公司的现金流控制好。当现金还有六个月就要花完的时就要开始注意了,尤其是当公司只够三个月的时,公司的处境就更危险了。CEO要保证哪怕公司没有融到资,还能运转至少半年,把控好公司的现金流,这个说多少遍都不为过。

2)

创业者一旦拿到钱后,从第一天起就要把注意力放在人身上。做企业最关键是建立一个组织,这其中,人是最重要的。招人、留人、用人、培养人都很重要。招人是CEO最重要的工作,创始人要评估自己每周有多少时间花在招人和与员工的沟通上。

时间的分配是衡量自己聚焦点的好方法。判断在人上的聚焦够不够的标准,就是统计自己在人上花了多少时间。我认为花在招人、与内部员工沟通、与外部客户沟通的时间应该占到一个CEO的50%以上的时间

3)执行力和速度

执行力是能把想的事情在多快的时间内执行到位,而且要能看得出效果。最怕的是事情没做成,但却不知道自己是战略错误还是执行不到位

速度也是一个很关键的判断执行力的指标,就像前面我们说时间分配是衡量聚焦点的重要指标。速度的重要性不是说销售成长快,而在于一个事情能不能解决,解决的到不到位。小企业要以快取胜,这里的快不是销售产生的速度,而是事情执行到位的速度

4)产品

公司早期要把产品放在第一位,而不是技术也不是营销(Marketing)。所谓做产品,最关键的是对客户需求的不断定位,找到客户的需求,把自己的资源和客户进行匹配,在很快的时间内把产品做出来。

在中国创业,技术很重要,但很多技术导向型的企业一定不是靠技术来做生意的,尤其是一些To B方向的企业,这是一个强关系型的生意,要知道买你产品的决策人是谁。比如,面向大企业的业务一定是部门做决策的,那影响他们决策的因素是什么,这些都是你在做产品的时候需要想到的。

归根结底,作为公司的老大,在一开始的阶段对产品的关心要高于对技术的关心,以及对市场营销的关心。你要能将销售和营销分开来看,产品刚出来的时候要重视Sales、轻视Marketing。

5)企业文化

很多创业者在初期不太注意这一点,其实企业文化从企业早期就逐渐形成了。如果早期有意培养了优秀的企业文化,那么在企业文化内核确定了之后,只要进新人的速度不是太快,公司文化就会沿着这个方向发展。

创始人应该好好想一想公司企业文化的这个「核」是什么。各家有各家的选择,但我要特别提醒一下,企业文化不是靠口号宣传出来的,是要靠创始人在点点滴滴的小事儿上实际出来的。比如,如果你的企业文化是关爱员工,那么一个新员工加入后,你能不能第一次见面就叫出他(她)的名字。企业文化的本质是创始人领导力的体现,创始人是什么样的人,创办的企业就会是什么模样的。

6)融资能力

创业者的融资能力正在变得很重要,这是我不愿意看到但在中国市场正在发生的事实。今天的中国VC市场上,创业者可能是需要一点忽悠的能力,但这个度怎么把握确实很难说清楚。很多企业级服务和医疗项目的创业者之前是工程师、产品经理,都不知道怎么宣传自己和公司,但作为创始人你要学会怎么把自己的公司和产品从更高的角度、用更大的概念讲好。不管我们喜欢不喜欢,融资的时候不会讲故事就会吃亏

Categories: life is fun

Natural Language Pipeline for Chatbots


Natural Language Pipeline for Chatbots

Chatbot developers usually use two technologies to make the bot understand the meaning of user messages: machine learning andhardcoded rules. See more details on chatbot architecture in my previous article.

Machine learning can help you to identify the intent of the message and extract named entities. It is quite powerful but requires lots of data to train the model. Rule of thumb is to have around 1000 examples for each class for classification problems.

 

If you don’t have enough labeled data then you can handcraft rules which will identify the intent of a message. Rules can be as simple as “if a sentence contains words ‘pay’ and ‘order’ then the user is asking to pay for an order”. And the simplest implementation in your favorite programming language could look like this:

def isRefundRequest(message):
    return 'pay' in message or 'order' in message

Any intent classification code can make errors of two types. True positives: the user doesn’t express an intent, but the chatbot identifies an intent. False positives: the user expresses an intent, but the chatbot doesn’t find it. This simple solution will make lots of errors:

  1. The user can use words “pay” and “order” in different sentences: “I make an order by mistake. I won’t pay.”
  2. A keyword is a substring of another word: “Can I use paypal for order #123?”
  3. Spelling errors: “My orrder number is #123. How can I pay?”
  4. Different forms of words: “How can I pay for my orders?”

 

Your chatbot needs a preprocessing NLP pipeline to handle typical errors. It may include these steps:

  1. Spellcheck

Get the raw input and fix spelling errors. You can do something very simple  or build a spell checker using deep learning.

  1. Split into sentences

It is very helpful to analyze every sentence separately. Splitting the text into sentences is easy, you can use one of NLP libraries, e.g. NLTK, StanfordNLP, SpaCy.

  1. Split into words

This is also very important because hardcoded rules typically operate with words. Same NLP libraries can do it.

  1. POS tagging

Some words have multiple meanings, for an example “charge” as a noun and “charge” as a verb. Knowing a part of speech can help to disambiguate the meaning. You can use same NLP libraries, or Google SyntaxNet, that is a little bit more accurate and supports multiple languages.

  1. Lemmatize words

One word can have many forms: “pay”, “paying”, “paid”. In many cases, an exact form of the word is not important for writing a hardcoded rule. If preprocessing code can identify a lemma, a canonical form of the word, it helps to simplify the rule. Lemmatization, identifying lemmas, is based on dictionaries which list all forms of every word. The most popular dictionary for English is WordNet. NLTK and some other libraries allow using it for lemmatization.

  1. Entity recognition: dates, numbers, proper nouns

Dates and numbers can be expressed in different formats: “3/1/2016″, “1st of March”, “next Wednesday”, “2016-03-01″, “123″, “one hundred”, etc. It may be helpful to convert them to unified format before doing pattern matching. Other entities which require special treatment: locations (countries, regions, cities, street addresses, places), people, phone numbers.

  1. Find concepts/synonyms

If you want to search for a breed of a dog, you don’t want to list all the dog breeds in the rule, because there are hundreds of them. It is nice if preprocessing code identified a dog breed in the message and marked the word with  a special tag. Then you can just look for that tag when applying the rule.

WordNet can be used to identify common concepts. You may need to add domain specific concept libraries, e.g. a list of drug names if you are building a healthcare bot.

 

After preprocessing is done you have a nice clean list of sentences and lists of words inside each sentence. Each word is marked with a part of speech and concepts, and you have a lemma for every word. The next step is to define patterns for intent identification.

You can invent your own pattern language using common logical operators AND, OR, NOT. The rule can look like this if you create an internal DSL (domain-specific language) based on Python:

r = Rule(
    And(
        Or('cancel', 'close'),
        'membership',
    Respond('Would you like to cancel your membership immediately?'))

Alternatively, you can invent external DSL, which can be more readable, but you will need extra work to create a compiler or an interpreter for that language. If you use a ChatScript language, it can look like this:

u: (<<[cancel close] membership>>)
    Would you like to cancel your membership immediately?

Do you use a chatbot engine with hardcoded rules? Have your developed your own? What issues have you encountered when building or using a chatbot engine? Please share in comments!

Categories: life is fun

Nvidia Tesla K20c on Ubuntu 16.04

February 4, 2017 Leave a comment

Spent 2 days to sort this out.  To install Nvidia Tesla K20c on Ubuntu 16.04.

My hardware + OS env :

  • Nvidia Tesla K20c
  • Nvidia GT 520 (graphic card to monitor)
  • Intel i5 CPU
  • 16GB RAM
  • Ubuntu 16.04 on SSD

Initially, I installed the Nvidia official driver, and CUDA using :

  • sudo apt-get install nvidia-cuda-toolkit
  • sudo ./NVIDIA-Linux-x86_64-331.89.run

But then ran into several weird errors like below.

“`
victor@ubuntu-tesla:~/Downloads$ cat /var/log/nvidia-installer.log
nvidia-installer log file ‘/var/log/nvidia-installer.log’
creation time: Sat Feb 4 11:15:23 2017
installer version: 331.89

PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin

nvidia-installer command line:
./nvidia-installer
–no-cc-version-check

Using: nvidia-installer ncurses user interface
-> License accepted.
-> Installing NVIDIA driver version 331.89.
-> There appears to already be a driver installed on your system (version: 331.89). As part of installing this driver (version: 331.89), the existing driver will be uninstalled. Are you sure you want to continue? (‘no’ will abort installation) (Answer: Yes)
-> Running distribution scripts
executing: ‘/usr/lib/nvidia/pre-install’…
-> done.
-> The distribution-provided pre-install script failed! Continue installation anyway? (Answer: Yes)
-> Would you like to register the kernel module sources with DKMS? This will allow DKMS to automatically build a new module, if you install a different kernel later. (Answer: No)
-> Performing CC sanity check with CC=”cc”.
-> Kernel source path: ‘/lib/modules/4.4.0-59-generic/build’
-> Kernel output path: ‘/lib/modules/4.4.0-59-generic/build’
-> Performing rivafb check.
-> Performing nvidiafb check.
-> Performing Xen check.
-> Performing PREEMPT_RT check.
-> Cleaning kernel module build directory.
executing: ‘cd ./kernel; make clean’…
-> Building NVIDIA kernel module:
executing: ‘cd ./kernel; make module SYSSRC=/lib/modules/4.4.0-59-generic/build SYSOUT=/lib/modules/4.4.0-59-generic/build NV_BUILD_MODULE_INSTANCES=’…
NVIDIA: calling KBUILD…
make[1]: Entering directory ‘/usr/src/linux-headers-4.4.0-59-generic’
test -e include/generated/autoconf.h -a -e include/config/auto.conf || ( \
echo >&2; \
echo >&2 ” ERROR: Kernel configuration is invalid.”; \
echo >&2 ” include/generated/autoconf.h or include/config/auto.conf are missing.”;\
echo >&2 ” Run ‘make oldconfig && make prepare’ on kernel src to fix it.”; \
echo >&2 ; \
/bin/false)
mkdir -p /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/.tmp_versions ; rm -f /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/.tmp_versions/*
make -f ./scripts/Makefile.build obj=/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel
cc -Wp,-MD,/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/.nv.o.d -nostdinc -isystem /usr/lib/gcc/x86_64-linux-gnu/5/include -I./arch/x86/include -Iarch/x86/include/generated/uapi -Iarch/x86/include/generated -Iinclude -I./arch/x86/include/uapi -Iarch/x86/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi –
include ./include/linux/kconfig.h -Iubuntu/include -D__KERNEL__ -fno-pie -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -fno-pie -no-pie -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time -maccumulate-outgoing-args -DCONFIG_X86_X32_ABI -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1 -DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables -fno-delete-null-pointer-checks -Wno-maybe-uninitialized -O2 –param=allow-store-data-races=0 -Wframe-larger-than=1024 -fstack-protector-strong -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls
-fno-var-tracking-assignments -pg -mfentry -DCC_USING_FENTRY -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -DCC_HAVE_ASM_GOTO -DNV_MODULE_INSTANCE=0 -DNV_BUILD_MODULE_INSTANCES=0 -UDEBUG -U_DEBUG -DNDEBUG -I/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel -Wall -MD -Wsign-compare -Wno-cast-qual -Wno-error -D__KERNEL__ -DMODULE -DNVRM -DNV_VERSION_STRING=\”331.89\” -Wno-unused-function -Wuninitialized -mno-red-zone -mcmodel=kernel -DNV_UVM_ENABLE -D__linux__ -DNV_DEV_NAME=\”nvidia\” -DMODULE -D”KBUILD_STR(s)=#s” -D”KBUILD_BASENAME=KBUILD_STR(nv)” -D”KBUILD_MODNAME=KBUILD_STR(nvidia)” -c -o /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/.tmp_nv.o /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.c
In file included from include/uapi/linux/stddef.h:1:0,
from include/linux/stddef.h:4,
from ./include/uapi/linux/posix_types.h:4,
from include/uapi/linux/types.h:13,
from include/linux/types.h:5,
from include/uapi/linux/capability.h:16,
from include/linux/capability.h:15,
from include/linux/sched.h:15,
from include/linux/utsname.h:5,
from /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv-linux.h:44,
from /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.c:13:
include/asm-generic/qrwlock.h: In function ‘queued_write_trylock’:
include/asm-generic/qrwlock.h:93:36: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
cnts, cnts | _QW_LOCKED) == cnts);
^
include/linux/compiler.h:165:40: note: in definition of macro ‘likely’
# define likely(x) __builtin_expect(!!(x), 1)
^
In file included from ./arch/x86/include/asm/preempt.h:5:0,
from include/linux/preempt.h:59,
from include/linux/spinlock.h:50,
from include/linux/seqlock.h:35,
from include/linux/time.h:5,
from include/uapi/linux/timex.h:56,
from include/linux/timex.h:56,
from include/linux/sched.h:19,
from include/linux/utsname.h:5,
from /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv-linux.h:44,
from /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.c:13:
include/linux/percpu-refcount.h: In function ‘percpu_ref_get_many’:
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:419:34: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_1(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:364:11: note: in expansion of macro ‘this_cpu_add_1’
case 1: stem##1(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-refcount.h:177:3: note: in expansion of macro ‘this_cpu_add’
this_cpu_add(*percpu_count, nr);
^
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:420:34: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_2(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:365:11: note: in expansion of macro ‘this_cpu_add_2’
case 2: stem##2(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-refcount.h:177:3: note: in expansion of macro ‘this_cpu_add’
this_cpu_add(*percpu_count, nr);
^
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:421:34: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_4(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:366:11: note: in expansion of macro ‘this_cpu_add_4’
case 4: stem##4(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-refcount.h:177:3: note: in expansion of macro ‘this_cpu_add’
this_cpu_add(*percpu_count, nr);
^
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:478:35: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_8(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:367:11: note: in expansion of macro ‘this_cpu_add_8’
case 8: stem##8(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-refcount.h:177:3: note: in expansion of macro ‘this_cpu_add’
this_cpu_add(*percpu_count, nr);
^
include/linux/percpu-refcount.h: In function ‘percpu_ref_put_many’:
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:419:34: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_1(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:364:11: note: in expansion of macro ‘this_cpu_add_1’
case 1: stem##1(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-defs.h:506:33: note: in expansion of macro ‘this_cpu_add’
#define this_cpu_sub(pcp, val) this_cpu_add(pcp, -(typeof(pcp))(val))
^
include/linux/percpu-refcount.h:276:3: note: in expansion of macro ‘this_cpu_sub’
this_cpu_sub(*percpu_count, nr);
^
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:420:34: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_2(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:365:11: note: in expansion of macro ‘this_cpu_add_2’
case 2: stem##2(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-defs.h:506:33: note: in expansion of macro ‘this_cpu_add’
#define this_cpu_sub(pcp, val) this_cpu_add(pcp, -(typeof(pcp))(val))
^
include/linux/percpu-refcount.h:276:3: note: in expansion of macro ‘this_cpu_sub’
this_cpu_sub(*percpu_count, nr);
^
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:421:34: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_4(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:366:11: note: in expansion of macro ‘this_cpu_add_4’
case 4: stem##4(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-defs.h:506:33: note: in expansion of macro ‘this_cpu_add’
#define this_cpu_sub(pcp, val) this_cpu_add(pcp, -(typeof(pcp))(val))
^
include/linux/percpu-refcount.h:276:3: note: in expansion of macro ‘this_cpu_sub’
this_cpu_sub(*percpu_count, nr);
^
./arch/x86/include/asm/percpu.h:130:31: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
((val) == 1 || (val) == -1)) ? \
^
./arch/x86/include/asm/percpu.h:478:35: note: in expansion of macro ‘percpu_add_op’
#define this_cpu_add_8(pcp, val) percpu_add_op((pcp), val)
^
include/linux/percpu-defs.h:367:11: note: in expansion of macro ‘this_cpu_add_8’
case 8: stem##8(variable, __VA_ARGS__);break; \
^
include/linux/percpu-defs.h:496:33: note: in expansion of macro ‘__pcpu_size_call’
#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val)
^
include/linux/percpu-defs.h:506:33: note: in expansion of macro ‘this_cpu_add’
#define this_cpu_sub(pcp, val) this_cpu_add(pcp, -(typeof(pcp))(val))
^
include/linux/percpu-refcount.h:276:3: note: in expansion of macro ‘this_cpu_sub’
this_cpu_sub(*percpu_count, nr);
^
In file included from include/uapi/linux/stddef.h:1:0,
from include/linux/stddef.h:4,
from ./include/uapi/linux/posix_types.h:4,
from include/uapi/linux/types.h:13,
from include/linux/types.h:5,
from include/uapi/linux/capability.h:16,
from include/linux/capability.h:15,
from include/linux/sched.h:15,
from include/linux/utsname.h:5,
from /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv-linux.h:44,
from /tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.c:13:
./arch/x86/include/asm/uaccess.h: In function ‘copy_from_user’:
./arch/x86/include/asm/uaccess.h:717:26: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (likely(sz < 0 || sz >= n))
^
include/linux/compiler.h:165:40: note: in definition of macro ‘likely’
# define likely(x) __builtin_expect(!!(x), 1)
^
./arch/x86/include/asm/uaccess.h: In function ‘copy_to_user’:
./arch/x86/include/asm/uaccess.h:735:26: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
if (likely(sz < 0 || sz >= n))
^
include/linux/compiler.h:165:40: note: in definition of macro ‘likely’
# define likely(x) __builtin_expect(!!(x), 1)
^
/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.c: In function ‘nvidia_unlocked_ioctl’:
/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.c:2027:29: error: ‘struct file’ has no member named ‘f_dentry’
return nvidia_ioctl(file->f_dentry->d_inode, file, cmd, i_arg);
^
scripts/Makefile.build:258: recipe for target ‘/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.o’ failed
make[2]: *** [/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel/nv.o] Error 1
Makefile:1420: recipe for target ‘_module_/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel’ failed
make[1]: *** [_module_/tmp/selfgz26270/NVIDIA-Linux-x86_64-331.89/kernel] Error 2
make[1]: Leaving directory ‘/usr/src/linux-headers-4.4.0-59-generic’
NVIDIA: left KBUILD.
nvidia.ko failed to build!
Makefile:178: recipe for target ‘nvidia.ko’ failed
make: *** [nvidia.ko] Error 1
-> Error.
ERROR: Unable to build the NVIDIA kernel module.
ERROR: Installation has failed. Please see the file ‘/var/log/nvidia-installer.log’ for details. You may find suggestions on fixing installation problems in the README available on the Linux driver download page at http://www.nvidia.com.

“`

 

The solution is the DKMS !

“`

sudo dkms remove nvidia-current-updates/331.89

sudo apt-get install nvidia-current-updates

“`

Then re-install them:

“`

sudo ./NVIDIA-Linux-x86_64-331.89.run
sudo apt-get install nvidia-cuda-toolkit

“`

Ta-da! all works!!!!!!

“`

victor@ubuntu-tesla:~/$ nvidia-smi
Sat Feb 4 12:11:39 2017
+—————————————————————————–+
| NVIDIA-SMI 367.57 Driver Version: 367.57 |
|——————————-+———————-+———————-+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla K20c Off | 0000:01:00.0 Off | 0 |
| 30% 35C P8 27W / 225W | 0MiB / 4742MiB | 0% Default |
+——————————-+———————-+———————-+
| 1 GeForce GT 520 Off | 0000:02:00.0 N/A | N/A |
| 40% 40C P0 N/A / N/A | 348MiB / 955MiB | N/A Default |
+——————————-+———————-+———————-+

+—————————————————————————–+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 1 Not Supported |
+—————————————————————————–+
“`

 

 

Categories: life is fun

关于lease bmw的好处,和具体操作

October 1, 2016 Leave a comment

关于lease bmw的好处,和具体操作

先说结论: 如果不是要开的里程特别高,比如一年两三万mile这种

或者是要keep一辆车很久而且自己还会动手修车

否则lease bmw是经济上和体验上都更好的选择,相对购买.

下面说原因.

首先大方向上,如果自己不会修车,bmw不算是适合长期持有的车,

因为整体上一方面它的可靠性只算中规中矩,另一方面它不是很repair friendly

那么意味着出了保修,无论是必须要进行的保养,还是可能出现的故障及维修

都不是一笔小花销.

而如果购买延保,quote出来的原厂warranty+maintenance价格相当不菲,

回头买了你车不坏,纠结,没买车坏了一笔几千块账单跳出来,也纠结

最后一算出保后平均每年的cost to own,恐怕没比再lease个新车省多少

另一方面,在保修期内的bmw则非常省心,因为它是同时包warranty和maintenance,

可以说除了胎,别的上不用花什么钱

所以很多买家选择把车在过保前处理掉

那么如果确定车到手不会keep超过保修,面临的就是买来三年多卖掉,

还是lease三年.

这里面lease的优势是很明显的,体现在以下几个方面:

1.只有车的使用权,而不拥有车.这意味着不用对车特别照顾,有些轻微磕碰也不用在乎.

而且比方说一旦车出现不大不小的事故,有carfax记录但又没到报废的程度,

也不用担心以后不好卖或者卖不上价.

2.bmw和很多豪华车都算上,精髓很多是在选配里面.但这些选配有一个问题,就是你

到卖的时候,卖不上价.比方说55k起价的x5,你配到70k算是well equipped,

但三年后卖,很可能你70k的x5,也就比55k的乞丐版x5多卖五千块钱,

这意味着选配对应的售价部分会有超过车起价以上的更高折旧.

问题在于买豪华车本来就是图个体验好,弄个没啥选配的乞丐版,那体验也要大打折扣.

而在lease的时候,情况则完全不同.

首先lease的残值百分比是作用在整个车价上,意味着选配部分

对应的车价按照起价相同的比例计算折旧.其次高配的车通常更好砍价,意味着

实际上按成交价看,高配车相对乞丐版的溢价就要比两者msrp差价更低.

结果就是如果lease车,选配部分的cost to own比buy and sell的情况低很多.

3.以bmw而言,其设定的残值比例通常是比你三年后卖掉能卖出来的价高的,

且不说lease三年后直接把车还掉,不用再折腾自己卖车(费时间)或者再多被

dealer砍一刀(tradein亏钱).

综合以上三点,lease bmw,当lease是个选择的时候(有时候不是选择,比如如果

你要一年开两三万mile的话,那通常lease没这么高里程的选项),它常常是那个

更好的选择.

那么接下来说说bmw lease的基本情况和计算方法.

lease一辆车,其成本主要来自三个方面:

1. lease acquisition fee, doc fee, tax

像bmw的acq fee在795,doc fee取决于具体dealer, tax取决于具体州

这里面acq fee和tax是固定的,doc fee则可以视情况和dealer砍

2.车辆折旧,也就是车在lease期间产生的贬值.

其计算方法就是成交价-lease到期残值百分比*MSRP.

比方说我一辆70k msrp的x5,三年36kmile残值是60%,成交价65k,

那么折旧就是65-70*0.6=23k

3.财务成本.lease期间车的所有权在车厂的财务部门,那么对方持有这个车辆会占款,

因此也就会产生财务成本.这个的计算,是用成交价和到期残值的均值,

结合当前利率算出每月的财务成本.

举一例,比方说现在的apr是3.12%,那么每月的财务成本就是

(成交价+残值)/2*(3.12%/12)=(成交价+残值)*(3.12%/24)

而这里3.12%/24这一项就被命名为money factor

那么实际上1是会打到2的成交价中,所以进一步可以说,

最后决定整个lease期间支出的,就是折旧及财务支出.

对于bmw来说,对于某个型号,某段时间内它会确定一个残值百分比,

比如15款x5目前就是3年36k残值60%.而money factor也是相对固定的,

目前是0.0013(对应的apr则是3.12%)

那么实际上可以和dealer商定的就是成交价这一项(也包含doc fee).

需要提及的是,bmw官网,乃至dealer店里,常常会贴出来一个广告,

说xxxx down, yyy/month for zz (通常是30/36) month.

实际上这组数字,就是基于当前的money factor和残值设定,以及一个bmw

设定的成交价来计算出来的.而这成交价多半是不太厚道的.所以切记不要直接

从了这个lease term.如果要看某个车的当前残值设定是多少,可以直接去

bmwusa官网点special offer->lease offer.对目标车型,点进去之后看

lease offer下面的小字部分,里面都会给出说本lease offer基于msrp xxxxx,

到期残值yyyyy进行计算.用yyyyy/xxxxx,就能得到这车型当前的残值百分比.

前面已经说了,lease的折旧部分,成交价用的是实际价格,而残值百分比是作用在

msrp上,也就是说当看好了一款车,那么对应的残值就固定了.成交价砍的越低,

折旧就越少.而且这里面的成交价砍价有杠杆效应:还是以x5为例,三年残值60%,

意味着如果成交价从msrp砍到10%off msrp,那么折旧支出就从40%*msrp减到

30%*msrp,也即是说降低25%.那么如果再遇到bmw某些时候搞活动,弄出来一个

非常高的残值百分比,而车价又砍掉比较多,那么最后的折旧就会低到令人发指的程度.

比方说前一阵子bmw对15款x1给到3年68%的残值,而x1通常能搞到10%off或更高,

那么这车三年只需要付出22%msrp就能搞定,意味着一辆40k的x1,三年折旧只有8.8k

平均到每月只有244.44usd,这就是超好的deal了.

另一方面是财务成本部分.显然的,砍成交价意味着可以降低money factor作用的本金,

因此有额外的好处.但更好的一点就是bmw有一个monthly security deposit(msd)

的政策,也就是说每压一个monthly payment的钱给bmw financial services,

就可以把money factor降低0.00007,最多可以压7个.这个钱在lease结束后会退回.

那么压7个之后,原来0.0013的mf会降到0.00081,也就是等效apr从3.12降到1.94,

或者更直观的,可以将财务成本支出降低37.7%,这也相当可观.

还是大致算一笔账,70k的x5,65k成交,60%残值,那么暂时忽略手续费,

每月的财务成本,原本是(65k+42k)*0.0013=139.1,7个msd后是86.67,

意味着36个月下来可以省1887.48usd.

那么同时大致计算一个msd是(65k-42k)/36+139.1=778

意味着5446usd带来的三年回报是1887.48,以单利计算年回报率在11.6%,

这是很划算的买卖,所以基本上7个msd是lease bmw必搞的.

最后,关于lease payment.bmw广告里常常会说要downpay三千多再每个月付多少

但实际上更合适的选择是0 downpay,直接每月付款.

这里主要顾虑是一旦出了一些意外事件,比如你要转lease,或者车total了

那么downpay的部分你是拿不回来的,白白损失了.所以宁可每个月按月支付折旧.

更新:以下是cassis网友在本线程下的回复,关于lease downpay的

很有信息量,所以全文引用如下:

发信人: cassis (KW), 信区: Automobile
标  题: Re: 稍微多说几句关于lease bmw的好处,和具体操作 (转载)
发信站: BBS 未名空间站 (Sat Mar 21 03:16:50 2015, 美东)

我觉得他说的大体上是对的,至少中心思想上。

Lease的车total掉的话,原则上你欠car company的钱相当于early buyout。这个early
buyout具体怎么算我不是很清楚,应该不完全是随时间线性递减的。保险公司陪的钱
比这个early buyout少得话,有GAP insurance的话由GAP insurance负责差价,否则是
你付。

举个极端例子吧,你lease个5万卖价的车,开出去第一天就total掉。假设没有down
payment,这时候的early buyout就应该是5万。保险公司多半不会按新车全价陪,假如
它只陪4万5的话,你(或者GAP)陪剩余的5千。

假如你事先付了5千首付,这时候early buyout应该是4万5,刚好和保险公司陪的一样
,所以GAP也不会启用。这种情况下你开了一天车就完全损失掉5千首付。这就是为什么
lease一般不推荐down payment(注意trade-in也相当于down payment)。GAP
insurance一般都是包在lease的acquisition fee里的,所以total了应该可以拍屁股走
人。

对BMW的lease,补充几点:

1) Acquisition fee is $725 standard, but the dealer is allowed to mark it up
to $925. This is $200 extra profit for the dealer.
2) Money factor is 0.0013 standard (at least for much of the time). Again
the dealer is allowed to mark it up by 0.0004 to 0.0017. Multiply it by 2400
you will know this means 1% higher interest. If you lease a $50K car, this
means roughly an extra $400/year on interest, or $1200 total for a 3 year
lease. This is a common trick by the dealer. You should absolutely insist on
the standard MF.
3) There is also a $300 disposition fee when you return the car at the lease
end. It can be waived if you lease another BMW.
4) Not sure if there is also a buyout fee. I won’t buy out at the end (as it
defeats the purpose of leasing) so I didn’t do much research. If you do buy
out at the end, then you paid extra money (acquisition + buyout fees)
compared to buy directly at the beginning.

对于上述帖子,我的推论就是,当车total,如果是0 downpay,total时的保险公司

赔付和尚未支付的cap cost与到期残值之和(也就是上文中的“early buyout value”)

之间有差距(后者大于前者),这个差距也就是所谓的gap

则acquisition fee中包含的gap insurance负责付这个gap,lease车主不需额外付款。

而如果downpay付的多,本质上相当于downpay的全部或部分来支付上述gap,

结果就是很可能已经付掉的downpay也拿不回来,因此带来额外的损失。

基于上述考虑,选择0 downpay可以规避上述风险,因此是更好的选择。

最后,关于如何和dealer周旋.

和买车不同,很多人对lease的价格构成和计算是不太熟悉的,那么dealer因此也习惯

去宰lease客户,这带来的一个副产品就是对于lease客户,dealer默认更不愿意妥协,

因为会认为对方好忽悠.所以更好的方法,如@Leasing所说,去dealer先别提lease的事,

事先把功课做好,公式放手机里备用,直接就按买车来砍价.同时,如果手里有什么

厂方给的折扣,比如test drive credit, new graduate credit,等等,一律握住先不要提

等把价格砍好了,再说要按这个价格lease,并且提出压msd降mf,然后如果遇到doc fee

收的离谱的,再往下砍.到最后要成交打单子了,再把厂方给的credit提出来要求再减,

否则无良dealer会把这部分折扣直接当成自己给的来议价,增加砍价难度.

不小心敲了一大篇,已经记不得前面都说了什么,先发这些,

大伙如果有问题再回复,我试着解答.

另外我手里有带我入门的哥们儿发给我的excel,据说是完全复制了dealer的lease计算
程序

有兴趣的朋友可以回复留个邮箱,我跟大家分享一下:)

————————-
5月19日更新:

还有一点需要补充的好处,是消费税上的优势。

在那些不需对lease车进行全额缴纳消费税(比如德州就如此规定)的州

消费税仅作用在downpay和monthly payment上

也即是说残值部分不需要交税。

而对应无论cash还是finance购买,都要对车的全款进行缴税。

以一辆65k的x5来看,如果按60%残值,6%消费税计算,则意味着节省2340usd的税

而在消费税比较高的州,比如消费税到了9%左右,则可节省更多(3510usd)

当然,如果车去tradein,那么也能得到买下一辆车的消费税抵扣,

但通常tradein给dealer时,对方给的offer都会偏低。如果卖给私人,

则无法得到消费税抵扣。

Categories: life is fun

如何通过房屋租售比来判断房产的价值或泡沫?

October 1, 2016 Leave a comment

链接:https://www.zhihu.com/question/20799544/answer/44545583
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

【4月14日的更新】
感谢 @chenqin老师对售租比数据取值范围的建议,我们前后各去除了2%之后,那些比较奇葩的售租比超过2000的值(估计是挂牌价错误或单位宿舍之类的)被剔除出去了。相应的部分图纸也进行了更新,其中那张散点图的趋势变得更为明显,售租比离散区从距市中心20km处即显现了出来。
—————————————————————————————————————————————–
【4月12日的原文】
最近一直和一位师兄在研究上海的房价,有点初步的结果,拿出来跟大家讨论一下。内容有点长,先说结论吧:

就上海而言,观察所谓“房价泡沫”的问题,房屋租售比在空间上的离散程度(而非其数值)有可能是一个更好的视角。

具体内容如下:

房屋租售比是什么?一般而言,“房屋租售比”= “每平方米建筑面积的月租金”/ “每平方米建筑面积的房价”。但为了便于理解,我们可以把这个概念颠倒一下,转变为“房屋售租比”。

倒过来,“房屋售租比”=“每平方米建筑面积的房价”/“每平方米建筑面积的月租金”,其含义可以简单理解为:“在保持当前的房价和租金条件不变的情况下,完全收回投资需要多少个月”。

一般而言,按照国际经验,在一个房产运行情况良好的区域,应该可以在200-300个月内完全回收投资。如果少于200个月(17年)就能收回投资,说明这个地区有较高的投资价值;如果一个地区需要高于300个月(25年),比如1200个月(100年)才能回收投资,则说明该地区有潜在的房产泡沫风险。

200~300个月的安全区间,这是怎么算出来的呢?

简单举个例子吧,我准备投资一套房产,不想占用太多现金流,怎么办?付个首付,问银行贷款呗,能贷多少贷多少,大不了租金全部用来还按揭。好的没问题,这样的话,假如房价和租金均保持不变,租金也必须能够跑赢贷款利率才行。所以,一般国际上所认为的合理的租售比本质上是一个与贷款利率挂钩的指标。

以上海为例,现行贷款利率差不多算是6%吧(新政前后有高有低),那么按照这套租金跑赢贷款利率的逻辑,合理的售租比应该是多少呢?粗算一下,就是差不多200个月。

那么,上海有多少房子的售租比能达到200呢?

我们搜集了上海4月份的37000余套住房的租金数据和34000余套住房的房价数据,并按照小区(约12000个)进行了匹配,将每一个小区的租售比汇总到了每一平方公里的城市空间当中,并以200个月为分界值制作出下图:
&lt;img src=”https://pic1.zhimg.com/dea82966bdca9fc3e579ec43c303cb3c_b.jpg&#8221; data-rawwidth=”405″ data-rawheight=”405″ class=”content_image” width=”405″&gt;
是的,你没有看错,上图中的红点表示了售租比高于200个月的栅格空间,而白点则表示了售租比在200个月以下的栅格空间。也就是说,现阶段上海几乎没有什么所有地区的房价租金是能跑赢房贷的。

真是痛(hao)心(bu)疾(yi)首(wai)的结果啊。

不要紧,痛定思痛,再来看一下,上海的售租比到底是一个什么水平呢?我们将所有小区的租售比数值进行了排序,求出了其中位数值:

522个月。

什么概念?假设我25岁研究生一毕业,就立刻全款买了一套房,然后放出去收租,那么,在我约69岁时,这44年来陆陆续续所收的租金总数就可以达到了25岁时买房所付的钱啦。(而且还不考虑什么净现值折算之类的)。

好开心啊。才44年,竟然没有超过房屋的70年产权期呢。

高兴归高兴,我们由这些数据暂时可以得到以下两个结论:

1、在不考虑房产增值的情况下,上海绝大多数地方的房子的房租收入都跑不赢当下的商业贷款利率的。如果房价不持续上涨的话,即使以市场价出租,也是买一个月亏一个月,亏的程度不同而已;

2,如果仅靠租金收入的话,上海全市平均回收投资需要522个月,折算下来,只有约2.3%的收益。而这种格局的维持,必须有赖于购房者对上海的房价上升的持续预期。也就是说,在上海,投资房产绝不是利率收益,而是预期收益。

那么大家不禁要问了,参考国际惯例不是200到300个月么,那522个月的上海,仅靠预期收益,其房价是否有泡沫呢?

答案是:我不关心。

是的,即使租售比能够在某种程度上代表房产潜在的泡沫程度,这对于像我这样的一般购房者而言也毫无意义。为什么?很简单,买房是刚需啊。对于刚需购房者而言,他们需要做出的权衡并不是买不买房;而是怎么买一个泡沫小、风险低、收益预期高的房子。因此,我并不关心全上海的售租比包含多少绝对意义上的泡沫概念。我关心的问题是:

上海具体哪些房子的相对意义上的资产泡沫小一些?

我们先以户型分类,可以看到下图:
&lt;img src=”https://pic3.zhimg.com/32f59abba1b4259c668a0a9c67ddfd4a_b.jpg&#8221; data-rawwidth=”504″ data-rawheight=”360″ class=”origin_image zh-lightbox-thumb” width=”504″ data-original=”https://pic3.zhimg.com/32f59abba1b4259c668a0a9c67ddfd4a_r.jpg”&gt;
总体而言,售租比随着套型的增大而增大。其中一室户的租售比最低,中位数值为455个月,低于上海的全市值522个月,相对比较健康。而四室以上的豪宅则达到了590个月。

毫无疑问,这个结果令只买得起一室户的我十分欣喜(是的,这个分析毫无必要)。

那么,接下来的问题是,哪些区域售租比较低呢?

在看租售比的空间分布前,我们先研究一下房价和房租的空间分布。看下图。
&lt;img src=”https://pic2.zhimg.com/d8faa6fd13ed3242e6d89f462ec37e85_b.jpg&#8221; data-rawwidth=”841″ data-rawheight=”414″ class=”origin_image zh-lightbox-thumb” width=”841″ data-original=”https://pic2.zhimg.com/d8faa6fd13ed3242e6d89f462ec37e85_r.jpg”&gt;

左图是上海全市房价的空间分布,右图是上海房租的空间分布,可以发现,两者均表现为明显的向心性的圈层特征,而且分布的模式也基本一致。 左图是上海全市房价的空间分布,右图是上海房租的空间分布,可以发现,两者均表现为明显的向心性的圈层特征,而且分布的模式也基本一致。

那么租售比呢?再看下图。
&lt;img src=”https://pic1.zhimg.com/008a014936c064f026bcaf9a2f7ccb0c_b.jpg&#8221; data-rawwidth=”414″ data-rawheight=”414″ class=”content_image” width=”414″&gt; 毫无疑问,既然房价和租金在空间上表现为同质的圈层模式,那么作为两者相除的结果,售租比自然抹去了向心性的圈层分布特征,呈现出相对均质的扁平化分布特征,基本上看不出什么明显的特征。 毫无疑问,既然房价和租金在空间上表现为同质的圈层模式,那么作为两者相除的结果,售租比自然抹去了向心性的圈层分布特征,呈现出相对均质的扁平化分布特征,基本上看不出什么明显的特征。

那么,在这张混乱斑驳的图纸下面,到底隐藏着哪些因素影响了售租比呢?

理论上说,在一个完全理性的房产市场上,租金更多体现功能性,因此,售租比应该与每个地块轨道交通可达性、是否学区房、就业密度、以及高学历人口比例、人口密度等空间因素有关。
现实当中呢?是否如此?我们将这些因素分别代入到租售比模型当中,弄出一堆枯燥的统计学数字之后,结果出来了。请看下图:
&lt;img src=”https://pic2.zhimg.com/ca220dbbfe9d58e42f93482c7abaaecd_b.jpg&#8221; data-rawwidth=”163″ data-rawheight=”145″ class=”content_image” width=”163″&gt;
这张表是什么意思?简单一句话来解释吧:在上海全市层面,无论是学区房、轨交、就业密度还是人口,上述因素与售租比的关联均不显著

这是什么结论?难道这些经典理论中谈到的空间因素都不影响房屋租售比?这不科学啊!

别着急,我们的研究精神是百折不挠的。既然结果不显著,那么必然是某种变量没有被控制住嘛。让我们找到它。会不会是空间距离的关系呢?

于是,我们又将每一个空间栅格的售租比按照距市中心的距离排序,制作出了下面这张散点图:
&lt;img src=”https://pic4.zhimg.com/fafda18cd57fee62776927b491ceea67_b.jpg&#8221; data-rawwidth=”583″ data-rawheight=”363″ class=”origin_image zh-lightbox-thumb” width=”583″ data-original=”https://pic4.zhimg.com/fafda18cd57fee62776927b491ceea67_r.jpg”&gt;
在上图中,一个规律隐约地浮现出来:租售比的数值虽然并不随着空间距离增大或衰减,但其数值的离散程度却和空间距离有关。简单来说:

售租比越远离市中心越离散,越靠近市中心则越收敛。

其分界线大约是在20到30公里处,差不多就是上海中心城区和郊区的分野。是的,上海的租售比格局就是呈现这样一种“中心城区——郊区”分化特征的。

在获得这个认识后,我们再将轨交、学区、人口、就业等要素分为中心城区和郊区两个区间,分别代入到租售比模型中,便可以得到下表:
&lt;img src=”https://pic1.zhimg.com/6f719405b1b0b7e2c410622d6e8a16d8_b.jpg&#8221; data-rawwidth=”402″ data-rawheight=”217″ class=”content_image” width=”402″&gt;
注:* p < 0.05 ** p < 0.01

一句话解释一下吧:

中心城区的餐饮价格就业岗位密度产业结构这三个指标与房屋售租比有显著的相关性。总体来说,但在中心城区内部,人少岗位多、生产性服务业比例高、餐饮价格高的地方售租比会更低。但是这种关系在郊区并不成立。

这一结果说明了什么呢?

简单来说,中心城区的房产市场对空间因素的响应更加敏锐,而郊区则迟钝的多。这在某种程度上暗示着,在上海的郊区房产市场上,租金市场和住房市场可能是不重合的。

从理论上看,对于上海这个超大型城市,租金市场往往是本地化的,更注重房屋的功能性,因此就近的就业密度、产业结构、餐饮价格等等与之有紧密关联;但是,住房市场却是全市(国)的,包含了很强的投资性,而对于投资性购房者而言,他们看中的并非是租金收入而是预期收益,因而其选购房屋和就近的设施、就业密度、产业结构、餐饮价格等等的关联度就会较弱。

我们将这一理论假设回应到现实的结果中,就可以得出这样一个结论:

中心城区的房屋售租比的离散程度低,对空间因素的响应也更合理,说明该地区租房市场更成熟,房屋价格中包含的功能性价值也更强;而郊区的房产市场离散程度高,对空间因素无响应,说明该地区租房市场发育较弱,而房屋价格中包含的功能性也较弱,相应地更依赖投资性(或者叫预期性)价值。

在一栋房子所包含的价格中,究竟是功能性价值更安全,还是投资性(预期性)价值更安全呢?这个答案不言而喻了吧。

写到这里,我默默地在朋友圈里翻了一遍,发现在郊区买房的朋友其实不少。不止是我,大概每个漂在魔都的人都有那么几个在郊区置业的朋友、亲戚、或者同事吧。那些年,连夜排队、摇号购房的狂热景象刺激了很多买不起市中心的房子,但工资又没有房子涨的快的白领们。他们有些人选择在郊区买了房,也许目的并不是居住,而是在一轮风起云涌的大泡沫开始翻滚的时候,以正常人的理性选择来买一个泡沫而已。

那么现在呢?房价进入滞涨时代,他们是选择回归郊区的居住,还是卖掉郊区的房子然后努力置换到离工作岗位更近的市中心?我身边更多的案例往往是后者。

事实上,我并不知道上海的房地产市场是不是泡沫,这个问题需要更多的数据和更深入的探讨。我只知道,无论它是不是,我们这些漂在魔都的人也都会奋不顾身地去买一个泡沫。问题更多在于:

你是希望选择一个可能会涨得更大的泡沫,还选择一个破了之后不会溅到自己一身一脸的泡沫呢?

换个问题可能就会是,你要选择郊区,还是市区呢?

我想这是一个属于每一个人的自己的选择。

哦对了,很多北京的朋友总是向我咨询帝都的问题。说实在的,首都的问题高深莫测,一直无法摸到门径。但今天简单看了一眼,根据今年四月份的数据,帝都的全市售租比中位数是555个月,比上海还要多33个月。唉,上海总是赶不上北京啊,魔都加油吧,请把泡泡吹得更大一些。

Categories: life is fun

面对泡沫,该持有资产还是持有货币?

September 20, 2016 Leave a comment

面对泡沫,该持有资产还是持有货币?

2016-07-06 21财闻汇

前言

显然,因错失太多机会,中国经济已经步入到了一个骑虎难下的困难境地,繁华背后是风声鹤唳,摆在政府面前的三个最大问题就是:资产价格过高、人民币估值过高、债务负担过重!每一个问题爆发,都能引发系统性的危机!都是政府不愿意看到的!也是百姓不愿意面对的!政府会怎么做?我们该怎么办?

作者:米公子,来源:米筐投资(ID:mikuangtouzi) 授权21财闻汇发布

1、三大泡沫之资产泡沫

20多年以来,中国经济模式一直都是以政府主导投资驱动为引擎的经济模式,在以投资、出口、消费三架马车的模型中,如今能主要关注的只有投资了,谈投资,主要的也就只有房地产经济了,所以,当下在中国谈资产价格,主要就是指房价。

北京近10年的房价变化↓↓↓

深圳近10年的房价变化↓↓↓

合肥近10年房价变化↓↓↓

兰州近10年房价变化↓↓↓

郑州数据较全,我们来看近15年郑州房价变化↓↓↓

可以看出,在近几年,房价涨幅加快,这是中国资产价格的基本面。

来看均价在3万以上的区排行↓↓↓

动则均价5万以上的小区比比皆是,已经成了全球最贵的区域。

中国房价TOP10城市和全球典型城市房价对比↓↓↓

显然,如果你说中国的房价还不够高,我就无语了。对于中国房价的泡沫问题,已经根本不需要去争论,这已经是危害到了国计民生的问题,已经是全球公认的问题。、

如果政府要去除资产泡沫,会发生什么负能量的事情?

1、去资产泡沫,直接说就是要降房价

2、降房价,则触动的是地方政府、开发商、购房者、银行四方的核心利益

3、房价降20%,首付20%的购房者则可能抛弃已购房产

4、房价降,土地价格就要降,地方政府的贷款、融资平台、地方债务怎么办?

5、房价降,对于买涨不买跌的中国大众来说,房地产市场会立即降温,开发商欠银行的钱怎么办?

6、房价跌,势必会引发债务产业链上的大面积债务违约,购房者不还贷、开发商还不上钱、地方政府卖不了地还不了钱,最终,银行坏账大面积产生。

7、中国特色的维权开始,购房者堵售楼部要求退房,处理不好就是群体事件。

如果政府要去除资产泡沫,会发生什么正能量的事情?

1、楼市降温,钱去哪里?会不会倒逼入实体经济?

2、如果政府能给企业家信心,一个中长期的信心,在中长周期内是坚决的去除资产泡沫,扶持实体经济的话,大量资金会转向实体经济。

3、只有民营经济的心转向了实体经济、只有钱流向了实体经济,中国的经济才有未来和希望,才能彻底解决当下的大多数经济问题。

4、理论上,这是最好的处理危机的方式。当然,阵痛是必须要有的,而且很痛,要为以前的不理性付出代价,这也是日本模式。地产经济不死,实体经济必然难活,因为在现在的中国,地产就是金融,金融就是地产,这个现状不改变,金融就起不到为实体经济服务的作用!

如果继续保资产,让资产泡沫继续,会发生什么?

1、对中国实体经济是致命摧毁,中国仅有的一点实体经济也会被摧毁。

2、对民众信心的严重伤害,虽然房价高涨不跌,但百姓也不是傻子,自然知道不合理,全国恐慌情绪会蔓延。

3、中国经济结构性调整的周期继续后延,中国经济进一步下滑。

4、像董潘所说,未来北京房价80万/平,这也是有可能的。

2、三大泡沫之人民币泡沫

什么是M2、GDP、通货膨胀、CPI?

M0就是社会上的现金,

M1就是M0+企业的活期存款,

M2就是M1+全国的定期存款。

如果把国家比作一个超市,M2的增长也就是货币总量的增长,GDP的增长可以简单看作是整个超市内货物数量增长。货物的增长速度跟不上钱的增长速度,货少钱多,货就会涨价。货涨价的幅度就是CPI的涨幅。

M2是最能体现信贷情况、判断经济基本面的一个数据。

中国15年以来的M2变化↓↓↓

我们的M2数据在过去15年膨胀了10倍!

中国与美国M2变化↓↓↓

可以看出,美国M2数据在过去十多年是平稳上升,没有剧烈变化,但中国的M2自2008年开始加速上升,在2009年超过美国,并继续保持高昂的姿态在上升,截止2015年底,中国的M2数值已经是美国的1.813倍!

中国与美国M2同比增速比较↓↓↓

如图,我们的M2扩张数据在过去10多年间,一直远超美国!

中国与世界四大经济体的M2与GDP数据比较↓↓↓

可以看出,目前中国的货币可以出去买下整个美国和多半个欧盟,到2016年底,我们就可以买下整个美国和整个欧盟了!

中国目前的M2增速是13%左右,全球M2增速是7%左右,照此速度不变、人民币不贬值的话,不出10年,中国可以买下全世界!当然,这是理论上,你问问你自己,这可能吗?这背后的问题有多大?如果你是上帝,你会怎么想?怎么做?

所以,人民币贬值,已经是全球公认的事实,只是贬值速度、何时贬值的问题。

如果人民币直接大幅贬值,会发生什么负能量的事情?

1、国内的资金恐慌,争相跑出中国寻求安全的庇护所,中国外汇储备必将很快耗干,人民币贬值就变得不可遏制。

2、如果中国强行管制,违背的就是全球经济公约和一系列合作协议要求,人民币国际化的步伐直接停止,国际指责如何应对?

3、主权债务问题也会发生,主权评级也会下调,对中国在国际形象影响较大。

4、人民币贬值后,我们大量对外依存的进口商品(如大豆、石油、矿石、农产品、精密仪器、药品 等)将成本大大提升,势必加重国内人民负担,提高国内生活成本,造成输入性的通货膨胀!

5、人民币贬值,出国旅游、海外投资就降温了,影响的是企业或有钱人。

6、人民币贬值,外汇出逃时,通常政府都会加息来对冲,反过来,加息会加重危机中的国内经济,加重企业负担和债务负担,处理不当,也会引发连锁危机。

如果人民币直接大幅贬值,会发生什么正能量的事情?

1、人民币贬值影响最多的是有钱人,是老板,是外企,是外资,是热钱,这些人毕竟是少数。

2、基本上,老百姓不会闹事,因为,对于没有大多数没有存款的老百姓来说,只要房价不跌,抱着房子睡觉最安心,那怕人民币贬值80%呢,和百姓没啥关系。

3、对出口企业利好,可以改变近几年出口贸易一直不振的现状。

4、对国家和政府最好的是,基本上不会有群体事件发生。

如果保人民币,不贬值,会发生什么?

1、在全球公认的估值过高之下,大多数的钱会选择趁高位离开中国,要不出去购买资产,要不出去寻求安全。

2、在钱逐步离开中国之时,外汇耗干之时,人民币不想贬值也要贬值。

3、目前人民币民以每月400-500亿的速度外流,不出意外,2018年中,外汇储备就会耗干。都没外汇储备了,还说不贬值?打脸吗?

4、亲,也许你们也只有两年的时间,两年后,想换外汇,也没有了。

3、三大泡沫之债务泡沫

不容忽视的债务数据:

1、中国企业债务已经占到了GDP的1.9倍

2、地方政府债务已经占到了GDP的50%,达30多万亿

3、法兴银行在一份研报中称,中国银行业不良资产贷款率达15%左右

4、企业债务(包括国企)违约状况已经接连到来

如图,信贷在扩张,但增速在下降↓↓↓

20年以来,我们一直得以生存的投资式经济发展模式,突然行不通了!突然走不动了!信贷在扩张,经济却没有增长,这是很可怕的事情,从去年的股灾、今年的房灾、以及中间发生的螺纹钢事件,以及未来可能发生的农产品动荡事件,都与此有关,因为,M2在扩张,钱太多,却无处可去,就流向可炒作的资源,所到之处,无不造成重大动荡和伤害。

深层次影响的就是整个中国企业界的投资信心↓↓↓

我们看到,从2016年初开始,民间投资信心锐减,这是很可怕的事情。

这个情绪的蔓延,很可怕,最终导致的就是大面积的债务违约,就是经济危机。

一张100元的钞票,我相信你,这就是100块钱,我不再相信你时,这就是一张废纸。

债务泡沫根本上还是资产泡沫的延伸

1、过去10年以来的房价上涨,就是一直靠债务扩张来维持的,房价涨、地价涨、信贷扩张、债务扩大。

2、债务泡沫破裂会影响并刺破资产泡沫,资产泡沫破裂也会影响并刺破债务泡沫,两者是相互依存的骨肉兄弟。

3、而债务大面积违约,最终会导致,经济危机,会形成群体事件,这是国家和政府不愿意看到的。

4、为什么房价和汇率不可兼得?

如果想保房价?

就是让所有人都认为房价还要上涨,于是购房者继续买、开发商继续拿地,不管是因为恐慌还是因为期待,反正就是认为房价还要涨,怎么玩?

就只能靠继续信贷扩张、继续增加M2投放、给开发商和地方政府继续加杠杆、继续借新还旧维持房价上涨,钱越来越多,钱继续往房地产市场上涌,泡沫继续拱,大家争相购买,房价自然就降不下来,地价也是一路涨,资产价格一路升,如同你在2016年上半年看到的一样。

在此情况之下,国内实体经济肯定是继续下滑,消费也是不振的,国内的钱会越来越多,M2余额越来越大,远超世界平均水平,越来越多的人对未来充满恐慌,人民币预期估值肯定就会再被下调,加重人民币贬值压力。

如果想保汇率?

想保汇率,就要遏制资金外流,如何不让资金外流?就是让钱自己知道,出不出去差别不大,比如国内资产已经贬值了,钱出去还不如在中国呢,反正国内资产已经贬值这么低了,出去再回来也赚不到钱,还不如在国内呆着看那个企业顶不住资产贬值带来的压力要破产,抄底收购优质资产更重要,其实就是要增加钱呆在国内的预期,减小钱出去之后的预期。

钱不再外流了,汇率自然也就保住了。

所以,保房价、保汇率是两条不一样的经济思路,不可兼得,不可同行!政府只能选择一条路去走!

5、政府会怎么做?

政府会怎么做,也就是选择东京泡沫破裂模式还是莫斯科泡沫破裂模式的区别。

日本模式:刺破资产泡沫

日本房地产也是在1985-1990经历了疯狂的泡沫式增长,最终,日本选择的是去除资产泡沫的解决方式,日本房价下降50%,但日元和美元汇率变化不大,最终,也教育了整个日本,从此20多年,日本房价再也没有起来过,所有的企业都在乖乖的从事着以前的实体制造业。

当然,那次经济危机也给日本经济造成了重伤,房价下跌下的债务危机全面爆发,购房者跳楼、开发商破产、企业破产、银行破产。。。。那些在高位接盘的购房者不得不面对现实,用余生来偿还高额的房贷。

而,很多日本企业,又不得不出售很多的国外资产,回国救灾。

好的是,伤害了日本人民,也最终挽救了日本经济。

莫斯科模式:保资产、弃汇率

缘于乌克兰事件,2014年,世界原油价格开始暴跌,从年初的100美元跌至年底的53美元,以美国为首的西方国家集团对俄罗斯实施了一系列经济制裁,并且不断加码,严重干扰了俄罗斯的金融形势乃至实体经济的发展,不仅中断了俄罗斯在西方的融资通道,而且还促使俄罗斯国内资本(包括外来投资和境内资本)大量外逃,外汇需求猛增,卢布遭遇集中抛售。

2014年上半年1美元还可以兑换35卢布,到12月中旬的时候不但腰斩过半,还曾下探1美元兑换80卢布的历史低位,贬值幅度超过50%。2014年12月15日卢布曾一夜暴跌13%,创近16年来最大单日跌幅。

为应对外汇锐减,数次加息后,基准利率从5.5%提高到17%,提高幅度高达惊人的209%。如此频繁地调整基准利率,并且提高幅度如此之大,利率绝对值如此之高,均为同期世界各经济体所罕见,也是俄罗斯本国自1998年金融危机以来的第一次。

货币贬值通常与通货膨胀伴随而行。据俄官方公布的数据,俄罗斯2015年1月通胀率达到15%,创7年新高。2015年俄罗斯食品价格涨幅达14.3%,通胀率达12.9%,在全球主要经济体中居第三位。

卢布贬值》加息》国内严重通胀,这是俄罗斯经济危机的发展轨迹,而在莫斯科,以卢布计价的房价,没有跌。

中国会怎么选择?

1、国家稳定是最大的根本,所以,从理性上分析,因为80%以上的人除了房子就没有存款,也没有什么国际视野和全球视野,只要房子不贬值,搂着房价就不闹事,管你人民币在国际上贬不贬呢,关我毛事?而我也不买进口东西也不出国旅游,贬就贬呗,于我何干?而维护社会稳定是最大的原则,所以,会选择国内保资产不贬值,在国际上牺牲人民币,让人民币贬值。

2、这是我们的判断,但让人民币贬值牺牲的是金字塔上层精英阶会的利益,而目前的绝大多数权力又还在他们手上,他们会愿意选择牺牲自己利益吗?这是一个利益博弈的过程。

3、但,在大是大非面前,我想,大势不可违。中国要选择的,俄罗斯模式是大概率事件。

4、在保资产价格、弃汇率的大趋势面前,人民币国内贬值也是大概率事件,未来北京房价涨到15万/平以上也是大概率事件,未来郑州涨到1.5-2万/平以上也是大概率事件,我知道很多人不愿意听到这句话,也不愿意看到这样的情况,其实我也一样,但这就是现实,不得不面对的现实。

5、在弃外汇的政策前提之下,不会走目前这样温水煮青蛙的慢跌模式,这样会增加恐慌情绪、加速资金外流,让问题累积加重,政府可能会选择快速贬值、然后企稳的模式,比如:在某一天突然政策性贬值10-20%,然后通过媒体、政策集中释放信息,告诉大家:贬值到位了,都不用跑了,跑也没啥意思了,目前的中国更安全。

6、所以,在汇率快速断崖式贬值之前,看到的人请不要犹豫、要快速行动,能帮到一个是一个。如果你愿意相信并认同,记得转给你的朋友!目前美联储6月不打算加息,我们还有时间!

6、我们该怎么办?

如果,我们的预判准确,我们该怎么应对?建议如下:

1、在海外有账户的,可以把部分存款兑换成美元汇到海外,这是最佳的选择,只要到了海外就是自由了,然后想买房、买土地就随便了,但首先是要汇出去,而且要快。而且时间已经不多了,管制会越来越严格。以后待事态稳定,再汇回来也不晚。

2、在海外没有账户的,也可以考虑在国内兑换一部分美金,但也不建议买太多,因为只能是持有,不能增值,也不能作别的投资。换成现金放家里也不是个事儿,把美元存在银行也还会受到管制,不让你用你也没办法。

3、可以考虑在国内购买人民币黄金资产,比如人民币黄金ETF等,记得,一定是人民币黄金,当人民币贬值时,人民币黄金一定会涨,但现在人民币黄金已经在涨的路上了,最好的入场时机(2015年下半年)已经过去了,但为时还不算太晚。

4、不懂外汇、也不懂黄金的,建议在核心城市、成熟区域购买房子,不要去购买郊区房,但这一条只能算是中下策吧,虽然我们判断房价不会跌,核心城市房价还要继续涨,政府会在国内保资产,在国际上牺牲人民币,但毕竟政府也不是万能的,如果到时控制不好,国内恐慌时,也不好说,但整体上,这是相对安全靠谱的。比如2015年的股灾,虽然这事过去了,但当时过程中政府的束手无策、笨拙应对也是很明显的,而且,危机越大、问题越深,政府会越来越无策。

5、没有了。

适当的核心城市成熟区域房产持有+适当的人民币黄金持有+适当的家庭资产海外储备=是当下最佳的对冲选择!

考虑到国内高通涨的预期,在个人能力范围之内,能贷款就贷款,然后配置成上述资产。

记住要多元化配置,不要把资产都放一个蓝子里!

结语:

有人会说,把人民币和房价全圈在国内,那岂不是严重的通货膨胀吗?这不一样会造成社会动荡吗?当然,我知道的,只是,这些事又是靠后的事,问题是,当下的这两大难题,在资产泡沫和人民币泡沫面前,政府有得选择吗?

民众、企业都已经很恐慌了,只能二选一,刺破一个,稳定人心,没有别的选择。这是关键。

Categories: life is fun

为什么Uber宣布从Postgres切换到MySQL?


为什么Uber宣布从Postgres切换到MySQL?

2016-07-29 Evan Klitzke 高可用架构

导读:近期 Uber 宣布将数据库从 Postgres 迁移到 MySQL,在多个技术社区中引起了轩然大波,通过本文我们来详细了解 Uber 做出以上决策背后的原因。

介绍

Uber 的早期架构是由 Python 编写一个单体后端应用程序,使用 Postgres 作为数据持久化。后来 Uber 架构经历一系列显著改变,朝着微服务架构和新的数据平台发展。具体而言,在许多以前使用的 Postgres 的场景,现在更多的使用构建在 MySQL 之上的 schemaless 存储系统(小编:Uber的数据中间件)。在本文中,将探讨一些我们发现的 Postgres 的弊端,并解释我们切换 schemaless 和其他后端服务到 MySQL 数据库的原因。

Postgres 架构概述

我们遇到的大量 Postgres 限制如下:

  • 效率低下的写入架构
  • 低效的数据复制
  • 表损坏的问题
  • 糟糕的 MVCC 从库支持
  • 难以升级到新的版本

我们将在所有这些限制,首先通过分析 Postgres 如何组织在磁盘上的表和索引进行分析,特别是比较与 MySQL 使用 InnoDB 存储相同数据的实现方式。需要注意的是,我们在这里提出的分析主要是基于我们有些老的 Postgres 9.2 版本系列的经验。但据我们所知,本文中讨论的 PG 内部架构,并没有显著在新的 Postgres 版本中改变,就如在 9.2 版的磁盘数据设计,也没有比 Postgres 的 8.3 版(10 年前的版本)有什么显著变化。

磁盘数据格式

关系数据库必须执行一些关键任务:

  • 提供插入/更新/删除功能
  • 进行 schema 更改的能力
  • 实现多版本并发控制 (MVCC)机制,使不同的连接分别有他们各自的数据的事务视图

考虑如何将上述这些功能组合在一起工作,是数据库设计时的重要考虑部分。

Postgres 的核心设计之一是不变的(immutable)行数据。这些不变的行在 Postgres 中称为“tuple”。Tuple 在 Postgres 内部实现中由 CTID 来唯一标识 。一个 CTID 代表 tuple 在磁盘上的位置(即物理磁盘偏移)。多个 ctid 可以潜在描述一个单列(例如,当用于 MVCC 目的,或存在的行的多个版本时,行的旧版本尚未被 autovacuum 回收处理)。有组织的 tuple 的集合形成表。表本身具有的索引,通常被组织为 B 树数据结构,映射索引字段到 CTID 的负载。

通常,这些 ctids 对用户透明,但知道他们是如何工作,可以帮助您了解 Postgres 在磁盘上的数据结构。要查看某行当前 CTID,可以在查询的时候显式加上 “CTID”:

为了解释布局的细节,让我们考虑一个简单的用户表的例子。对于每个用户,我们有一个自动递增的用户 ID 的主键,还有用户的名字和姓氏,以及用户的出生年份。我们还定义了用户的全名复合二级索引(姓和名),并在用户的出生年份加上另一个二级索引。创建这样一个表 DDL 可能是这样的:

注意这个定义中的三个索引:主键索引加上两个二级索引。

对于本文中的例子,我们看下表的数据,它由一个选择有影响力的历史数学家开始:

如上所述,每行中隐含有独特的,不透明 CTID。因此,我们可以这样理解表的内部结构:

主键索引,它映射 ID 与 ctids,是这样定义的:

B 树被用在 id 字段上,B 树中的每个节点上保存了 CTID 值。注意,在这种情况下,在 B 树的字段的顺序,刚好与表中顺序相同,这是由于使用自动递增的 id 的缘故,但这并不一定需要是这种情况。

二级索引看起来相似;主要的区别是字段存储顺序不同,因为 B 树,必须按字典顺序组织。姓名索引(first,last)按字母表的顺序排列:


同样,birth_year 聚簇索引按升序排列,就像这样:

正如你所看到的,在这两种情况下,在各自的二级索引 CTID 字段本身并不是有序的,不象第一个自动递增的主键的情况。

假设我们需要更新此表中的记录。举例来说,假设要更新 al-Khwārizmī’ 的出生年份到 770 CE。正如前面提到的,行的 tuple 是不可变的。因此,要更新记录,需要添加一个新的  tuple。这种新的 tuple 有一个新的不透明 CTID,我们称之为 I。Postgres 需要能够从旧的 tuple D 处找到新的 I。在内部,Postgres 存储每个 tuple 中的版本字段,以及指向前一 tuple 的 ctid 指针(如果有)。因此,该表的新结构如下:

只要 al-Khwārizmī 的两个版本存在,索引则必须维护两行的记录。为简单起见,我们省略了主键索引并显示只有在这里的二级索引,它是这样的:


我们将旧版本标识成红色,将新版标识成绿色。在此之下,Postgres 使用另一个字段来保存该行版本,以确定哪一个 tuple 是最新的。这个新增的字段允许数据库确定事务看到的是那一个行的 tuple。


在 Postgres,主索引和二级索引都指向磁盘上的 tuple 偏移。当一个 tuple 的位置变化,各项索引都必须更新。

复制

当我们插入数据到表中,如果启用了流复制机制,Postgres 将会对数据进行复制,处于崩溃恢复的目的,数据库启用了预写日志 (WAL)并使用它来实现两阶段提交(2PC)。即使不启用复制的情况下,数据库也必须保留 WAL ,因为 WAL 提供了 ACID 的原子性(Atomicity)及持久性(Durability)能力。

我们可以通过如下场景来更好的理解 WAL,如果数据库遇到突然断电时意外崩溃,WAL 就提供了磁盘上表与索引更新变化的一个账本。当 Postgres 的守护程序再次启动后,就会对比账本上的记录与磁盘上的实际数据是否一致。如果帐本包含未在磁盘上的体现的数据,则可以利用 WAL 的记录来修正磁盘上的数据。

另外一方面,Postgres 也利用 WAL 将其在主从之间发送来实现流复制功能。每个从库复制数据与上述崩溃恢复的过程类似。流复制与实际崩溃恢复之间的唯一区别是,在恢复数据过程中是否能对外提供数据访问服务。

由于 WAL 实际上是为崩溃恢复目的而设计,它包含在物理磁盘的低级别更新的信息。WAL 记录的内容是在行 tuple 和它们的磁盘偏移量(即一行 ctids) 的实际磁盘上的代表级别。如果暂停一个 Postgres 主库,从库数据完全赶上后,在从库的实际磁盘上的内容完全匹配主库。因此,像工具 rsync 都可以恢复一个同步失败的从库。

Postgres 上述设计的大坑

Postgres 的上述设计给 Uber 在 PG 的使用上,导致了效率低下和其他很多问题。

1. 写放大(Write Amplification)

在 Postgres 设计的第一个问题是已知的写入放大 。

通常的写入放大是指一种问题数据写入,比如在 SSD 盘上,一个小逻辑更新(例如,写几个字节)转换到物理层后,成为一个更大的更昂贵的更新。

同样的问题也出现在 Postgres,在上面的例子,当我们做出的小逻辑更新,比如修改 al-Khwārizmī 的出生年份时,我们不得不执行至少四个物理的更新:

  1. 在表空间中写入新行的 tuple;
  2. 为新的 tuple 更新主键索引;
  3. 为新的 tuple 更新姓名索引 (first, last) ;
  4. 更新 birth_year 索引,为新的 tuple 添加一条记录;

事实上,这四步更新仅为了反映一个到主表的写操作;并且每个这些写入也同样需要在 WAL 得到体现,所以在磁盘上写入的总数目甚至比 4 步更大。

值得一提的是这里更新 2 和 3。当我们更新了 al-Khwārizmī 的出生年份,我们实际上并没有改变他的主键,我们也没有改变他的名字和姓氏。然而,这些索引仍必须与创建在数据库中的行记录了新的行的 tuple 的更新。对于具有大量二级索引的表,这些多余的步骤可能会导致巨大的低效。举例来说,如果我们有一个表上定义了十几个二级索引,更新一个字段,仅由一个单一的索引覆盖必须传播到所有的 12 项索引,以反映新行的 CTID。

2. 复制

因为复制发生在磁盘的变化上,因此写入放大问题自然会转化为复制层的放大。一个小的逻辑记录,如“更改出生年份为 CTID D 到 770”,WAL 会将上述描写的 4 步从网络上同步到从库,因此写入放大问题也等同一个复制放大问题,从而 Postgres 的复制数据流很快变得非常冗长,可能会占用大量的带宽。

在 Postgres 的复制发生一个数据中心内的情况下,复制带宽可能不是一个问题。现代网络设备和交换机可以处理大量的带宽,许多托管服务提供商提供免费或廉价的内部数据中心带宽。然而,当复制必须在不同数据中心之间发生的,问题都可以迅速升级

例如,Uber 原本使用的物理服务器在西海岸机房。为了灾难恢复的目的,我们在东海岸托管空间添加了一批服务器。在本设计中,我们西部数据中心作为主库,东海岸增加了一批服务器作为从库。

级联复制可以降低跨数据中心的带宽要求,只需要主库和一个从库之间同步一份数据所需的带宽和流量,即便在第二个数据中心配置了多个从库。然而,Postgres 的复制协议的详细程度,对于使用了大量二级索引的数据库,仍可能会导致数据的海量传输。采购跨国的带宽是昂贵的,即使有钱的土豪公司,也无法做到跨国的带宽和本地的带宽一样大。

这种带宽的问题也导致我们曾经在 WAL 归档方面出现过问题。除了发送所有从西海岸到东海岸的 WAL 更新,我们将所有的 WAL 记录归档到一个文件存储的 Web 云服务,这样当出现数据灾难情况时,可以从备份的 WAL 文件恢复。但是流量峰值时段,我们与存储网络服务的带宽根本无法跟上 WAL 写入的速度。

3. 数据损坏

在一次例行主数据库扩容的变更中,我们遇到了一个 Postgres 9.2 的 bug。从库的切换时间顺序执行不当,导致他们中的一些节点误传了一些 WAL 记录。因为这个 bug,应该被标记为无效的部分记录未标记成无效。

以下查询说明了这个 bug 如何影响我们的用户表:

SELECT * FROM users WHERE ID = 4;

此查询将返回两条记录:修改出生年份之前的老记录,再加上修改后的新记录。如果将 CTID 添加到 WHERE 列表中,我们将看到返回记录中存在不同的 CTID 记录,正如大家所预料的,返回了两个不同行的 tuple。

这个问题是有几个原因非常伤脑筋。首先,我们不能轻易找出这个问题影响的行数。从数据库返回的结果重复,导致应用程序逻辑在很多情况下会失败。我们最终使用防守编程语句来检测已知有这个问题表的情况。因为 bug 影响所有服务器,损坏的行在不同的服务器节点上可能是不同的,也就是说,在一个从库行 X 可能是坏的,Y 是好的,但对另一个从库,用行 X 可能是好的,Y 行可能是坏。事实上,我们并不确定数据损坏的从库节点数量,以及主库是否也存在数据损坏。

虽然我们知道,问题只是出现在每个数据库的少量几行,但我们还是非常担心,因为 Postgres 复制机制发生在物理层,任何小的错误格式有可能会导致彻底损坏我们的数据库索引。B 树的一个重要方面是,它们必须定期重新平衡 ,并且这些重新平衡操作可以完全改变树的结构作为子树被移到新的磁盘上的位置。如果错误数据被移动,这可能会导致树的大部分地区变得完全无效。

最后,我们追踪到了实际的 bug,并用它来确定新的 master 不存在任何损坏行。然后再把 master 的快照同步到所有从库上去,这是一个艰苦的体力活的过程(小编:看到美帝的 DBA 也这么苦逼心理终于平衡一点了),因为我们每次只能从在线的池子里面拿出有限几台来操作。

虽然我们遇到的这个 bug 仅影响 Postgres 9.2 的某些版本,而且目前已经修复了很久。但是,我们仍然发现这类令人担忧的 bug 可以再次发生。可能任意一个新的 Postgres 版本,它会带着这种致命类型的 bug,而且由于其复制的不合理的设计,这个问题一旦出现,就会立即蔓延到集群中所有复制链的数据库上。

4. 从库无 MVCC

Postgres 没有真正的从库 MVCC 支持。在从库任何时刻应用 WAL 更新,都会导致他们与主库物理结构完全一致。这样的设计也给 Uber 带来了一个问题。

为了支持 MVCC,Postgres 需要保留行的旧版本。如果流复制的从库正在执行一个事务,所有的更新操作将会在事务期间被阻塞。在这种情况下,Postgres 将会暂停 WAL 的线程,直到该事务结束。但如果该事务需要消耗相当长的时间,将会产生潜在的问题,Postgres 在这种情况下设定了超时:如果一个事务阻塞了 WAL 进程一段时间,Postgres 将会 kill 这个事务。

这样的设计意味着从库会定期的滞后于主库,而且也很容易写出代码,导致事务被 kill。这个问题可能不会很明显被发现。例如,假设一个开发人员有一个收据通过电子邮件发送给用户一些代码。这取决于它是如何写的,代码可能隐含有一个的保持打开,直到邮件发送完毕后,再关闭的一个数据库事务。虽然它总是不好的形式,让你的代码举行公开的数据库事务,同时执行无关的阻塞 I / O,但现实情况是,大多数工程师都不是数据库专家,可能并不总是理解这个问题,特别是使用掩盖了低级别的细节的 ORM 的事务。(小编:美帝程序员代码习惯跟咱们也很类似)

Postgres 的升级

因为复制记录在物理层面工作,这导致不能在不同的 Postgres GA 版本之间进行复制。运行的 Postgres 9.3 主数据库无法复制数据到 Postgres 9.2 的从库上,也无法在运行 9.2 的主数据库复制数据到 Postgres 9.3 的从库上。

我们按照以下这些步骤,从一个 Postgres 的 GA 版本升级到另一个:

  • 关闭主数据库。
  • 在主库上运行 pg_upgrade 命令,这是更新主库数据的命令 。在一个大的数据库上,这很容易需要几个小时的时间,执行期间不能够提供任何访问服务。
  • 再次启动主库。
  • 创建主库的新快照,这一步完全复制一份主库的所有数据,因此对于大型数据库,它也需要几个小时的时间。
  • 清除所有从库上的数据,将从主库导出的快照恢复到所有从库。
  • 把每个从库恢复到原先的复制层次结构。等待从库追上主库的最新的更新数据。

我们使用上述方法将 Postgres 9.1 成功升级到 Postgres 9.2。然而,这个过程花了太多时间,我们不能接受这个过程再来一次。到 Postgres 9.3 出来时,Uber 的增长导致我们的数据大幅增长,所以升级时间将会更加漫长。出于这个原因,我们的 Postgres 的实例一直运行 Postgres 9.2 到今天,尽管当前的 Postgres GA 版本是 9.5

如果你正在运行 Postgres 9.4 或更高版本,你可以使用类似 pglogical,它实现了 Postgres 的一个逻辑复制层。使用 pglogical,可以在不同的 Postgres 版本之间复制数据,这意味着升级比如从 9.4 到 9.5,不会产生显著的停机时间。但这个工具的能力依然存疑,因为它没有集成到 Postgres 主干,另外对于老版本的用户,pglogical 仍然不能支持。

MySQL 架构概述

为了更进一步解释的 Postgres 的局限性,我们了解为什么 MySQL 是 Uber 新存储工程 Schemaless 的底层存储 。在许多情况下,我们发现 MySQL 更有利于我们的使用场景。为了了解这些差异,我们考察了 MySQL 的架构,并与 Postgres 进行对比。我们特别分析 MySQL 和 InnoDB 存储引擎如何一同工作。Innodb 不仅在 Uber 大量使用,它也是世界上使用最广泛的 MySQL 存储引擎。

 

InnoDB 的磁盘数据结构

与 Postgres 一样,InnoDB 支持如 MVCC 和可变数据这样的高级特性。详细讨论 InnoDB 的磁盘数据格式超出了本文的范围;在这里,我们将重点放在从 Postgres 的主要区别上。

 

最重要的架构区别在于 Postgres 的索引记录直接映射到磁盘上的位置时,InnoDB 保持二级结构。而不是拿着一个指向磁盘上的行位置(如 CTID 在 Postgres),InnoDB 的第二个索引记录持有一个指向主键值。因此,在 MySQL 中的二级索引与相关联的主键索引键,是如下所示:

为了执行上的(first, last)索引查找,我们实际上需要做两查找。第一次查找表,找到记录的主键。一旦找到主键,则根据主键找到记录在磁盘上的位置。

这种设计意味着 InnoDB 对 Postgres 在做非主键查找时有小小的劣势,因为 MySQL 要做两次索引查找,但是 Postgres 只用做一次。然后因为数据是标准化的,行更新的时候只需要更新相应的索引记录。

而且 InnoDB 通常在相同的行更新数据,如果旧事务因为 MVCC 的 MySQL 从库而需要引用一行,老数据将进入一个特殊的区域,称为回滚段。

如果我们更新 al-Khwārizmī 的出生年份,我们看会发生什么。如果有足够的空间,数据库会直接更新 ID 为 4 的行(更新出生年份不需要额外的空间,因为年份是定长的 int)。出生年份这一列上的索引同时也会被更新。这一行的老版本被复制到回滚段。主键索引不需要更新,同样姓名索引也不需要更新。如果在这个表上有大量索引,数据库需要更新包含了 birth_year 的索引。因此,我们并不需要更新 signup_date,last_login_time 这些索引,而 Postgres 则必须全更新一遍。

这样的设计也使得 vocuum 和压缩效率更高。所有需要 vocuum 的数据都在回滚段内。相比之下,Postgres 的自动清理过程中必须做全表扫描,以确定删除的行。

 

MySQL 使用额外的间接层:二级索引记录指向主索引记录,而主索引本身包含在磁盘上的排的位置。如果一个行偏移的变化,只有主索引需要更新。

复制

MySQL 支持多个不同的复制模式:

  • 语句级别的复制:复制 SQL语句(例如,它会从字面上直译复制的语句,如:更新用户 SET birth_year = 770 WHERE ID = 4 )
  • 行级别的复制:复制所有变化的行记录
  • 混合复制:混合这两种模式

这些模式都各有利弊。基于语句的复制通常最为紧凑,但可能需要从库来支持昂贵的语句来更新少量数据。在另一方面,基于行的复制,如同 Postgres 的 WAL 复制,是更详细,但会导致对从库数据更可控,并且更新从库数据更高效。

在 MySQL 中,只有主索引有一个指向行的磁盘上的指针。这个对于复制来说很重要。MySQL 的复制流只需要包含有关逻辑更新行的信息。复制更新如“更改行的时间戳 x 从 T_ 1 至 T_ 2 ”,从库自动根据需要更新相关的索引。

相比之下,Postgres 的复制流包含物理变化,如“在磁盘偏移8382491,写字节XYZ。” 在 Postgres 里,每一次磁盘物理改变都需要被记录到 WAL 里。很小的逻辑变化(如更新时间戳)会引起许多磁盘上的改变:Postgres 必须插入新的 tuple,并更新所有索引指向新的 tuple。因此许多变化将被写入 WAL。这种设计的差异意味着 MySQL 复制二进制日志是显著比 PostgreSQL 的 WAL 流更紧凑。

复制如何工作也会影响从库的 MVCC。由于 MySQL 的复制流使用逻辑的更新,从库可以有真正的 MVCC 语义; 因此,读库查询不会阻塞复制流。相比之下,Postgres 的 WAL 流包含物理磁盘上的变化,使得 Postgres 的从库无法应用复制更新从而与查询相冲突,所以 PG 复制不能实现 MVCC。

MySQL 的复制架构意味着,bug 也许会导致表损坏,但不太可能导致灾难性的失败。复制发生在逻辑层,所以像一个重新平衡 B tree 这样的操作不会导致索引损坏。一个典型的 MySQL 复制问题是一个语句被跳过(或较少一点的情况,重复执行)的情况下。这可能会导致数据丢失或无效,但不会导致数据库出现灾难问题。

最后,MySQL 的复制架构使得它可以在 MySQL 不同版本之间进行复制。MySQL 只在复制格式改变的时候才增加版本号,这对 MySQL 来说很不常见。MySQL 的逻辑复制格式也意味着,在磁盘上的变化在存储引擎层不影响复制格式。做一个 MySQL 升级的典型方法是在一个时间来更新应用到一个从库,一旦你更新所有从库,你可以把它提为新的 master。这个操作几乎是 0 宕机的,这样也能保证 MySQL 能及时得到更新。

其他 MySQL 设计优势

到目前为止,我们集中于 Postgres 和 MySQL 在磁盘上的架构。MySQL 的架构导致性能比 Postgres 有显著优势。

缓冲池设计

首先,两个数据库缓冲池的工作方式不同。Postgres 用作缓存的内存比起内存的机器上的内存总数小很多。为了提高性能,Postgres 允许内核通过自动缓存最近访问的磁盘数据的页面缓存。举例来说,我们最大的 Postgres 的节点有 768G 可用内存,但只有大约 25G 的内存实际上是被 Postgres 的 RSS 内存使用,这让 700 多 GB 的可用内存留给 Linux 的页面缓存。

这种设计的问题是,相比访问 RSS 内存,操作系统的页面缓存访问数据实际上开销更大。从磁盘查找数据,Postgres 执行 lseek 和 read 系统调用来定位数据。这些系统调用的招致上下文切换,这比从主存储器访问数据更昂贵。事实上,Postgres 在这方面完全没有优化:Postgres 没有利用的 pread(2)系统调用,pread 会合并 seed + read 操作成一个单一的系统调用。

相比之下,InnoDB 存储引擎实现了自己的 LRUs 算法,它叫做 InnoDB 的缓冲池。这在逻辑上类似于 Linux 的页面缓存,但在用户空间实现的,因此也显著比 Postgres 设计复杂,InnoDB 缓冲池的设计有一些巨大的优势:

  • 使得它可以实现一个自定义的 LRU 设计。例如,它可以检测到病态的访问模式,并且阻止这种模式给缓冲池带来太大的破坏。
  • 它导致更少的上下文切换。通过 InnoDB 缓冲池访问的数据不需要任何用户/内核上下文切换。最坏的情况下的行为是一个的出现 TLB miss,但是可以通过使用 huag page 来搞定。

 

连接处理

MySQL 的实现是对每个连接生成一个线程,相对来说开销较低;每个线程拥有堆栈空间的一些内存开销,再加上堆上分配用于连接特定的缓冲区一些内存。对 MySQL 来说扩展到 10,000 左右的并发连接不是罕见的事情,实事上我们现在的 MySQL 接近这个连接数。

Postgres 使用的是每连接一个进程的设计。这很明显会比每连接每线程的设计开销更大。启动一个新的进程比一个新的线程会占用更多的内存。此外,线程之间进行通讯比进程之间 IPC 开销低很多。Postgres 9.2 使用系统V IPC为IPC原语,而不是使用线程模型中轻量级的 futexes,futex 的非竞争是常见的情况,比 System V IPC 速度更快,不需要进行上下文切换。

除了与 Postgres 的设计相关联的内存和 IPC 开销,即使有足够的可用内存可用,Postgres 对处理大连接数的支持依然非常差。我们已经碰到扩展 Postgres 几百个活动连接就碰到显著的问题的情况,在官方文档中也没有确切的说明原因,它强烈建议使用独立的连接池来保证大连接数。因此,使用 pgbouncer 做连接池基本可行。但是,在我们后端系统使用过程中发现有些 BUG,这会导致开启大量的原本不需要的活跃连接,这些 BUG 也已经造成好几次宕机。

结论

Postgres 在 Uber 初期运行的很好,但是 PG 很遗憾没能很好适应我们的数据增长。今天,我们有一些遗留的 Postgres 实例,但我们的数据库大部分已经迁移到 MySQL(通常使用我们的 Schemaless 中间层),在一些特殊的情况下,也使用 NoSQL 数据库如 Cassandra。我们对 MySQL 的使用非常满意,后续可能会在更多的博客文章中介绍其在 Uber 一些更先进的用途。

作者 Evan Klitzke 是 Uber 核心基础架构组资深软件工程师。他也是一个数据库爱好者,是 2012 年 9 月加入 Uber 的一名早鸟。

英文原文:

Why Uber Engineering Switched from Postgres to MySQL

Categories: life is fun