架构第1章

本文参考《极客时间》- 从0开始学架构

架构到底是什么?

架构和框架是什么关系?
  • 系统与子系统:系统是由一系列有关联,按特定规则组成的个体,并且产生新的能力,而系统与子系统则是观察的交角度不同
  • 模块与组件:模块是从逻辑角度去看待,而组件是从物理角度去看待
    (也可以说模块是业务维度上职责的划分,组件从技术角度)
  • 框架与架构:框架(比如mvc,mvp)是规范也是约束,可以理解为封闭性的话题,定义好,让别人如何去使用。而架构是一种结构,是一种开放性的话题,如何去设计组织架构,如何让架构更具有拓展性,减少沟通错误成本
架构的目的
  • 架构是为了应对软件系统复杂度而提出的一个解决方案。
  • 架构即(重要)决策。
    是在一个有约束的盒子里去求解或接近最合适的解。这个有约束的盒子是团队经验、成本、资源、进
    度、业务所处阶段等所编织、掺杂在一起的综合体(人,财,物,时间,事情等)。架构无优劣,但是存在恰当的架构用在合适的软件系统中,而这些就是决策的结果。
  • 需求驱动架构,架起分析与设计实现的桥梁。"跳出代码,总揽全局"
  • 架构与开发成本的关系。
    架构设计处于软件研制的前期,一方面,越是前期,如有问题,就能够越早发现,修改的代价也就越低;另外一方面,也意味着,软件实施后期若有架构上的修改,也需要付出更多的代价。
复杂度来源:高性能,高可用,高扩展

来源一:高性能
软件系统中高性能带来的复杂度主要体现的两方面,
一.单台计算机内部为了高性能带来的复杂度;
二.多台计算机集群为了高性能带来的复杂度

  • 单机的高性能,更多的落脚点是机器本身的性能,以及处理具体任务的方式,多进程或多线程,更合理的应用单机的性能;
  • 集群的高性能,即任务的分配和分解。分配是物理层面的,即哪些机器处理用户的请求;分解是业务层面的,即单个请求哪些业务子系统来处理。
    分配的难点:分配机器的性能,分配算法,与业务系统的连接,失败重试机制等等。
    分解难点在于业务切分的粒度把握,只能对业务与机器这两块理解恰到好处,才能做较好的切分。
  • 因此集群的高性能的基础是把握好单机器性能。

性能优化点思路总结起来还是两步走:先单机后集群,如多线程、协程等编程模型的使用,缓存的使用,最终都是为了更快完成一次请求服务

  • 如何衡量这个性能要求高还是不高呢?
    对于架构师来说,常见系统的性能量级需要烂熟于心,例如nginx负载均衡性能是3万左右,mc的读取性能5万左右,kafka号称百万级,zookeeper写入读取2万以上,http请求访问大概 在2万左右。
    具体的数值和机器配置以及测试案例有关,但大概的量级不会变化很大。
    如果是业务系统,由于业务复杂度差异很大,有的每秒500请求可能就是高性能了,因此需要针对业务进行性能测试,确立性能基线,方便后续架构设计做比较。
    ***当前,我们的系统实现高性能采用也仅仅微服务+redis+消息加其他,虽有不足,但在进步中。

来源二:高可用
高可用的定义:系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。

现实: 没有任何系统真的能做到“无间断”。不论是内部原因系统设计,还是外部自然灾害,都会导致间断。
在复杂的分布式系统中,每个服务都有99.99%的可能出现故障,YTX有80个应用也就是说有99.99%的80次方,也就是也就是99.2%的高可用,也就是说有0.8%的故障,那么一年有70个小时的故障。如果,阿里巴巴70个小时的故障,那就是损失惨重了。

如何做到高可用?

  • 核心思想:网站高可用的主要技术手段是服务与数据的冗余备份与失效转移。(分布式存储和分布式计算)
  • 同一服务组件部署在多台服务器上;
    数据存储在多台服务器上互相备份。出现问题,不影响系统的整体可用性,不导致数据丢失。
  • 从架构角度看可用性:当前网站系统多采用经典的分层模型,从上到下为:应用层、服务层与数据层。在部署架构上常采用应用和数据分离部署,应用会部署到不同服务器上,这些服务器被称为应用层的服务器;这些可复用的服务也会各自部署在不同服务器上,称为服务层的服务器;而各类数据库系统、文件柜等数据则部署在数据层的服务器。
  • 硬件故障方面引起不可用的技术解决措施:
    (1)应用服务器。集群对外提供服务(前提是这些服务需要设计为无状态,即应用服务器不保存业务的上下文信息,而仅根据每次请求提交的数据进行业务逻辑的操作响应),当均衡设备通过心跳检测手段检测到应用服务器不可用时,则将其从集群中移除,并将请求切换到其他可用的应用服务 上。
    (2)服务层服务器。这些服务器被应用层通过分布式服务框架(如Dubbo)访问,分布式服务框架可在应用层客户端程序中实现软件负载均衡,并通过服务注册中心提供服务的服务器进行心 跳检测,当发现有服务器不可用时,立即通知客户端程序修改服务列表,同时移除响应的服务器。
    (3)数据服务器。需要在数据写入时进行数据同步复制,将数据写入多台服务器上,实现数据冗 余备份;当数据服务器宕机时,应用程序将访问切换到有备份数据的服务器上。
    软件方面引起不可用的技术解决措施:通过软件开发过程进行质量保证。通过预发布验证、严格测试、灰度发布等手段,尽量减少上线服务的故障。

没有完美的高可用解决方案。而是减少或规避。规避某个问题的时候,一般会引发另一个问题,作出取舍。

***SpringCloud的hystrix的出现就是为了高可用
***高性能和高可用都通过增加更多机器达到目的,但本质上有区别的:高性能增加机器目的在于“扩展”处理性能;高可用增加机器目的在于“冗余”处理单元。

来源三:
可扩展性指系统为了应对将来需求变化而提供的一种扩展能力,当有新的需求出现时,系统不需要或者仅需要少量修改就可以支持,无须整个系统重构或者重建。
面向对象思想、设计模式都是为了解决可扩展性的而出现的方法与技术。

设计具备良好可扩展性的系统两个基本条件:
1.正确预测变化(业务维度,对业务深入理解,对业务的变化进行预测)
2.完美封装变化(技术维度,利用扩展性好的技术,实现对变化的封装)
在实际工作场景中的(实现良好的可扩展性)解决方案 :
(1)使用分布式服务(框架)构建可复用的业务平台。
(2)使用分布式消息队列降低业务模块间的耦合性。
(1)分布式服务框架 (如Dubbo)可以将业务逻辑实现和可复用组件服务分离开,通过接口降低子系统或模块间的耦合性。新增功能时,可以通过调用可复用的组件实现自身的业务逻辑,而对现有系统没有任何影响。可复用组件升级变更的时候,可以提供多版本服务对应用实现透明升级,对现有应用不会造成影响。
(2) 分布式消息队列 基于生产者-消费者编程模式,利用分布式消息队列(如RabbitMQ)将用户请求、业务请求作为消息发布者将事件构造成消息发布到消息队列,消息的订阅者作为消费者从消息队列中获取消息进 行处理。通过这种方式将消息生产和消息处理分离开来,可以透明地增加新的消息生产者任务或者新的消息消费者任务。

其他复杂性来源:
来源四.低成本
How:一般通过“创新”达到低成本的目标。
(1)引入新技术。主要复杂度在于需要去熟悉新技术,并且将新技术与已有技术结合;一般中小型公司基本采用该方式达到目标。
(2)开创一个全新技术领域。主要复杂度在于需要去创造全新的理念和技术,并且与旧技术相比,需要有质的飞跃,复杂度更高;一般大公司拥有更多的资源、技术实力会采用该方式来达到低成本的目标。
来源五.安全
安全是一个庞大而又复杂的技术领域,一旦出问题,对业务和企业形象影响非常大。
从技术的角度来讲
(1)功能安全-“防小偷”,减少系统潜在的缺陷,阻止黑客破坏行为;
(2)架构安全—“防强盗”,保护系统不受恶意访问和攻击,保护系统的重要数据不被窃取。由于是蓄意破坏系统,因此对影响也大得多。架构设计时需要特别关注架构安全。
How:
(1)功能安全。是一个逐步完善的过程,而且往往都是在问题出现后才能有针对性的提出解决方案,与编码实现有关。
(2)架构安全。传统企业主要通过防火墙实现不同区域的访问控
制,功能强大、性能一般,但是成本更高。互联网企业更多地是依靠运营商或者云服务商强大的带宽和流量清洗的能力,较少自己来设计和实现。
来源六.规模
What:规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。
(1)业务功能越来越多,调用逻辑越来越复杂;
(2)数据容量、类型、关联关系越来越多。
How:规模问题需要与高性能、高可用、高扩展、高伸缩性统一考虑。常采用“分而治之,各个击破”的方法策略。
来源七.可伸缩性
当前大型互联网网站需要面对大量用户高并发访问、存储更多数据、处理更高频次的用户交互。网站系统一般通过多种分布式技术将多台服务器组成集群对外提供服务。伸缩性一般是系统可以
根据需求和成本调整自身处理能力的一种能力。伸缩性常意味着系统可以通过低成本并能够快速改变自身的处理能力以满足更多用户访问、处理更多数据而不会对用户体验造成任何影响。
伸缩性度量指标包括
(1)处理更高并发;
(2)处理更多数据;
(3)处理更高频次的用户交互。
其复杂度体现在
(1)伸——增强系统在上述三个方面的处理能力;
(2)缩——缩减系统处理能力;
(3)上述伸缩过程还必须相对低成本和快速。

架构设计三原则
合适原则:“合适优于业界领先”。
简单原则:“简单优于复杂”。
演化原则:“演化优于一步到位”。

软件架构设计的过程:

  • 首先,设计出来的架构要满足当时的业务需要。
  • 其次,架构要不断地在实际应用过程中迭代,保留优秀的设计,修复有缺陷的设计,改正错误的设计,去掉无用的设计,使得架构逐渐完善。分而治之,复杂问题简单化
  • 第三,当业务发生变化时,架构要扩展、重构,甚至重写;代码也许会重写,但有价值的经验、教训、逻辑、设计等(类似生物体内的基因)却可以在新架构中延续。

架构设计流程

架构设计第1步:识别复杂度

将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。
“亿级用户平台”这个案例,团队就优先选择将 子系统的数量降下来,后来发现子系统数量降下来后,不但开发效率提升了,原来经常发生的小问题也基本消失了,于是团队再在这个基础上做了异地多活方案,也取得了非常好的 效果。

架构设计第2步:设计备用方案

最好是“三方案”,又叫“第三选择”,可以防止思维狭隘,目光短浅,思维盲区等决策陷阱

  1. 几种常见的架构设计误区
    (1)设计最优秀的方案。不要面向“简历”进行架构设计,而是要根据“合适”、“简单”、“演进”的架构设计原则,决策出与需求、团队、技术能力相匹配的合适方案。
    (2)只做一个方案。一个方案容易陷入思考问题片面、自我坚持的认知陷阱。

  2. 备选方案设计的注意事项
    (1)备选方案不要过于详细。备选阶段解决的是技术选型问题,而不是技术细节。例如,评审的时候针对某个定时器应该是1分钟还是30秒,争论得不可开交。
    (2)备选方案的数量以 3~5个为最佳。
    (3)备选方案的技术差异要明显。例如,采用ZooKeeper和Keepalived两种不同的技术来实现主备,差异就很大
    (4)备选方案不要只局限于已经熟悉的技术。

3.“微博”设计方案
(1)采用开源的Kafka,高性能
(2) 集群 + MySQL存储
“高可用写入”和“高性能读取”一样,可采用集群。因为消息只要写入集群中一台服务器就算成功写入,因此“高可用写入”的集群分配算法和“高性能读取”也一 样采用轮询,即正常情况下,客户端将消息依次写入不同的服务器;某台服务器异常的情况下,客户端直接将消息写入下一台正常的服务器即可。
整个系统中最复杂的是“高可用存储”和“高可用读取”,“高可用存储”要求已经写入的消息在单台服务器宕机的情况下不丢失;“高可用读取”要求已经写入的消息在单台服务器宕机的 情况下可以继续读取。架构师第一时间想到的就是可以利用MySQL的主备复制功能来达到“高可用存储“的目的,通过服务器的主备方案来达到“高可用读取”的目的。

image.png

(3)备选方案3:集群 + 自研存储系统
(4)高可用消息存储和读取可以采用mongo和redis
这么高的gps很难保证消息不丢 那么可以采用有消息确认机制和消息回溯的MQ 或者自研rpc的时候考虑消息发送失败的时候重新选择节点然后落盘

架构设计流程的第3步:评估和选择备选方案。

列出我们需要关注的质量属性点,然后分别从这些质量属性的维度去评估每个方案,再综合挑选适合当时情况的最优方案。

常见的方案质量属性点有:性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等。在评估这些质量属性时,需要遵循架构设计原则1“合适原则”和原则2“简单原则”, 避免贪大求全,基本上某个质量属性能够满足一定时期内业务发展就可以了。

image.png

列出表格后,一时无法判断。最终架构师选择了备选方案2
针对备选方案2的缺点,架构师解释是:
第一缺点是性能,业务目前需要的性能并不是非常高,方案2能够满足,即使后面性能需求增加,方案2的数据分组方案也能够平行扩展进行支撑(参考架构设计原 则3:演化原则)。
第二缺点是成本,一个分组就需要4台机器,支撑目前的业务需求可能需要12台服务器,但实际上备机(包括服务器和数据库)主要用作备份,可以和其他系统并 行部署在同一台机器上。
第三缺点是技术上看起来并不很优越,但我们的设计目的不是为了证明自己(参考架构设计原则1:合适原则),而是更快更好地满足业务需求。

2 RocketMQ 和 Kafka 有什么区别?
(1) 适用场景 Kafka适合日志处理;RocketMQ适合业务处理。
(2) 性能 Kafka单机写入TPS号称在百万条/秒;RocketMQ大约在10万条/秒。Kafka单机性能更高。
(3) 可靠性 RocketMQ支持异步/同步刷盘;异步/同步Replication;Kafka使用异步刷盘方式,异步Replication。RocketMQ所支持的同步方式提升了数据的可靠性。
(4) 实时性 均支持pull长轮询,RocketMQ消息实时性更好
(5) 支持的队列数 Kafka单机超过64个队列/分区,消息发送性能降低严重;RocketMQ单机支持最高5万个队列,性能稳定(这也是适合业务处理的原因之一)
3 为什么阿里会自研RocketMQ?
(1) Kafka的业务应用场景主要定位于日志传输;对于复杂业务支持不够
kafka针对海量数据,但是对数据的正确度要求不是十分严格。 而阿里巴巴中用于交易相关的事情较多,对数据的正确性要求极高,Kafka不合适,然后就自研了RocketMQ。
(2) 阿里很多业务场景对数据可靠性、数据实时性、消息队列的个数等方面的要求很高
(3)当业务成长到一定规模,采用开源方案的技术成本会变高(开源方案无法满足业务的需要;旧版本、自开发代码与新版本的兼容等)
(4) 阿里在团队、成本、资源投入等方面约束性条件几乎没有

上网看了相关对比,认为阿里选择自己开发RocketMQ更多是业务的驱动,当业务更多的需要以下功能的支持时,kafka不能满足或者ActiveMQ等其他消息中间件不能满 足,所以选择自己开发(RocketMQ设计的真的很牛)
1、数据可靠性
kafka使用异步刷盘方式,异步Replication
RocketMQ支持异步刷盘,同步刷盘,同步Replication,异步Replication
2、严格的消息顺序
Kafka支持消息顺序,但是一台Broker宕机后,就会产生消息乱序 RocketMQ支持严格的消息顺序,在顺序消息场景下,一台Broker宕机后,发送消息会失败,但是不会乱序 3、消费失败重试机制
Kafka消费失败不支持重试
RocketMQ消费失败支持定时重试,每次重试间隔时间顺延
4、定时消息
Kafka不支持定时消息
RocketMQ支持定时消息
5、分布式事务消息
Kafka不支持分布式事务消息
阿里云ONS支持分布式定时消息,未来开源版本的RocketMQ也有计划支持分布式事务消息
6、消息查询机制
Kafka不支持消息查询
RocketMQ支持根据Message Id查询消息,也支持根据消息内容查询消息(发送消息时指定一个Message Key,任意字符串,例如指定为订单Id) 7、消息回溯
Kafka理论上可以按照Ofset来回溯消息
RocketMQ支持按照时间来回溯消息,精度毫秒,例如从一天之前的某时某分某秒开始重新消费消息
.........

架构设计流程第4步:详细方案设计

详细方案设计就是将方案涉及的关键技术细节给确定下来。

  • 假如我们确定使用Elasticsearch来做全文搜索,那么就需要确定Elasticsearch的索引是按照业务划分,还是一个大索引就可以了;副本数量是2个、3个还是4个,集群节点数量 是3个还是6个等。
  • 假如我们确定使用MySQL分库分表,那么就需要确定哪些表要分库分表,按照什么维度来分库分表,分库分表后联合查询怎么处理等。
  • 假如我们确定引入Nginx来做负载均衡,那么Nginx的主备怎么做,Nginx的负载均衡策略用哪个(权重分配?轮询?ip_hash?)等。 可以看到,详细设计方案里面其实也有一些技术点和备选方案类似。
    例如,Nginx的负载均衡策略,备选有轮询、权重分配、ip_hash、fair、url_hash五个,具体选哪个呢?看起
    来和备选方案阶段面临的问题类似,但实际上这里的技术方案选择是很轻量级的,我们无须像备选方案阶段那样操作,而只需要简单根据这些技术的适用场景选择就可以了。 例如,Nginx的负载均衡策略,简单按照下面的规则选择就可以了。
    轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,后端服务器分配的请求数基本一致,如果后端服务器“down掉”,能自动剔除。
    加权轮询
    根据权重来进行轮询,权重高的服务器分配的请求更多,主要适应于后端服务器性能不均的情况,如新老服务器混用。
    ip_hash 每个请求按访问IP的hash结果分配,这样每个访客固定访问一个后端服务器,主要用于解决session的问题,如购物车类的应用。
    fair
    按后端服务器的响应时间来分配请求,响应时间短的优先分配,能够最大化地平衡各后端服务器的压力,可以适用于后端服务器性能不均衡的情况,也可以防止某台后端服务器性能
    不足的情况下还继续接收同样多的请求从而造成雪崩效应。
    url_hash 按访问URL的hash结果来分配请求,每个URL定向到同一个后端服务器,适用于后端服务器能够将URL的响应结果缓存的情况。
    这几个策略的适用场景区别还是比较明显的,根据我们的业务需要,挑选一个合适的即可。例如,比如一个电商架构,由于和session比较强相关,因此如果用Nginx来做集群负载均 衡,那么选择ip_hash策略是比较合适的。

详细设计方案阶段可能遇到的一种极端情况就是在详细设计阶段发现备选方案不可行,一般情况下主要的原因是备选方案设计时遗漏了某个关键技术点或者关键的质量属性。例如,我曾经参与 过一个项目,在备选方案阶段确定是可行的,但在详细方案设计阶段,发现由于细节点太多,方案非常庞大,整个项目可能要开发长达1年时间,最后只得废弃原来的备选方案,重新调整项目目标、计划和方案。
这个项目的主要失误就是在备选方案评估时忽略了开发周期这个质量属性。
幸运的是,这种情况可以通过下面方式有效地避免: 架构师不但要进行备选方案设计和选型,还需要对备选方案的关键细节有较深入的理解。例如,架构师选择了Elasticsearch作为全文搜索解决方案,前提必须是架构师自己
对Elasticsearch的设计原理有深入的理解,比如索引、副本、集群等技术点;而不能道听途说Elasticsearch很牛,所以选择它,更不能成为把“细节我们不讨论”这句话挂在嘴边 的“PPT架构师”。
通过分步骤、分阶段、分系统等方式,尽量降低方案复杂度,方案本身的复杂度越高,某个细节推翻整个方案的可能性就越高,适当降低复杂性,可以减少这种风险。

如果方案本身就很复杂,那就采取设计团队的方式来进行设计,博采众长,汇集大家的智慧和经验,防止只有1~2个架构师可能出现的思维盲点或者经验盲区。

详细方案设计实战

虽然我们上期在“前浪微博”消息队列的架构设计挑选了备选方案2作为最终方案,但备选方案设计阶段的方案粒度还比较粗,无法真正指导开发人员进行后续的设计和开发,因此需要 在备选方案的基础上进一步细化。

下面我列出一些备选方案2典型的需要细化的点供参考,有兴趣的同学可以自己尝试细化更多的设计点。

  • 1.细化设计点1:数据库表如何设计?
    数据库设计两类表:
    一类是日志表,用于消息写入时快速存储到MySQL中;
    另一类是消息表,每个消息队列一张表。 业务系统发布消息时,首先写入到日志表,日志表写入成功就代表消息写入成功;后台线程再从日志表中读取消息写入记录,将消息内容写入到消息表中。 业务系统读取消息时,从消息表中读取。
    日志表表名为MQ_LOG,包含的字段:日志ID、发布者信息、发布时间、队列名称、消息内容。 消息表表名就是队列名称,包含的字段:消息ID(递增生成)、消息内容、消息发布时间、消息发布者。 日志表需要及时清除已经写入消息表的日志数据,消息表最多保存30天的消息数据。

  • 2.细化设计点2:数据如何复制?
    直接采用MySQL主从复制即可,只复制消息存储表,不复制日志表。

  • 3.细化设计点3:主备服务器如何倒换?
    采用ZooKeeper来做主备决策,主备服务器都连接到ZooKeeper建立自己的节点,主服务器的路径规则为“/MQ/server/分区编号/master”,备机为“/MQ/server/分区编 号/slave”,节点类型为EPHEMERAL。
    备机监听主机的节点消息,当发现主服务器节点断连后,备服务器修改自己的状态,对外提供消息读取服务。

  • 4.细化设计点4:业务服务器如何写入消息?
    消息队列系统设计两个角色:生产者和消费者,每个角色都有唯一的名称。
    消息队列系统提供SDK供各业务系统调用,SDK从配置中读取所有消息队列系统的服务器信息,SDK采取轮询算法发起消息写入请求给主服务器。如果某个主服务器无响应或者返回错误,SDK将发起请求发送到下一台服务器。

  • 5.细化设计点5:业务服务器如何读取消息?
    消息队列系统提供SDK供各业务系统调用,SDK从配置中读取所有消息队列系统的服务器信息,轮流向所有服务器发起消息读取请求。
    消息队列服务器需要记录每个消费者的消费状态,即当前消费者已经读取到了哪条消息,当收到消息读取请求时,返回下一条未被读取的消息给消费者。

  • 关于消息:

  • 6.细化设计点6:业务服务器和消息队列服务器之间的通信协议如何设计?
    考虑到消息队列系统后续可能会对接多种不同编程语言编写的系统,为了提升兼容性,传输协议用TCP,数据格式为ProtocolBufer。

  • 1、发送端和消费端如何寻址 利用zookeeper做注册中心,把broker的地址注册到zk上,发送端和消费端只要配置注册中心的地址即可获取集群所以broker地址,当有broker下线时,发送端和消费端能及时更新broker地 址。

  • 2、发送端消息重试
    当发送消息发生网络异常时(不包括超时异常),可以重新选择下一台broker来重试发送,重试策略可以自定义。

  • 3、消息消费采用pull还是push? 考虑push模式会更复杂,故放弃,采用pull模式,消费端主动去拉,为了达到与push模式相同的低延迟效果,可以采用长轮询的方式,消费端轮询拉取消息费,当有消费可消费时,返回消息, 如果没有可消费的消息,挂起当前线程,直到超时或者有可消费的消息为止。

  • 4、消息重复问题
    消息中间件不解决消息重复的问题,有业务系统自己根据业务的唯一id去重。

  • 5、顺序消息
    发送端在发生顺序消息时,只发送到相同broker的相同队列,消费端消费时,顺序消息只能由同一个消费端消息。

  • 6、定时消息
    发送端指定消息延时多长时间消费,broker端定时扫描定时消息,达到延时时间的消息加入到消费队列。

  • 7、事务消息 发送端分两步,先预发送消息,broker端只记录消息为预发送状态,再执行本地事务,然后再根据本地事务的成功或者失败发送确认消息(回滚还是提交),这步如果发生异常,broker启动定 时任务,把未确认的消息发送给发送端回查事务状态(需要发送端提供回查接口)。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容