存档

‘杂谈’ 分类的存档

如何让别人发现自己的才能

2019年5月18日 1 条评论

再小的个体也有品牌,尤其是在网红经济下的今天,高曝光意味着高收入,在那些躺着挣钱的大V带动下,很多搞技术的人也开始希望自己能被更多人认知认可,提高知名度的同时能交一些朋友,互相学习提高技术水平,朋友多了路好走。

可选择的路子很多,比如常见的:

  • 写博客,现在坚持的人不多,搜索引擎被csdn、jianshu等网站霸屏
  • 写公众号,新注册的号没有留言功能,少了沟通手段
  • 写微博...

选择哪一条路或者同时都选,记录感受、写些总结的东西是我们自然而然的选择。我觉得比较最简单的路子是专注于某一个技术,写出一些列的文章,从基础功能、高级功能、进阶优化形成一个体系比较好,比东一下西一下会更容易坚持下去,而且容易吸引到铁粉支持,还能为自己的履历增加一个亮点。

如果不知道写什么好呢?可以借助百度搜索指数或者微信指数来辅助选出自己擅长同时又比较热门的方向,搜索指数高意味着关注的人多,容易找到人互相交流。

百度上更多人redis相关的主题
微信上关注spring主题的更多

我有两个主题在写,如果有感兴趣的可以一起写。

  • nginx主题:www.nginx.cn
  • redis主题:www.redis.com.cn

无论选择什么主题,最好提前写好提纲或者更新频率计划,这样才能长久的坚持下来。写任何主题都有江郎才尽的时候,从微信公众号就可以看出来,大V们动不动就让大家投票、分享,让你花钱入群讲故事,最后拿着你的故事去吸引新人入群,这种套路就如同淘金路上卖水的,你想着入群去找金子,其实人家是把水卖给了你,可发财的总是卖水。

最后,如果你不能合理规划时间,本着满足自己兴趣和理想的信念,大把时间投在这上面,我还是劝你先去赚钱,把工作做好,有了钱才能更好的谈兴趣。毕竟那些微博、微信大号明星是少数,多少怀揣着明星梦的人,最后只是为别人做嫁衣。

ps:品牌很重要,如果你没想好自己的品牌(合适的网名)前,建议不要开始写。不要像我一样没有品牌。欢迎大家关注我的公众号:程序员翻身,大家可以发消息给我交流,我有时间都会回复。

分类: 杂谈 标签:

TCP连接建立的三次握手与连接断开四次挥手

2017年9月4日 没有评论

TCP三次握手

一、什么是三次握手

三次握手(Three-way Handshake),是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。

二、三次握手的目的

三次握手的目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。客户端执行连接请求时。将触发三次握手。

三、三次握手过程

第一次握手:
客户端发送一个TCP的SYN标志位置1的包指明客户打算连接的服务器的端口,以及初始序号X,保存在包头的序列号(Sequence Number)字段里。
第二次握手:
服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1同时,将确认序号(Acknowledgement Number)设置为客户的ISN加1以.即X+1。
第三次握手.
客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1。如果正确则连接建立成功,客户端和服务器进入ESTABLISHED状态,完成三次握手,随后客户端与服务器之间可以开始传输数据了。把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1。

TCP四次挥手

一、什么是四次挥手

TCP的连接的拆除需要发送四个包,因此称为四次挥手(four-way handshake)。客户端或服务器均可主动发起挥手动作,任何一方执行close操作即可产生挥手操作。

二、四次挥手过程

第一次挥手:

客户端发送一个FIN,用来关闭客户端到服务器的数据传送,客户机进入FIN_WAIT_1状态。
第二次挥手:

服务器收到FIN后,发送一个ACK给客户端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),服务器进入CLOSE_WAIT状态。
第三次挥手:

服务器发送一个FIN,用来关闭服务器到客户端的数据传送,服务器进入LAST_ACK状态。
第四次挥手:

客户端收到FIN后,客户端进入TIME_WAIT状态,接着发送一个ACK给服务器,确认序号为收到序号+1,服务器进入CLOSED状态,完成四次挥手。

有限状态机FSM:Finite State Machine
1、CLOSED 没有任何连接状态
2、LISTEN 侦听状态,等待来自远方TCP端口的连接请求
3 、SYN-SENT 在发送连接请求后,等待对方确认
4、SYN-RECEIVED 在收到和发送一个连接请求后,等待对方确认
5、ESTABLISHED 代表传输连接建立,双方进入数据传送状态
6、FIN-WAIT-1 主动关闭,主机已发送关闭连接请求,等待对方确认
7 、FIN-WAIT-2 主动关闭,主机已收到对方关闭传输连接确认,等待对方发送关闭传输连接请求
8、 TIME-WAIT 完成双向传输连接关闭,等待所有分组消失
9、CLOSE-WAIT 被动关闭,收到对方发来的关闭连接请求,并已确认
10、LAST-ACK 被动关闭,等待最后一个关闭传输连接确认,并等待所有分组消失

11、CLOSING 双方同时尝试关闭传输连接,等待对方确认

附加问题:

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次挥手?
答:因为当服务器收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来回应的,SYN报文是用来同步的。但是关闭连接时,当服务器收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,”发送的FIN报文已经收到”。只有等到客户端所有的报文都发送完了,客户端才能发送FIN报文,因此不能一起发送。故需要四步挥手。
【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?
答:四个报文都发送完毕,客户端和服务器可以直接进入CLOSE状态了,但有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文,确保之前的数据不会丢失后再进入close状态。

原文:http://www.178linux.com/85976

分类: 杂谈 标签:

人社部解决夫妻两地攻略

2016年10月3日 3 条评论

Step1,到北京市公安局人口管理处开动迁证明
指南上提示要两次到北京市公安局人口管理处,一次是开准予迁入证明,一次是开户口迁入通知。实际上只用去一次,办事大厅就把两个证明都给了。在去之前,可以打一下指南上的电话,看一下自己的批文是不是已经抄送到北京市公安局。(北京,北京市公安局人口管理处TEL:87680101 成寿寺路甲19号)
去北京市公安局人口管理处需要带的资料:
1、  人事部批文原件;2、  双方户口卡原件;3、  双方身份证原件;4、  结婚证原件;
从北京市公安局人口管理处拿到两张卡片:
1、  给外地派出所的准予迁入证明 (第二联);2、  给北京落户派出所的户口迁入通知(第三联);
Step2,办理商调函
配偶在京单位出具接收函。拿着身份证、调令去开商调函(北京,全国人才 64229303 和平里东街12号)需要持下列资料:
1、  人事部批文原件;2、  结婚证;3、  北京市公安局出具的准予迁入证明;
Step3,办理档案调出
拿着商调函到人才市场开具行政介绍信、工资转移介绍信、档案转递单、转正定级表(不确定)。
Step4:(北京,北京市公安局人口管理处)
拿着行政介绍信、工资转移介绍信、档案转递单,调令、户口迁移证再次到北京市公安局人口管理处换取准迁证的第三联。(这些需要在40天内办完)。
Step5:(北京,全国人才)
拿着行政介绍信、工资转移介绍信、档案转递单,调令、户口迁移证到人才中心存档案;
Step6,到外地派出所办理户口迁移证
需要提供材料如下:
1、  人事部批文原件;2、  准予迁入证明;3、  配偶户口卡;4、  配偶身份证;
Step7,落户北京,办理北京身份证
需要提供材料如下:
1、  北京市公安局出具的准予迁入证明;2、  从外地派出所拿到的户口迁移证;

分类: 杂谈 标签:

防火墙断开数据库或者mq的连接造成的长时间重连等待

2016年6月8日 1 条评论

在测试环境经常会遇到服务失去响应,需要假死15分钟左右才能继续处理业务,每天早上来都需要重启服务才行,直觉感觉是防火墙有问题,不同于生产网络,测试网络之间的防火墙每隔固定时间最长24小时就会断开无数据流量的连接,但是应用端以为连接还是好的,需要探查较长的时间来确认连接是否可用。同时也发现有人在遇到这方面的解释,比较详细,post一下供参考。
最近生产上发现一个问题,刚开始,应用连接数据库正常,如果长时间没有业务估计半小时以上,再发起业务时,发现应用重连不上数据库,一直挂在重连那里,如果重启应用又能很快连上数据库(数据库是Oracle)。后来经数据库专家的同学看了后,发现我们的生产是RAC的,而客户端配置了TAF,导致在发生会话切换的时候,可能原来的连接没有释放好,影响了重连。把Oracle客户端的TAF关掉,重连的问题解决了。但又出现了一个很奇怪的现象,就是今天要说的重点问题,如果长时间没业务的时候还是断,而且断了后执行SQL要15分钟左右应用才能返回,这将导致应用在15分钟内不能服务,应用返回的错误是 ORA-03113: end-of-file on communication channel从这个错误看,应该是Oracle客户端返回了连接断开的错误,但是为什么要15分钟后才返回这个错误呢?

机器的网络情况如下:

应用主机A ----> FW1(防火墙1) ---->FW2(防火墙2) ----> 数据库主机(OracleDB)

后来经网络专家的同学判断,有可能是防火墙设置了会话超时,如果长时间一个会话上没有数据防火墙就会删除

会话,同时网上也有人遇到类似的情况:

26142928_6I68

我们做了类似的尝试,放开防火墙的时间限制后,问题没再出现。但是还有几个疑问没有解决:

1.为什么防火墙删除会话后,主机要等15分钟?

2.防火墙删除会话后,会不会通知主机(给主机发RST)?

早上和同事讨论,猜测是由于防火墙删除了会话,但主机并不知道,有数据库操作的时候,由Oracle客户端发起TCP请求,但由于防火墙找不到会话,丢弃了这些包(目前是不是丢还不清楚),导致了TCP不停地超时重发。

查看TCP/IP详解第一卷的21章节21.2节,都超时重发有这样的描述:

26142928_3a2X

这里提到9分钟,不过这本书写得比较早,猜测linux有所不一样,不过原理差不了太多,google了一下,

好像找到了15分钟的说法, 参考资料[1]中提到:

TCP_RTO_MIN=(HZ/5)=0.2s
TCP_RTO_MAX=(120*HZ)=120s
linear_backoff_thresh = ilog2(120*5)=ilog2(0x258)=9
timeout:未超过linear_backoff_thresh=9的部分按TCP_RTO_MIN 2的指数倍增长,超过的部分按TCP_RTO_MAX线性增长
tcp_time_stamp:当前时钟时间
例如数据发送阶段,sysctl_tcp_retries2=9,则timeout=1023*TCP_RTO_MIN=204.6s;sysctl_tcp_retries2=11时,timeout=1023*TCP_RTO_MIN+2*TCP_RTO_MAX=448.6s
默认sysctl_tcp_retries2=15,timeout=1023*TCP_RTO_MIN+6*TCP_RTO_MAX=920.6s,约15分钟

是根据RTO及一定的算法算出来的(具体的算法,可以看参考资料[3])

简单说,就是如果系统配置重传次数小于9的话,就是指数增长时间,如果大于9的话,就是最大超时时间。

而linux默认是15,所以刚好是15分钟,查看我们主机的配置,确认是15:

[steven@kfjk2 ~]$ cat /proc/sys/net/ipv4/tcp_retries2
15

现在还有一个问题没弄清楚,就是防火墙删除会话后,是否会通知主机?现在看起来应该是不会的,至少在主机上是没收到防火墙的RST,由于两个防火墙的两个厂商不一样,也有可能是一个吃掉另外一个的包也说不定。假如删除会话后,在原来的会话上来有包上来,是重建会话呢?还是直接把包丢弃?还是发RST呢?从目前主机的现象来看,猜测是:

防火墙删除会话后,不会通知主机也就是不会给主机发RST,当有新包上来,找不到连接,但不是S包的时候,直接丢弃,

导致主机用完了重发次数后,自己发RST后给应用报断开连接。

不过。。。以上的东东都是根据现象来猜测的,最有效的办法是捉出tcpdump包来看,但由于是生产不敢乱动,也先这样吧!

仅以此记,为避免以后踩坑,同时开发人员也要关心网络部署,当时我并没有考虑中间有两个防火墙。

来源http://m.oschina.net/blog/318965

分类: oracle, 杂谈 标签:

一致性哈希算法的实现

2016年5月29日 1 条评论

一致性哈希算法能够减少增减节点带来的memcache缓存失效带来的冲击。

下面是一个简单的java版实现算法,其中的哈希值算法没有实现,用HashFunction作为一个接口来提供自定义的hash值函数,大多数情况下我们可以使用md5。

circle代表有一个有序整型map,表示要缓存的对象所对应hash值。
创建ConsistentHash对象时会同时创建虚拟节点。每个复制节点都是实用对象名和后缀结合的hash值。
缓存对象分布在每一个map中的节点上。

分类: 杂谈 标签:

epoll入门实例

2016年4月10日 没有评论

epoll是目前进行服务器端编程的普遍选择,好处很多,这里不再赘述,本文主要描述如何在c语言中使用epoll的完整样例程序。
首先介绍用到的数据结构和三个api说明,然后通过编写一个打印所有输入到socket的字符输出到终端的服务器端的程序来完成整个例子。

epoll_event是用来对要监控的socket描述, 它包括epoll_data_t和要监控的事件类型的(一个__uint32_t类型的events)。epoll_data_t里的fd是用来存储要监控的文件描述符。

events 结构体中第一个参数支持的事件类型

– EPOLLIN,读事件

– EPOLLOUT,写事件

– EPOLLPRI,带外数据,与select的异常事件集合对应

– EPOLLRDHUP,TCP连接对端至少写写半关闭

– EPOLLERR,错误事件

– EPOLLET,设置事件为边沿触发

– EPOLLONESHOT,只触发一次,事件自动被删除

epoll在一个文件描述符上只能有一个事件,在一个描述符上添加多个事件,会产生EEXIST的错误。同样,删除epoll的事件,只需描述符就够了

使用epoll的三个api
头文件 /usr/include/sys/epoll.h
1. 生成一个epoll专用的文件描述符
如果调用成功返回0,不成功返回-1

epoll_create返回的是一个文件描述符,也就是说epoll是以特殊文件的方式体现给用户
__size提示操作系统,用户可能要使用多少个文件描述符,该参数已经废弃,填写一个大于0的正整数

2.用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
如果调用成功返回0,不成功返回-1

3.用于轮询I/O事件的发生,返回发生事件数

epoll的api使用方式
1.epoll_create 生成的epoll专用的文件描述符
2.使用epoll_ctl注册事件,修改事件,删除事件对应的文件描述符到epollfd指定的epoll内核事件表中
3.使用epoll_wait阻塞等待注册的文件描述符上可读事件的发生
4.当有新客户端的连接或者客户端的数据写入,返回需要处理的事件数目

epoll的两种模式

1. 水平触发(LT):使用此种模式,当数据可读的时候,epoll_wait()将会一直返回就绪事件。如果你没有处理完全部数据,并且再次在该epoll实例上调用epoll_wait()才监听描述符的时候,它将会再次返回就绪事件,因为有数据可读。ET只支持非阻塞socket。

2. 边缘触发(ET):使用此种模式,只能获取一次就绪通知,如果没有处理完全部数据,并且再次调用epoll_wait()的时候,它将会阻塞,因为就绪事件已经释放出来了。

ET的效能更高,但是对程序员的要求也更高。在ET模式下,我们必须一次干净而彻底地处理完所有事件。LT两种模式的socket都支持。

实例代码

1.创建并绑定服务器端socket
采用一种可移植的方式来生产socket,getaddrinfo返回对应的网卡信息,遍历对应的网络接口生成socket
成功返回socket文件描述符,失败返回-1

2.设置socket为非阻塞模式
通过在文件描述符上设置 O_NONBLOCK 表识来实现非阻塞socket

3.event 循环处理

main函数的流程是
1. create_and_bind创建服务器端的socket描述符
2. 设置描述符为非阻塞
3. 监听描述符
4. 创建epoll文件描述符efd
5. 使用边缘触发的方式添加sfd输入监听事件

最外层的while循环时主事件循环(event loop)。调用epoll_wait阻塞等待事件发生,当事件到达epoll_wait返回事件在事件参数中,一批epoll_event结构体。
epoll事件循环中epoll实例在建立新连接时候添加事件和当断开连接的时候删除事件。

当事件发生时,有如下几种方式
错误:当发生错误,或者不是可读事件通知时,简单关闭文件描述符,关闭文件描述符会自动从efd的监控集中删除。
新连接:当监听描述符可读时,表示有新的连接到达,accept()新连接,设置新连接描述符为非阻塞并添加到efd监控集中。
客户端数据:当任何一个客户端文件描述符可读,使用read()每次读区512字节循环读取。 因为我们需要读取当前所有可读区数据 ,当边缘触发的情况下不会再次通知可读。 读取到的数据调用write写到标准输出stdout (fd=1)。如果read(2)返回0,表示EOF并切可以关闭客户端连接。如果返回-1并且 errno设置为EAGAIN表示这个事件所有可读的数据读取完毕可以返回进入主事件循环。

就这样不断的循环,添加和删除文件描述符到efd的监控集中。
https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/

分类: 杂谈 标签:

分布式系统的数据一致性和处理顺序问题

2016年2月18日 4 条评论

现在先抛出问题,假设有一个主数据中心在北京M,然后有成都A,上海B两个地方数据中心,现在的问题是,假设成都上海各自的数据中心有记录变更,需要先同步到主数据中心,主数据中心更新完成之后,在把最新的数据分发到上海,成都的地方数据中心A,地方数据中心更新数据,保持和主数据中心一致性(数据库结构完全一致)。数据更新的消息是通过一台中心的MQ进行转发。

先把问题简单化处理,假设A增加一条记录Message_A,发送到M,B增加一条记录 MESSAGE_B发送到M,都是通过MQ服务器进行转发,那么M系统接收到条消息,增加两条数据,那么M在把增加的消息群发给A,B,A和B找到自己缺失的数据,更新数据库。这样就完成了一个数据的同步。

从正常情况下来看,都没有问题,逻辑完全合理,但是请考虑以下三个问题

1 如何保证A->M的消息,M一定接收到了,同样,如何保证M->A的消息,M一定接收到了

2 如果数据需要一致性更新,比如A发送了三条消息给M,M要么全部保存,要么全部不保存,不能够只保存其中的几条记录。我们假设更新的数据是一条条发送的。

3 假设同时A发送了多条更新请求,如何保证顺序性要求?

这两个问题就是分布式环境下数据一致性的问题

对于第一个问题,比较好解决,我们先看看一个tcp/ip协议链接建立的过程

我们的思路可以从这个上面出发,在简化一下,就一个请求,一个应答。

简单的通信模型是这样的

A->M : 你收到我的一条消息没有,消息的ID是12345

M->A: 我收到了你的一条消息数据,消息数据是ID;12345

这样就一个请求,一个应答,就完成了一次可靠性的传输。如果A一致没有收到M的应答,就不断的重试。这个时候M就必须保证幂等性。不能重复的处理消息。那么最极端的情况是,怎么也收不到M的应答,这个时候是系统故障。自己检查一下吧。

这么设计就要求,A在发送消息的时候持久化这个消息的数据内容,然后不断的重试,一旦接收到M的应答,就删除这条消息。同样,M端也是一样的。不要相信MQ的持久化机制,不是很靠谱的。

那么M给A发送消息也采取类似的原理就可以了。

下面在看看第二个问题,如何保持数据的一致性更新,这个还是可以参考TCP/IP的协议。

首先A发送一条消息给M:我要发送一批消息数据给你,批次号是10000,数据是5条。

M发送一条消息给A:ok,我准备好了,批次号是10000,发送方你A

接着A发送5条消息给M,消息ID分别为1,2,3,4,5 ,批次号是10000,

紧接着,A发送一个信息给M:我已经完成5小消息的发送,你要提交数据更新了

接下来可能发送两种情况

1 那么M发送消息给A:ok,我收到了5条消息,开始提交数据

2 那么M也可以发送给A:我收到了5条消息,但是还缺少,请你重新发送,那么A就继续发送,直到A收到M成功的应答。

整个过程相当复杂。这个也就是数据一旦分布了,带来最大的问题就是数据一致性的问题。这个成本非常高。

对于第三个问题,这个就比较复杂了

这个最核心的问题就是消息的顺序性,我们只能在每个消息发一个消息的序列号,但是还是没有最好解决这个问题的办法。因为消息接收方不知道顺序。因为即使给他了序列号,也没有办法告诉他,这个应该何时处理。最好的办法是在第二种方式的基础作为一个批次来更新。

这个只是以最简单的例子来说明一下分布式系统的要保证数据一致性是一件代价很大的事情。当然有的博主会说,这个何必这么复杂,直接数据库同步不就可以了。这个例子当然是没有问题的,万一这个几个库的模型都不一样,我发送消息要处理的事情不一样的。怎么办?

在上文,简单的介绍了分布式数据的同步问题,上面的问题比较抽象,在目前的互联网应用中还很少见,这次在通过一个比较常见的例子,让大家更深入的了解一下分布式系统设计中关于数据一致性的问题

这次我们拿我们经常使用的功能来考虑吧,最近网购比较热门,就以京东为例的,我们来看看京东的一个简单的购物流程

用户在京东上下了一个订单,发现自己在京东的账户里面有余额,然后使用余额支付,支付成功之后,订单状态修改为支付成功,然后通知仓库发货。假设订单系统,支付系统,仓库系统是三个独立的应用,是独立部署的,系统之间通过远程服务调用。

订单的有三个状态:I:初始 P:已支付 W:已出库,订单金额100, 会员帐户余额200

如果整个流程比较顺利,正常情况下,订单的状态会变为I->P->W,会员帐户余额100,订单出库。

但是如果流程不顺利了?考虑以下几种情况

1:订单系统调用支付系统支付订单,支付成功,但是返回给订单系统数据超时,订单还是I(初始状态),但是此时会员帐户余额100,会员肯定会马上找京东骂京东,为啥不给老子发货,我都付钱了

2:订单系统调用支付系统成功,状态也已经更新成功,但是通知仓库发货失败,这个时候订单是P(已支付)状态,此时会员帐户余额是100,但是仓库不会发货。会员也要骂京东。

3:订单系统调用支付系统成功,状态也已经更新成功,然后通知仓库发货,仓库告诉订单系统,没有货了。这个时候数据状态和第二种情况一样。

对于问题一,我们来分析一下解决方案,能想到的解决方案如下

1 假设调用支付系统支付订单的时候先不扣钱,订单状态更新完成之后,在通知支付系统你扣钱

如果采用这种设计方案,那么在同一时刻,这个用户,又支付了另外一笔订单,订单价格200,顺利完成了整个订单支付流程,由于当前订单的状态已经变成了支付成功,但是实际用户已经没有钱支付了,这笔订单的状态就不一致了。即使用户在同一个时刻没有进行另外的订单支付行为,通知支付系统扣钱这个动作也有可能完不成,因为也有可能失败,反而增加了系统的复杂性。

2 订单系统自动发起重试,多重试几次,例如三次,直到扣款成功为止。

这个看起来也是不错的考虑,但是和解决方案一样,解决不了问题,还会带来新的问题,假设订单系统第一次调用支付系统成功,但是没有办法收到应答,订单系统又发起调用,完了,重复支付,一次订单支付了200。

假设支付系统正在发布,你重试多少次都一样,都会失败。这个时候用户在等待,你怎么处理?

3 在第二种方案的基础上,我们先解决订单的重复支付行为,我们需要在支付系统上对订单号进行控制,一笔订单如果已经支付成功,不能在进行支付。返回重复支付标识。那么订单系统根据返回的标识,更新订单状态。

接下来解决重试问题,我们假设应用上重试三次,如果三次都失败,先返回给用户提示支付结果未知。假设这个时候用户重新发起支付,订单系统调用支付系统,发现订单已经支付,那么继续下面的流程。如果会员没有发起支付,系统定时(一分钟一次)去核对订单状态,如果发现已经被支付,则继续后续的流程。

这种方案,用户体验非常差,告诉用户支付结果未知,用户一定会骂你,你丫咋回事情,我明明支付了,你告诉我未知。假设告诉用户支付失败,万一实际是成功的咋办。你告诉用户支付成功,万一支付失败咋办。

4 第三种方案能够解决订单和支付数据的一致性问题,但是用户体验非常差。当然这种情况比较可能是少数,可以牺牲这一部分的用户体验,我们还有没有更好的解决方案,既能照顾用户体验,又能够保证资金的安全性。

我们再回来看看第一种方案,我们先不扣钱,但是有木有办法让这一部分钱不让用户使用,对了,我们先把这一部分钱冻结起来,订单系统先调用支付系统成功的时候,支付系统先不扣钱,而是先把钱冻结起来,不让用户给其他订单支付,然后等订单系统把订单状态更新为支付成功的时候,再通知支付系统,你扣钱吧,这个时候支付系统扣钱,完成后续的操作。

看起来这个方案不错,我们仔细在分析一下流程,这个方案还存在什么问题,假设订单系统在调用支付系统冻结的时候,支付系统冻结成功,但是订单系统超时,这个时候返回给用户,告知用户支付失败,如果用户再次支付这笔订单,那么由于支付系统进行控制,告诉订单系统冻结成功,订单系统更新状态,然后通知支付系统,扣钱吧。如果这个时候通知失败,木有问题,反正钱都已经是冻结的了,用户不能用,我只要定时扫描订单和支付状态,进行扣钱而已。

那么如果变态的用户重新拍下来一笔订单,100块钱,对新的订单进行支付,这个时候由于先前那一笔订单的钱被冻结了,这个时候用户余额剩余100,冻结100,发现可用的余额足够,那就直接在对用户扣钱。这个时候余额剩余0,冻结100。先前那一笔怎么办,一个办法就是定时扫描,发现订单状态是初始的话,就对用户的支付余额进行解冻处理。这个时候用户的余额变成100,订单数据和支付数据又一致了。假设原先用户余额只有100,被冻结了,用户重新下单,支付的时候就失败了啊,的确会发生这一种情况,所以要尽可能的保证在第一次订单结果不明确的情况,尽早解冻用户余额,比如10秒之内。但是不管如何快速,总有数据不一致的时刻,这个是没有办法避免的。

第二种情况和第三种情况如何处理,下次在分析吧。

由于互联网目前越来越强调分布式架构,如果是交易类系统,面临的将会是分布式事务上的挑战。当然目前有很多开源的分布式事务产品,例如java JPA,但是这种解决方案的成本是非常高的,而且实现起来非常复杂,效率也比较低下。对于极端的情况:例如发布,故障的时候都是没有办法保证强一致性的。

在上文主要介绍了数据分布的情况下保证一致性的情况,在第二篇文章里面,我这里提出了三个问题

1.订单系统调用支付系统支付订单,支付成功,但是返回给订单系统数据超时,订单还是I(初始状态),但是此时会员帐户余额100,会员肯定会马上找京东骂京东,为啥不给老子发货,我都付钱了

2.订单系统调用支付系统成功,状态也已经更新成功,但是通知仓库发货失败,这个时候订单是P(已支付)状态,此时会员帐户余额是100,但是仓库不会发货。会员也要骂京东。

3.订单系统调用支付系统成功,状态也已经更新成功,然后通知仓库发货,仓库告诉订单系统,没有货了。这个时候数据状态和第二种情况一样。

重点分析解决了第一个的问题以及相应的方案,发现在数据分布的环境下,很难绝对的保证数据一致性(任何一段区间),但是有办法通过一种补偿机制,最终保证数据的一致性。

在下面在分析一下第二个问题

订单系统调用支付系统成功,状态也已经更新成功,但是通知仓库发货失败,这个时候订单是P(已支付)状态,此时会员帐户余额是100,但是仓库不会发货。会员也要骂京东。

通过在上一篇文章里面分析过,这个相对来说是比较简单的,我可以采取重试机制,如果发现通知仓库发货失败,就一致重试,

这里面有两种方式:

1 异步方式:通过类似MQ(消息通知)的机制,这个是异步的通知

2 同步调用:类似于远程过程调用

对于同步的调用的方式,比较简单,我们能够及时获取结果,对于异步的通知,就必须采用请求,应答的方式进行,这一点在(关于分布式系统的数据一致性问题(一))里面有介绍。这里面就不再阐述。

来看看第三个问题

订单系统调用支付系统成功,状态也已经更新成功,然后通知仓库发货,仓库告诉订单系统,没有货了。这个时候数据状态和第二种情况一样。

我觉得这是一个很有意思的问题,我们还是考虑几种解决的方案

1 在会员下单的时刻,就告诉仓库,我要你把货物留下来,

2 在会员支付订单时候,在支付之前检查仓库有没有货,如果没有货,就告知会员木有货物了

3 如果会员支付成功,这个时候没有货了,就会退款给用户或者等待有货的时候在发货

正常情况,京东的仓库一般都是有货的,所以影响到的会员很少,但是在秒杀和营销的时候,这个时候就不一定了,我们考虑假设仓库有10台iphone

如果采用第一种方案,

1 在会员下单的时候,相当于库存就-1,那么用户恶意拍下来,没有去支付,就影响到了其他用户的购买。京东可以设置一个订单超时时间,如果这段时间内没有支付,就自动取消订单

2 在会员支付之前,检查仓库有货,这种方案了,对于用户体验不好,但是对于京东比较好,至少我东西都卖出去了。那些没有及时付款的用户,只能投诉了京东无故取消订单

3 第三种方案,这个方案体验更不好,而且用户感觉受到京东欺诈,但是对于京东来说,比第二种方案更有益,毕竟我还可以多卖出一点东西。

个人觉得,京东应该会采用第二种或者第三种方式来处理这类情况,我在微博上搜索了 “京东 无故取消订单”,发现果真和我预料的处理方式。不过至于这里的无故取消是不是技术上的原因我不知道,如果真的是技术上的原因,我觉得京东可以采用不同的处理方案。对于秒杀和促销商品,可以考虑第一种方案,大多数人都会直接付款,毕竟便宜啊,如果用户抢不到便宜的东西,抱怨当然很大了。这样可以照顾大多数用户的体验。对于一般的订单,可以采用第二种或者第三种方式,这种情况下,发生付款之后仓库没有货的情况会比较少,并且就算发生了,用户也会觉得无所谓,大不了退钱吗,这样就可以实现自己的利益最大化而最低程度的减少用户体验。

而铁道部在这个问题上,采用的是第一种方案,为什么和京东不一样,就是因为用户体验,如果用户把票都买了,你告诉我木有票了,旅客会杀人的。哈哈,不过铁道部不担心票卖不出去,第一种方案对他影响没有什么。

说了这么多,就是说 分布式环境下(数据分布)要任何时刻保证数据一致性是不可能的,只能采取妥协的方案来保证数据最终一致性。这个也就是著名的CAP定理。

在前面三篇文章中,介绍了关于分布式系统中数据一致性的问题,这一篇主要介绍CAP定理以及自己对CAP定理的了解。

CAP定理是2000年,由 Eric Brewer 提出来的

Brewer认为在分布式的环境下设计和部署系统时,有3个核心的需求,以一种特殊的关系存在。这里的分布式系统说的是在物理上分布的系统,比如我们常见的web系统。

这3个核心的需求是:Consistency,Availability和Partition Tolerance,赋予了该理论另外一个名字 - CAP。

Consistency:一致性,这个和数据库ACID的一致性类似,但这里关注的所有数据节点上的数据一致性和正确性,而数据库的ACID关注的是在在一个事务内,对数据的一些约束。

Availability:可用性,关注的在某个结点的数据是否可用,可以认为某一个节点的系统是否可用,通信故障除外。

Partition Tolerance:分区容忍性,是否可以对数据进行分区。这是考虑到性能和可伸缩性。

为什么不能完全保证这个三点了,个人觉得主要是因为一旦进行分区了,就说明了必须节点之间必须进行通信,涉及到通信,就无法确保在有限的时间内完成指定的行文,如果要求两个操作之间要完整的进行,因为涉及到通信,肯定存在某一个时刻只完成一部分的业务操作,在通信完成的这一段时间内,数据就是不一致性的。如果要求保证一致性,那么就必须在通信完成这一段时间内保护数据,使得任何访问这些数据的操作不可用。

如果想保证一致性和可用性,那么数据就不能够分区。一个简单的理解就是所有的数据就必须存放在一个数据库里面,不能进行数据库拆分。这个对于大数据量,高并发的互联网应用来说,是不可接受的。

我们可以拿一个简单的例子来说明:假设一个购物系统,卖家A和卖家B做了一笔交易100元,交易成功了,买家把钱给卖家。

这里面存在两张表的数据:Trade表Account表 ,涉及到三条数据Trade(100),Account A ,Account B

假设 trade表和account表在一个数据库,那么只需要使用数据库的事务,就可以保证一致性,同时不会影响可用性。但是随着交易量越来越大,我们可以考虑按照业务分库,把交易库和account库单独分开,这样就涉及到trade库和account库进行通信,也就是存在了分区,那么我们就不可能同时保证可用性和一致性。

我们假设初始状态

trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,I)

account(accountNo,balance) = account(A,300)

account(accountNo,balance) = account(B,10)

在理想情况下,我们期望的状态是

trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)

account(accountNo,balance) = account(A,200)

account(accountNo,balance) = account(B,110)

但是考虑到一些异常情况

假设在trade(20121001,S)更新完成之前,帐户A进行扣款之后,帐户A进行了另外一笔300款钱的交易,把钱消费了,那么就存在一个状态

trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)

account(accountNo,balance) = account(A,0)

account(accountNo,balance) = account(B,10)

产生了数据不一致的状态

由于这个涉及到资金上的问题,对资金要求比较高,我们必须保证一致性,那么怎么办,只能在进行trade(A,B,20121001)交易的时候,对于任何A的后续交易请求trade(A,X,X),必须等到A完成之后,才能够进行处理,也就是说在进行trade(A,B,20121001)的时候,Account(A)的数据是不可用的。

任何架构师在设计分布式的系统的时候,都必须在这三者之间进行取舍。首先就是是否选择分区,由于在一个数据分区内,根据数据库的ACID特性,是可以保证一致性的,不会存在可用性和一致性的问题,唯一需要考虑的就是性能问题。对于可用性和一致性,大多数应用就必须保证可用性,毕竟是互联网应用,牺牲了可用性,相当于间接的影响了用户体验,而唯一可以考虑就是一致性了。

牺牲一致性

对于牺牲一致性的情况最多的就是缓存和数据库的数据同步问题,我们把缓存看做一个数据分区节点,数据库看作另外一个节点,这两个节点之间的数据在任何时刻都无法保证一致性的。在web2.0这样的业务,开心网来举例子,访问一个用户的信息的时候,可以先访问缓存的数据,但是如果用户修改了自己的一些信息,首先修改的是数据库,然后在通知缓存进行更新,这段期间内就会导致的数据不一致,用户可能访问的是一个过期的缓存,而不是最新的数据。但是由于这些业务对一致性的要求比较高,不会带来太大的影响。

异常错误检测和补偿

还有一种牺牲一致性的方法就是通过一种错误补偿机制来进行,可以拿上面购物的例子来说,假设我们把业务逻辑顺序调整一下,先扣买家钱,然后更新交易状态,在把钱打给卖家

我们假设初始状态

account(accountNo,balance) = account(A,300)

account(accountNo,balance) = account(B,10)

trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,I)

那么有可能出现

account(accountNo,balance) = account(A,200)

trade(buyer,seller,tradeNo,status) = trade(A,B,20121001,S)

account(accountNo,balance) = account(B,10)

那么就出现了A扣款成功,交易状态也成功了,但是钱没有打给B,这个时候可以通过一个时候的异常恢复机制,把钱打给B,最终的情况保证了一致性,在一定时间内数据可能是不一致的,但是不会影响太大。

两阶段提交协议

当然,还有一种方式就是我另外一篇文章里面《X/Open DTP-分布式事务模型》里面说的,但是再第一阶段和第二阶段之间,数据也可不能是一致性的,也可能出现同样的情况导致异常。而且DTP的分布式事务模型 限制太多,例如必须有实现其功能的相关的容器支持,并且资源管理器也必须实现了XA规范。限制比较多。

国外有的架构师有两种方案去解决CAP的限制,但是也是比较适合特定的业务,而没有通用的解决方案,

探知分区->分区内操作->事后补偿

就是上面介绍的异常检测恢复机制,这种机制其实还是有限制,

首先对于分区检测操作,不同的业务涉及到的分区操作可能不一样

分区内操作限制:不同的业务对应的约束不一致

事后补偿:由于业务约束不一样,补偿方式也不一样。

所以这只能作为一种思想,不能做一个通用的解决方案

(转载)

分类: 杂谈 标签:

区分同步 异步 阻塞 非阻塞

2016年1月18日 没有评论

同步/异步
首先来解释同步和异步的概念,这两个概念与消息的通知机制有关.
举个例子,比如我去银行办理业务,可以自己去排队办理,也可以叫人代办,等他帮忙处理完了直接给我结果,对于要办理这个银行业务的人而言,自己去办理是同步方式,而别人代办完毕则是异步方式.区别在于,同步的方式下,操作者主动完成了这件事情.异步方式下,调用指令发出之后,操作马上就返回了,操作者并不能马上就知道结果了,而是等待所调用的异步过程(在这个例子中是帮忙代办的人)处理完毕之后,通过通知手段(在代码中通常是回调函数)来告诉操作者结果.
异步IO
在上图的异步IO模型中,应用程序调用完aio_read之后,不论是否有数据可读,这个操作都会马上返回,这个过程相当于这个例子中委托另一个人去帮忙代办银行业务的过程,当数据读完拷贝到用户内存之后,会发一个信号通知原进程告诉读数据操作已经完成(而不仅仅是有数据可读).

阻塞/非阻塞
接着解释阻塞/非阻塞的概念,这两个概念与程序处理事务时的状态有关.
同样是前面的例子,当真正执行办理业务的人去办理银行业务时,前面可能已经有人排队等候了.如果这个人一直从排队到办理完毕,中间都没有做过其他的事情,那么这个过程就是阻塞的,这个人当前只在做这么一件事情.
阻塞IO
在上图中,应用程序发起recvfrom操作之后,要等待数据拷贝成功才能返回,这一整个过程中,不能做其它的操作,这个就是典型的阻塞IO.

反之,如果这个人发现前面排队的人不少,于是选择了出去逛逛,过了一会再回来看看有没有轮到他的号被叫到,如果没有又继续出去逛过一阵再回来看看,如此以往,这个过程就是非阻塞的,因为处理这个事情的人,在这整个过程中,并没有做到除了这件事之外不能再做别的事情,他的做法是反复的过来尝试,如果没有完成就下一次再次尝试完成这件事情.
非阻塞IO
上图与前面阻塞IO图示的区别在于,当没有数据可读时,同样的recvfrom操作返回了错误码,表示当前没有可读数据,换言之,即使没有数据也不会一直让这个应用阻塞在这个调用上,这就是非阻塞IO.

到了这里,可以先简单的小结一下这两组概念了:

阻塞/非阻塞:区别在于完成一件事情时,是不是当事情还没有完成时,处理这件事情的人除此之外不能再做别的事情.
同步/异步:是自己去做这件事情,还是等别人做好了来通知你做好了,然后自己去拿结果.注意,这里说的是拿结果.如果只是别人告诉你可以做某事,然后自己去操作,这种情况下也是同步的操作,在后面多路复用I/O中会进行阐述.

可见,两组概念不是一个维度的概念.我们把需要办理银行业务的人称为A,把代办理的人称为B,那么在A委托B办理业务的情况下,假设A在交代B帮忙办事之后,A就去做别的事情了,那么A并不存在针对办理银行业务这件事情而言是阻塞还是非阻塞,办理事务时阻塞与否是针对真正需要办理这件事情的人,也就是这个例子里的B.

与多路复用I/O的联系
前几年写上一篇文章的时候,将多路复用I/O类的select/poll等和异步操作混为一谈,在这里需要特别做一些补充说明.在以前的说明中,就这个例子而言,我列举了一个情况,当去办理业务的人,需要排队时通常都会先去叫号拿到一个纸条上面写了号码,然后等待银行叫号,在那个例子里面,我将银行叫号比作select操作,把纸条比作向select注册的回调函数,一旦可以进行操作的条件满足,就会根据这个回调函数来通知办理人,然后办理人再去完成工作,因此select等多路复用操作是异步的行为.

上面那个例子,最大的错误在于,没有意识到,同步与异步的区别在于是不是要求办理者自己来完成,所有需要自己去完成操作的都是同步操作,不管是注册了一个回调(这里的叫号小纸条)等待别人回调你,还是自己一直阻塞等待.在上面的例子中,虽然对需要办理业务的人而言,通过叫号小纸条,他可以等待银行的办理通知,等待的同时可以去做点别的事情,比如看看手机什么的,但是只要可以办理该业务的条件满足,真正叫到了你的号可以办理业务时,办理者是需要自己去完成办理的.

换言之,在完成一件事情时,这里需要区分处理两种状态:一是这个事情是不是可以做了(条件满足的消息,如select告诉你某个文件描述符可读),一是完成了这件事情(如调用read/write完成IO操作).多路复用IO做的,是它可以记录下来有哪些人在等待消息的通知,在条件满足时负责通知办理者,而完成这件事情还是需要办理者自己去完成.只要是自己去完成的操作,都是同步的操作.

UNP的6.2节中,最后对异步/同步做的总结是最准确的了:

POSIX defines these two terms as follows:

A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes.
An asynchronous I/O operation does not cause the requesting process to be blocked.
Using these definitions, the first four I/O models—blocking, nonblocking, I/O multiplexing, and signal-driven I/O—are all synchronous because the actual I/O operation (recvfrom) blocks the process. Only the asynchronous I/O model matches the asynchronous I/O definition.

http://www.codedump.info/?p=515

分类: 杂谈 标签:

那些我印象深刻的建议和教诲

2015年12月26日 没有评论

看过博主很多篇文章,而且还经常忘了网址,很多观点深有感触,只是自己少了那份文字描述能力,转载过来共勉。

人的一生,当然有很多的时间去自己摸索和探究,做出自己的选择;其他人的教诲,很多时候并不会干涉选择,反而会让人少走弯路,更快捷抵达自己的目标。下面,我列了自己印象深刻的教诲(或者说“建议”),既是对各位的感谢,也希望通过分享让更多人受益。

技术是你的安身立命之本

这是大学时候中文系的王老师对我说的。当时我基本不怎么上计算机的专业课,晚自习看原版教材,白天在图书馆泡着,外加去中文系听课。对从小只接受过自然科学教育的人来说,不受约束阅读文史哲的魅力实在太大了,越看越入迷,加之当时网络管束很松,很容易在网上和大家聊得热血沸腾——只是,我从没有想过自己毕业了要干什么。

结果,又一次和王老师聊天时,他跟我说:“技术才是你的安身立命之本,文史哲只能当兴趣”。虽然我当时不理解这句话的真正含义,但还是照做了,又拨出很多时间学习计算机专业知识。当然,最终的理解还是王老师帮忙完成的。有一次上大课,他说:“面对人间的不义,作为知识分子我们当然有责任上阵。但是,上阵是有多种方式的。你们是希望赤膊上阵呢,还是披挂上阵?” 就在那一瞬间,我明白了“技术是安身立命之本”的含义,并受用至今。

要把目标设高一点

这还是大学老师的教诲。大四的时候在机房上机,我的程序很快写完了,就和授课的姜老师聊天。他问我找工作的事情,我当时看刘韧《知识英雄2.0》看得入迷(这本书我还是在老榕开的8848上买的呢),就说“我就想去外企当个程序员”。

我记得当时他的表情一愣,然后说:“我给你点建议吧,通常来说,你给自己设定的目标都是自己能到达的顶点,甚至都达不到。你现在只希望按部就班去外企当个程序员,很可能就只能去国内企业当个程序员,这有什么意思?年轻人,还是要把目标设高一点。”

后来或许我没有把目标设定那么高,但是我也不愿意给自己设定界限,所以走出了一条我从没想过的路,而且回头来看走得还不算坏。

功夫不服有心人,还是蠢?

大学毕业之后我想去北京工作,但当时我其实没有任何经验,也没有什么资源可以借助,其实并没有太多信心,压力也不小。

听说我要去北京,有个舅舅专程请我吃饭。他给我讲了个故事:有个人高考一心希望考上理想的大学,但是失利了。他不甘心,复读了再考,又失利了。这样反复了三四年,最后,他终于考上了。大家纷纷说:哎呀,真是功夫不负有心人。

听到这里,我还没明白他的意思。结果他看着我问:“如果这个人没考上,大家应该怎么说呢?” 我于是猜测:“继续鼓励,等着说功夫不负有心人?”

“错啦,其实很简单,大家就会说‘你看,这就是蠢嘛’”。说完他自顾自地笑了。我却要等好几年之后才能想明白,看官永远有评价的权利,但其实“功夫不负有心人”和“蠢”之间可能连窗户纸都没有,只看个人如何面对了。

多用Google吧

我工作的第一天,项目经理把我叫去说:给你们讲讲JUnit, SVN,Ant, JBuilder的用法,明天开始用。这四样东西我以前都没有接触过,第一反应就是在QQ上跟同学抱怨这家公司不人性,得到的答复却是“赶紧学,赚到了,我们这还不让用呢”,于是我硬着头皮全接了下来……

这就是我呆的第一家公司的“风范”,新的工具、框架都只扔一个名词出来,项目经理似乎也很不耐烦我去问东问西——当然真正去问的时候,他的态度还是比较好的。有一天下班的时候他看我还是愁眉不展地面对屏幕,就说了一句“别担心,多用Google吧”。

对当时的我来说,这就是救命稻草了。如果说之前因为放不下面子又找不到头绪在做“忍者神龟”,那天晚上我就在办公室疯狂地使用Google来搜索,到凌晨1点左右终于找到了头绪。窗外是漆黑的北京城,但我仿佛看到了黎明的曙光。从此,也染上了多用Google的“恶习”。

现在你们终于可以拿公司的钱做实验了

工作了几年之后,我时常困惑于公司要做的事情和自己想做的方向之间的差异,又担心自己的价值得不到提升,离开了公司就毫无优势。有天晚上我和霍炬(Virushuo)聊天,他说他毕业的时候,老师跟他们说了一句很重要的话“你们终于可以拿公司的钱做实验了”。要想提升自己的价值,不能满足于公司指派的任务,不能期望天上会掉馅饼来让自己增值,而应当把自己的工作环境视作资源场,努力去思考能从中收获什么。

其实我们在公司里,除去本职工作,是有大把的机会学习的,而且也不限于“拿公司的软硬件做实验”。比如思考行业会有什么发展并根据现实比对,观察每个职位的人都在做什么,做得好的同事有怎样的方法论,找外国同事聊天练习口语之类。这些机会你抓住了,就可以成长,没有抓住,也就白白浪费了。

大旗不倒,才有机会

我离开北京的时候,和昔日在抓虾网的老板老徐(徐易容)吃了一次饭。当时老徐已经在做美丽说了,但是刚刚开始,还有太多太多的不确定。席间我们谈了很多,也谈到一个人应该做什么。

老徐说:这个世界上的Skill是无穷无尽的,掌握不完的,我们不停地去掌握这些Skill,真的有成就感吗?不见得,还是要找到自己真正想做的事情。现在有一家上市公司请我去做技术VP,把技术都给管起来,我当然能做。但是我还是希望创业,如果我接了这个职位后来再创业,大家会怎么想?如果我不接受这个职位,抓虾失败了,我还是要创业,哪怕再失败,我都是在向外不停地传递“徐易容专注于创业”的信息,就像一杆大旗一直立在那里,然后才会有人才、资金、资源向我这里聚拢……

我后来时常惊讶于老徐的执着,他很早就想清楚了品牌这项事业是需要长时间经营的。“贪图蝇头小利”常常并不与道德挂钩,反而与毅力和魄力挂钩。

面对自己的弱点,不要躲

我离开北京之前找各路朋友吃了一圈饭,其中就有教我做菜的师傅曹勇。

本来,我们只是很随意地聊聊,回忆回忆发点感慨,到快吃完的时候他忽然正色跟我说:我做了这么多年的菜,有一点经验可以告诉你。很多人就会有意无意去逃避自己的弱点,或者变得很敏感,一旦别人提起来就容易多想,就容易激动,这样的人往往成不了大事。听我一句话,面对自己的弱点,不要躲。

我见的人越多,经历的越多,也就越觉得他说的有道理。“日三省吾身”的人或许对自己有什么弱点非常清楚,不这么做的人,大概多少都有些模糊的感觉。怎样放平心态对待自己的弱点,真是人生的一大考验。有些人采取鸵鸟政策,假装问题不存在;有些人一看苗头不对就转移,避开心虚;还有些人打肿脸充胖子,掩盖心虚。总之,都是在躲,都是不健康的应对。

真正健康的方式是什么?是努力戒除情绪,用客观的角度看待自己的弱点:这个问题真的存在吗?如果真的存在,它有多严重?我有没有办法去改进它?如果有,应该怎么做?如果没有,大概会遇到哪些后果,我是否准备好了面对?在其他人提到这些弱点的时候,我怎么判断他们是无意的还是有意的?是无意的要如何忽略?是有意的要如何面对?…… 必须承认,一开始面对这些问题确实会很难堪甚至难过,但是成长往往就是来自让自己难过,再努力克服难过的过程。

本文链接 那些我印象深刻的建议和教诲

分类: 杂谈 标签:

code kata是什么?

2015年12月5日 3 条评论

最近,我大量阅读了Steve Yegge的文章。其中有一篇叫“Practicing Programming”(练习编程),写成于2005年,读后令我惊讶不已:

与你所相信的恰恰相反,单纯地每天埋头于工作并不能算是真正意义上的锻炼——参加会议并不能锻炼你的人际交往能力;回复邮件并不能提高你的打字水平。你必须定期留出时间,集中锻炼,这样才能把事情做得更好。

我认识很多杰出的程序员——这是在亚马逊工作最好的额外“福利”之一。如果仔细观察他们,你会发现他们时时都在锻炼。他们已经很优秀了,但他们仍然不忘锻炼。他们锻炼的方法林林总总,而我在这篇文章中只会介绍其中的几种。

阅读全文...

分类: 杂谈 标签: