记忆中唯独就wwW131https www.778ddcomm缺失了,调整入口的131dd那一段

第三方数据
Brake Disc
8DD 355 111-131
第三方数据HELLA PAGID : 8DD 355 111-131
Brake Disc | HELLA PAGID : 8DD 355 111-131
Brake Disc Type: Externally Vented
Brake Disc Thickness: 30 mm
Min. thickness: 28 mm
Height: 59.4 mm
Hole Pitch / Number: 05/06
Bolt Hole Circle ?: 112 mm
Centering Diameter: 68 mm
Weight: 10.92 kg
Supplementary Article/Info 2: without wheel hub
Supplementary Article/Info 2: without wheel studs
Techn. Info. No.: 54323
AUDI&&A6 (4F2, C6) 2.0 TDI
AUDI&&A6 (4F2, C6) 2.0 TDI
AUDI&&A6 (4F2, C6) 2.0 TFSI
AUDI&&A6 (4F2, C6) 2.7 TDI
AUDI&&A6 (4F2, C6) 2.7 TDI
AUDI&&A6 (4F2, C6) 2.7 TDI quattro
AUDI&&A6 (4F2, C6) 2.7 TDI quattro
AUDI&&A6 (4F2, C6) 2.7 TDI quattro
AUDI&&A6 (4F2, C6) 2.8
AUDI&&A6 (4F2, C6) 2.8 FSI
AUDI&&A6 (4F2, C6) 2.8 FSI
AUDI&&A6 (4F2, C6) 2.8 FSI
AUDI&&A6 (4F2, C6) 2.8 FSI quattro
AUDI&&A6 (4F2, C6) 2.8 FSI quattro
AUDI&&A6 (4F2, C6) 2.8 FSI quattro
AUDI&&A6 (4F2, C6) 3.0
AUDI&&A6 (4F2, C6) 3.0
AUDI&&A6 (4F2, C6) 3.0 TDI quattro
AUDI&&A6 (4F2, C6) 3.0 TDI quattro
AUDI&&A6 (4F2, C6) 3.0 TDI quattro
AUDI&&A6 (4F2, C6) 3.0 quattro
AUDI&&A6 (4F2, C6) 3.2 FSI
AUDI&&A6 (4F2, C6) 3.2 FSI
AUDI&&A6 (4F2, C6) 3.2 FSI quattro
AUDI&&A6 (4F2, C6) 3.2 FSI quattro
AUDI&&A6 Allroad Estate (4FH, C6) 2.7 TDI quattro
AUDI&&A6 Allroad Estate (4FH, C6) 2.7 TDI quattro
AUDI&&A6 Allroad Estate (4FH, C6) 2.7 TDI quattro
AUDI&&A6 Allroad Estate (4FH, C6) 3.0 TDI quattro
AUDI&&A6 Allroad Estate (4FH, C6) 3.0 TDI quattro
AUDI&&A6 Allroad Estate (4FH, C6) 3.0 TDI quattro
AUDI&&A6 Avant (4F5, C6) 2.0 TDI
AUDI&&A6 Avant (4F5, C6) 2.0 TDI
AUDI&&A6 Avant (4F5, C6) 2.0 TFSI
AUDI&&A6 Avant (4F5, C6) 2.4
AUDI&&A6 Avant (4F5, C6) 2.4 quattro
AUDI&&A6 Avant (4F5, C6) 2.7 TDI
AUDI&&A6 Avant (4F5, C6) 2.7 TDI
AUDI&&A6 Avant (4F5, C6) 2.7 TDI
AUDI&&A6 Avant (4F5, C6) 2.7 TDI quattro
AUDI&&A6 Avant (4F5, C6) 2.7 TDI quattro
AUDI&&A6 Avant (4F5, C6) 2.7 TDI quattro
AUDI&&A6 Avant (4F5, C6) 2.8 FSI
AUDI&&A6 Avant (4F5, C6) 2.8 FSI
AUDI&&A6 Avant (4F5, C6) 2.8 FSI
AUDI&&A6 Avant (4F5, C6) 2.8 FSI quattro
AUDI&&A6 Avant (4F5, C6) 2.8 FSI quattro
AUDI&&A6 Avant (4F5, C6) 2.8 FSI quattro
AUDI&&A6 Avant (4F5, C6) 3.0
AUDI&&A6 Avant (4F5, C6) 3.0 TDI quattro
AUDI&&A6 Avant (4F5, C6) 3.0 TDI quattro
AUDI&&A6 Avant (4F5, C6) 3.0 TDI quattro
AUDI&&A6 Avant (4F5, C6) 3.0 TDI quattro
AUDI&&A6 Avant (4F5, C6) 3.0 TDi
AUDI&&A6 Avant (4F5, C6) 3.0 TFSI quattro
AUDI&&A6 Avant (4F5, C6) 3.0 TFSI quattro
AUDI&&A6 Avant (4F5, C6) 3.0 quattro
AUDI&&A6 Avant (4F5, C6) 3.2 FSI
AUDI&&A6 Avant (4F5, C6) 3.2 FSI quattro
AUDI&&A8 (4E_) 2.8 FSI
AUDI&&A8 (4E_) 2.8 FSI
AUDI&&A8 (4E_) 3.0
AUDI&&A8 (4E_) 3.0
AUDI&&A8 (4E_) 3.0 TDI quattro
AUDI&&A8 (4E_) 3.0 TDI quattro
AUDI (FAW)
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 2.0 TFSI
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 2.8
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 2.8 quattro
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 2.8 quattro
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 3.0
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 3.0 TFSI quattro
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 3.0 quattro
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 3.1 FSI
AUDI (FAW)&&FAW A6L Saloon (4F2, C6) 3.1 FSI quattro
APEC braking
HELLA PAGID
HELLA PAGID
HELLA PAGID
HELLA PAGID
HELLA PAGID
HELLA PAGID
HELLA PAGID
ZIMMERMANN
ZIMMERMANN
ZIMMERMANN
ZIMMERMANN
ZIMMERMANN
4F0615301E
4E0615301AD
4F0615301E
4E0615301AD
4F0615301E
4E0615301AD
4F0615301E
4E0615301AD
宜配网全球网站:
记住此次登录
按品牌拼音首字母查找:
客服电话:020-&blockquote&&b&摘要:&/b&使用过开源HBase的人都知道,运维HBase是多么复杂的事情,集群大的时候,读写压力大,配置稍微不合理一点,就可能会出现集群状态不一致的情况,糟糕一点的直接导致入库、查询某个业务表不可用, 甚至集群运行不了。&/blockquote&&h2&概述&/h2&&p& 使用过开源HBase的人都知道,运维HBase是多么复杂的事情,集群大的时候,读写压力大,配置稍微不合理一点,就可能会出现集群状态不一致的情况,糟糕一点的直接导致入库、查询某个业务表不可用, 甚至集群运行不了。在早期0.9x版本的时候,HBase的修复工具还有一下bug,使得即使你懂得如何修复的情况下,依然需要多次重复运行命令,绕过那些不合理的修复逻辑,甚至有时候需要自己写代码预先修复某个步骤。&/p&&h2&背景&/h2&&p& 上周五,某公司使用的某DataHup 大数据产品自建一个HBase集群挂了!整个集群有30+T 业务数据,是公司的数据中心,集群直接启动不了。他们也是经历了熬战一天一夜的情况下,依旧没有解决恢复,还曾有过重装集群重导数据念头。最后,通过钉钉HBase技术交流群找到群主——阿里云HBase的封神。随后其立即下达命令,临时成立 HBase抢救小分队,尽力最大的努力,使用最低风险的方式,抢救最完整的集群。&/p&&p& 蹭蹭蹭,几个抢救队员集齐,开始救火。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-7e8b849d8af4f2fa26a811_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&445& data-rawheight=&305& class=&origin_image zh-lightbox-thumb& width=&445& data-original=&https://pic1.zhimg.com/v2-7e8b849d8af4f2fa26a811_r.jpg&&&/figure&&h2& 救火开始 &/h2&&p& 虽然紧急,但是抢救工作不能乱,我们把救火过程主要分为几步:&/p&&figure&&img src=&https://pic2.zhimg.com/v2-206cf8d0ba_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1668& data-rawheight=&644& class=&origin_image zh-lightbox-thumb& width=&1668& data-original=&https://pic2.zhimg.com/v2-206cf8d0ba_r.jpg&&&/figure&&h2&1. 定位现象问题所在&/h2&&p& 首先与用户沟通现场环境情况,以及客户在出问题之前做过哪些重大操作,特别是一些特殊操作,平时没做过的。据用户描述已经远程观察了解到,用户使用开源的某DataHup自建了一个HBase集群, 存储公司的大量的业务,是公司的数据中心。集群有7个RegionServer、2个Master,32核256G的机器配置,业务数据量有30+T。HBase的master已经都挂了,两个&/p&&p&RegionServer也挂了,用户使用过“重启大法”,依旧无法正常运行。&/p&&p& 寥寥几句没有更多信息,我们只能上集群开日志,打jstack,观察HBase运行流程为什么中断或者挂掉。&/p&&p& 首先我们先检查HDFS文件系统,fsck发现没有什么异常。其次开始检查HBase,把Debug日志打开,全部关闭HBase集群,为了便于观察现象,只启动一个Master和一个RegionServer。启动后,发现Master 因为fullscan meta表(master启动的一个流程)timeout Abort 终止了。观察meta region分配到的RegionServer也挂了,查看日志并没有异常,貌似是这个开源的DataHup 当RegionServer scan数据操作超时 会被manager kill掉的样子。打jstack发现,Master确实在等待fullscan meta完成,而接管meta region&/p&&p&的RegionServer确实一直在忙着scan meta数据,确实有忙不过来超时了。按理说,扫描meta表应该很快的才对。&/p&&p& 检查发现HDFS的HBase meta表有1T多数据!!!进一步查看现象HFile的内容,发现了大量的Delete famly 的cell存在,而且很多是重复的,序列号(没有截图,想象一下)。问题现象定位了,用户使用这个系列的DataHup 的HBase生态时,有组件存在bug往hbase meta表写了大量的这些冗余的delete数据,导致hbase 启动时full scan meta卡着,最终导致整个集群无法正常启动运行服务。&/p&&h2&2. 提出解决方案,评估风险&/h2&&p& 我们很快生成了两个相对较优的方案。第一个是使用离线compaction,把hbase meta表进行一次major compaction把多余的delete family删除,然后再重启即可。第二个方案是,直接移除meta 表的无用hfile, 逆向生成meta 表数据进行修复meta表即可。&/p&&p& 第一个方案做离线compaction对集群来说没有什么风险,缺点是离线compaction并不快,因为meta表region只有一个,执行离线meta表compaction时只有一个task,非常的缓慢耗时。&/p&&p& 第二个方案是逆向修复meta表信息。看似风险很大,其实实际操作起来,很多风险可以降低。我们可以备份好核心的元数据,只有就可以在恢复失败的时候,还原到原来修复手术的前状态。这样一来,这个修复过程也就风险极大降低了。&/p&&h2&3. 开始实施&/h2&&p& 秉着更安全风险更低的情况下,我们还是先选择了方案一,给meta表做离线major compaction的方案。但最终因为MapReduce和本地模式的compaction都太慢了,开始会oom,调整后,最终因meta的hfile checksum校验失败中断了。meta表的hfile都存在问题,那么这个compaction过程就不能正常进行了。&/p&&p& 我们开始选择方案二,和用户沟通风险后,开始制定操作步骤, 把这个方案的实施带来的风险尽可能降到最低。规避这个方案存在的风险,前提是懂得这个方案会有什么风险。下面我们来分析一下,如图:&/p&&figure&&img src=&https://pic1.zhimg.com/v2-efb2dd2ba327a3bced5216_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1446& data-rawheight=&340& class=&origin_image zh-lightbox-thumb& width=&1446& data-original=&https://pic1.zhimg.com/v2-efb2dd2ba327a3bced5216_r.jpg&&&/figure&&p&可以看到,开源HBase的meta表,是可以逆向生成回来的,但是有可能不同的DataHup生产商可能会有一些额外的信息hack进meta表里,对于这部分信息,在开源的逆向生成过程中是不包含的,存在这个关系数据丢失。但是这些核心的业务数据都存在,只是hack的第三方关联信息不存在了。有人可能会问,会有哪些数据可能hack到这里呢?曾看到过某厂商会在meta表了多加一些额外的字段用来保存virtual hostname信息,还有一些将二级索引相关的信息会保存在tableinfo 文件那里。HBase的开发商越多,什么姿势都可能存在,这个就是可能的风险点。&/p&&p&
接下来我们开始实施,这个问题比较典型,用户的meta表里,有1T多的hfile 数据,检查hfile 发现几乎99%的hfile是delete famly相关的内容,我们就移除这些delete famly的hfile到备份目录,只留下一个正常数据的hfile,而这个hfile也仅仅有30M左右的数据。重启HBase后,正常运行。HBase一致性检查发现很幸运,没有坏文件,也没有丢失的tableinfo、regioninfo、hfile相关的block等。如果发现有文件丢失,corrupt hfile等等问题,逆向生成元数据的修复过程就可能会带来风险,但HBase集群核心业务数据依然可以完整挽救。&/p&&h2&4. 用户再自己验证一下是否正常&/h2&&p& 通知用户验证集群运行,业务运行情况。&/p&&h2&小结&/h2&&p& 由于用户的自建HBase集群不像云HBase一样可以我们远程登录管理,只能使用一些远程桌面工具先登录到用户的工作PC再跳到集群环境上,整个操作起来非常的卡顿,影响了问题定位以及最终抢救的效率。&/p&&p& 很多用户使用某些开源DataHup自建集群都会碰到各种各样的运维问题,不要害怕,只要HDFS数据不丢失,HBase怎么挂都可以拯救回来的,不用急着格式化HBase集群重装/重导数据。更多HBase 故障恢复技术交流,请关注钉钉HBase技术交流群。&/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//qr.dingtalk.com/action/joingroup%3Fcode%3Dv1%2Ck1%2CdWFLrx3y8xLTT2QdsLM1GN8uV8TmtqbykHk6pzE%2BC8GaO/VaEts5ZUgMgs79lSb2tzJfywaOtjEnQLyfAnm9tFJOzSBMGmve4Rh%2Bke9MoBNFC2u1yQIUAKOucy/oNr8IOAg4zHiLVhtfdQt9xtncK2L8oFqU5ajJ& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&qr.dingtalk.com/action/&/span&&span class=&invisible&&joingroup?code=v1,k1,dWFLrx3y8xLTT2QdsLM1GN8uV8TmtqbykHk6pzE+C8GaO/VaEts5ZUgMgs79lSb2tzJfywaOtjEnQLyfAnm9tFJOzSBMGmve4Rh+ke9MoBNFC2u1yQIUAKOucy/oNr8IOAg4zHiLVhtfdQt9xtncK2L8oFqU5ajJ&/span&&span class=&ellipsis&&&/span&&/a& (二维码自动识别)&/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//click.aliyun.com/m/46528/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原文链接&/a& &/p&&p&&b&更多技术干货敬请关注云栖社区知乎机构号:&a href=&https://www.zhihu.com/org/a-li-yun-yun-qi-she-qu-48& class=&internal&&阿里云云栖社区 - 知乎&/a&&/b& &/p&
摘要:使用过开源HBase的人都知道,运维HBase是多么复杂的事情,集群大的时候,读写压力大,配置稍微不合理一点,就可能会出现集群状态不一致的情况,糟糕一点的直接导致入库、查询某个业务表不可用, 甚至集群运行不了。概述 使用过开源HBase的人都知道,运…
&p&&b&我用电饭锅烤一只香到骨子里的鸡!&/b&&/p&&h2&先祭出一只电饭锅烤鸡 &/h2&&figure&&img src=&https://pic1.zhimg.com/v2-3f1e90f13968ddd890afc0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1024& data-rawheight=&570& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-3f1e90f13968ddd890afc0_r.jpg&&&/figure&&p&我大学有个室友,是个地地道道的老广,他爱吃鸡那真是爱到了骨子里,每天无鸡不欢。&/p&&p&在吃遍饭堂形形色色各种鸡之后,琢磨出福利了我们4年的大招——&b&电饭锅烤鸡&/b&!&/p&&figure&&img src=&https://pic2.zhimg.com/v2-8cd376ef8ead_b.jpg& data-size=&normal& data-rawwidth=&400& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&400&&&figcaption&当年宿管阿姨无数次上门的罪魁祸首&/figcaption&&/figure&&p&因为好吃又简单,舍友的这招我沿用至今,还边吃边改良了烤鸡的配方。&/p&&p&不骄傲地说,今天这电饭锅烤鸡,绝对够格做压轴硬菜。&/p&&p&&br&&/p&&p&&b&&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dc36ece359ebbedc42a138e5%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&电饭锅烤鸡&/a&食材清单:&/b&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-7dd7ff35c3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1093& data-rawheight=&614& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1093& data-original=&https://pic4.zhimg.com/v2-7dd7ff35c3_r.jpg&&&/figure&&p&童半鸡:1只
姜片:10-15片&/p&&p&食用油:少许
蒜头:4-8块&/p&&p&料酒:5勺
葱头:3-5个&/p&&p&生抽:5勺
辣椒:1-2个&/p&&p&老抽:2勺
密封袋:1个 &/p&&p&香油:1勺
蜂蜜:少许盐1勺&/p&&p&冰糖:4-6块&/p&&p&&br&&/p&&p&&b&&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dc36ece359ebbedc42a138e5%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&电饭锅烤鸡&/a&料理步骤:&/b&&/p&&p&&br&&/p&&p&1|童子鸡洗净,用叉子在鸡身扎些洞,以便入味&/p&&figure&&img src=&https://pic3.zhimg.com/v2-256b2b9a568c9f13cc92_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1093& data-rawheight=&614& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1093& data-original=&https://pic3.zhimg.com/v2-256b2b9a568c9f13cc92_r.jpg&&&/figure&&p&2|准备一个碗,在食用油里加入5勺料酒,5勺生抽,2勺老抽1勺香油,1勺盐。再加入姜片、蒜头、葱头、少量辣椒搅拌均匀&/p&&figure&&img src=&https://pic1.zhimg.com/v2-1eb296ff24_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1094& data-rawheight=&615& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1094& data-original=&https://pic1.zhimg.com/v2-1eb296ff24_r.jpg&&&/figure&&p&3|塞些葱头、菱片到鸡身里面,再把整只鸡放进密封袋里倒入腌料,密封后放入冰箱冷藏腌制一晚&/p&&figure&&img src=&https://pic3.zhimg.com/v2-22f223a6e4dde414b3aeca_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1091& data-rawheight=&611& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1091& data-original=&https://pic3.zhimg.com/v2-22f223a6e4dde414b3aeca_r.jpg&&&/figure&&p&4|电饭煲内胆涂上食用油,在底部铺上姜片以及蒜头葱结,把腌制好的童子鸡放入锅内,淋入密封袋中2/3的腌料&/p&&figure&&img src=&https://pic2.zhimg.com/v2-3c738daebaaad3d71cbf228c05a7fd85_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1090& data-rawheight=&612& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1090& data-original=&https://pic2.zhimg.com/v2-3c738daebaaad3d71cbf228c05a7fd85_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-b32a7c1f6e3fdae4e6940e8a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1087& data-rawheight=&610& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1087& data-original=&https://pic3.zhimg.com/v2-b32a7c1f6e3fdae4e6940e8a_r.jpg&&&/figure&&p&5|电饭煲启用“煮饭”模式,煮好后保温状态下焖10分钟&/p&&figure&&img src=&https://pic3.zhimg.com/v2-decdaa83a6c8a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1089& data-rawheight=&612& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1089& data-original=&https://pic3.zhimg.com/v2-decdaa83a6c8a_r.jpg&&&/figure&&p&6|开盖后稍稍翻身淋入剩下的脆料,放入少量冰糖,并在鸡身涂上蜂蜜,以便烤好后鸡身油亮,继续启用“煮饭”模式,在保温状态下焖煮15分钟鸡。&/p&&figure&&img src=&https://pic3.zhimg.com/v2-ef81ca75f714dfc55e0146_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&408& data-rawheight=&230& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&408&&&/figure&&figure&&img src=&https://pic1.zhimg.com/v2-da84ba728d38_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1089& data-rawheight=&610& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1089& data-original=&https://pic1.zhimg.com/v2-da84ba728d38_r.jpg&&&/figure&&figure&&img src=&https://pic3.zhimg.com/v2-38e1b959b73da_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1091& data-rawheight=&618& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1091& data-original=&https://pic3.zhimg.com/v2-38e1b959b73da_r.jpg&&&/figure&&p&7|取出装盘,把锅中剩余的酱料盛在蘸碟中做蘸酱&/p&&figure&&img src=&https://pic3.zhimg.com/v2-689023eece1f2b4d33f1da2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1092& data-rawheight=&618& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1092& data-original=&https://pic3.zhimg.com/v2-689023eece1f2b4d33f1da2_r.jpg&&&/figure&&p&越写越饿,接下来准备做米酒鸡、盐焗鸡、麻油鸡、油纸包鸡,想看点赞了啊喂!&/p&&p&&br&&/p&&h2&再祭出一只蒜香米酒鸡&/h2&&p&&b&用蒜瓣加米酒,香气在我家绕了三小时。&/b&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-63d710ebab463d56155ddc5e83a18f94_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1080& data-rawheight=&608& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1080& data-original=&https://pic1.zhimg.com/v2-63d710ebab463d56155ddc5e83a18f94_r.jpg&&&/figure&&p&嫩滑的鸡肉吸足了酱汁,很入味。&/p&&p&就连你以为是配料的蒜瓣,也完全没有辛辣味,香甜下饭。&/p&&figure&&img src=&https://pic2.zhimg.com/v2-1cc4cb361f19c01f4152361_b.jpg& data-size=&normal& data-rawwidth=&400& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&400&&&figcaption&来,吃&/figcaption&&/figure&&p&&b&01 食材&/b&&/p&&p&鸡腿肉、姜、豆瓣酱&/p&&p&蒜瓣、米酒、水、高汤&/p&&p&&br&&/p&&p&&b&02 步骤&/b&&/p&&p&1.鸡腿肉切块,热锅里热油入5片姜爆香&/p&&figure&&img src=&https://pic3.zhimg.com/v2-e6a88bae6a7a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&400&&&/figure&&p&2.鸡肉沥干水后,入油锅翻炒到表皮金黄后拨到一边,下一勺豆瓣酱,出红油后将鸡肉翻炒均匀,加生抽一勺,盐和糖少许,翻炒均匀&/p&&figure&&img src=&https://pic2.zhimg.com/v2-37d143eeac46a6c0f317c66a461f3021_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&400&&&/figure&&p&3. 倒入蒜瓣,大火翻炒至蒜瓣表面微焦&/p&&figure&&img src=&https://pic1.zhimg.com/v2-247dc960ff35bd0d6d0b6d8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&400&&&/figure&&p&4. 淋50g米酒,再倒入高汤或白开水没过鸡肉,调小火盖上锅盖焖至收汁,起锅装盘就ok&/p&&figure&&img src=&https://pic2.zhimg.com/v2-4fdb65348bd_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&225& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&400&&&/figure&&p&好的爱情,是这只蒜香米酒鸡。&/p&&p&就像米酒和蒜瓣,两者味浓且矛盾,可一煮,都没有了那股子辛辣,味道交融,反而香得热烈。&/p&&p&&br&&/p&&h2&&b&古法盐焗鸡也不能活着出去&/b&&/h2&&p&&b&做好这只鸡要用1斤盐?!&/b&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-da63e3e993e494967ade44ff309aab47_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1280& data-rawheight=&720& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic4.zhimg.com/v2-da63e3e993e494967ade44ff309aab47_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-84bdfb2de3d4f5975b1fbd3378fb0aed_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&408& data-rawheight=&230& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&408&&&/figure&&p&曾经向粉丝征集过“美食与故事”,让我感到到哭的一个故事没想到主角却是一只鸡。&/p&&figure&&img src=&https://pic4.zhimg.com/v2-b36abb9af5a76e91dbf0a0cffa2af943_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1280& data-rawheight=&960& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic4.zhimg.com/v2-b36abb9af5a76e91dbf0a0cffa2af943_r.jpg&&&/figure&&p&&b&食材清单:&/b&&/p&&p&整鸡、粗盐、砂纸&/p&&p&&br&&/p&&p&&b&料理步骤:&/b&&/p&&p&1.整鸡洗净晾干水分,鸡身用粗盐抹一遍&/p&&figure&&img src=&https://pic2.zhimg.com/v2-adda591c6e502adb9f4909_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1095& data-rawheight=&617& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1095& data-original=&https://pic2.zhimg.com/v2-adda591c6e502adb9f4909_r.jpg&&&/figure&&p&2.用两张盐焗鸡砂纸,把鸡包起来&/p&&figure&&img src=&https://pic3.zhimg.com/v2-dbceed686b496_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1089& data-rawheight=&613& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1089& data-original=&https://pic3.zhimg.com/v2-dbceed686b496_r.jpg&&&/figure&&p&3.准备一个砂锅,倒入粗盐垫底,放入整鸡&/p&&figure&&img src=&https://pic1.zhimg.com/v2-cfa9a1149c4c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1088& data-rawheight=&605& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1088& data-original=&https://pic1.zhimg.com/v2-cfa9a1149c4c_r.jpg&&&/figure&&p&4.避免鸡肉跟锅壁接触,余下粗盐铺在鸡的上方&/p&&figure&&img src=&https://pic2.zhimg.com/v2-4ff9084bcfe9b9a898bd41_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1090& data-rawheight=&613& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1090& data-original=&https://pic2.zhimg.com/v2-4ff9084bcfe9b9a898bd41_r.jpg&&&/figure&&p&5.焗鸡,中灾煮10分钟后,转小火慢焗1小时即可&/p&&figure&&img src=&https://pic1.zhimg.com/v2-277cd9718fcca6c314ba64_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1087& data-rawheight=&614& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1087& data-original=&https://pic1.zhimg.com/v2-277cd9718fcca6c314ba64_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/v2-d63f1c9c2fa3ba7031a1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1087& data-rawheight=&611& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&1087& data-original=&https://pic2.zhimg.com/v2-d63f1c9c2fa3ba7031a1_r.jpg&&&/figure&&p&&b&下面是让你100%做好盐焗鸡的小贴士 &/b& &/p&&p&&br&&/p&&p&&b&TIP 1&/b& &b&鸡事先要怎么处理?&/b& &/p&&p&请市场卖鸡阿姨帮你把活鸡处理成白白净净的样子。&/p&&p&拿回家再清洗一遍,然后晾干(或者用厨房纸巾擦干)!这点很关键,会影响鸡皮的香脆口感,不要湿漉漉的就包纸咯。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-11fd5d3bf2791ff8ecb826c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&408& data-rawheight=&230& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&408&&&/figure&&p&&b&TIP 2&/b& &b&包鸡的纸去哪儿找?&/b& &/p&&p&盐焗鸡砂纸可以在某宝买,也可以用烘焙油纸代替。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-fa387bb76ce8_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&408& data-rawheight=&230& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&content_image& width=&408&&&/figure&&p&&b&TIP 3&/b& &b&要用多少盐?&/b& &/p&&p&焗鸡的盐得用粗盐,腌咸菜一粒粒的那种。一只大小适中的鸡一包半盐绰绰有余,熟练的话一包就够啦。&/p&&p&记得不要让鸡和纸直接接触到锅壁,可以拿盐垫在鸡与锅壁之间。&/p&&p&&br&&/p&&p&&b&TIP 4&/b& &b&姜葱蘸料怎么做?&/b& &/p&&p&切姜末和葱白,撒点盐混合在一起。然后锅中热花生油,等油滚后直接淋上去,搅拌均匀就可以了。&/p&&p&晚点再来更新。嘻嘻嘻&/p&&hr&&p&来都来了撩一下再走?&/p&&p&&b&关注【一餐范】微信公众号,&/b&给你安利&b&3000道&/b&美食菜谱与视频!&/p&&p&&br&&/p&&p&&b&测评大全:&/b&&a href=&//link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D43a3e4e6a480d87f09f86bf05ae65fdb%26chksm%3Dea1e42b046c7aa2a76e91f0e1f6ce31e46bfc0aabc9%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&狗粮味道测评&/a&丨&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3Defc852c0a2ff180bac18ffb9%26source%3D41%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&40包糖果测评&/a&丨&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D6afd971cd3caecad9c6c52%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&全球泡面Top10大赏&/a&……&/p&&p&&b&味蕾挑战实验室:&/b&&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D637efe593dd1cad7f39b%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&崂山圣水火锅&/a&丨&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D4e771f68a7d769ca167ac14b157efe51%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&蓝色可乐鸡翅&/a&丨&a href=&//link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D552ae762b13df343a11e4e%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&花椒果昔&/a&……&/p&&p&&b&厨房技巧:&/b&&a href=&//link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D39da835eaadc8ff47fdc6%26chksm%3Dea1e07e9dd698effff0682ce2afc74b1d0ad911a6534%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&厨房神器指南帖&/a&丨&a href=&//link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3Dacb696b0a%26chksm%3Dea1e063ddd698f2becfd4f420fe1d6f7094531cffc8acff%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&11种饺子皮花式技巧&/a&丨&a href=&//link.zhihu.com/?target=http%3A//mp.weixin.qq.com/s%3F__biz%3DMzI1NjkxOTMxOA%3D%3D%26mid%3D%26idx%3D1%26sn%3D29a7262061bfb0d7aee5ada%26chksm%3Dea1e42e5e2d311c088ac1ec675cca862ae46e62cd9cb04%26scene%3D21%23wechat_redirect& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&牙签切水果&/a&……&/p&&p&&br&&/p&&p&不仅教你做菜,还用故事讲给你听,食物背后的那些事儿~&/p&&figure&&img src=&https://pic4.zhimg.com/v2-d3f461a5fff5f8b5f8ef5b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&618& data-rawheight=&153& data-watermark=&& data-original-src=&& data-watermark-src=&& data-private-watermark-src=&& class=&origin_image zh-lightbox-thumb& width=&618& data-original=&https://pic4.zhimg.com/v2-d3f461a5fff5f8b5f8ef5b_r.jpg&&&/figure&
我用电饭锅烤一只香到骨子里的鸡!先祭出一只电饭锅烤鸡 我大学有个室友,是个地地道道的老广,他爱吃鸡那真是爱到了骨子里,每天无鸡不欢。在吃遍饭堂形形色色各种鸡之后,琢磨出福利了我们4年的大招——电饭锅烤鸡!因为好吃又简单,舍友的这招我沿用至今…
&p&我推荐一个方法,很简单但很好用,就是不断地&b&复盘。&/b&&/p&&p&&br&&/p&&blockquote& 「复盘」这个词最早来源于棋类术语,也称「复局」,指对局完毕后,复演该盘棋的记录,以检查对局中对弈者的优劣与得失关键。每天「打谱」,按照棋谱排演,有效地加深对这盘对弈的印象,也可以找出双方攻守的漏洞。
复盘被认为是围棋选手增长棋力的最重要方法,尤其是自己和高水平者对弈时,可以通过他人的视角看到自己思考不足的地方,从而将别人的经验化为己用。围棋棋手的训练方法很简单:不断下棋,简单复盘,日复一日,年复一年。方法最单调但也最有效。&br&&b&通俗来说,复盘就是把当时「走」的过程重复多遍,并且主动思考为什么这么「走」,下一步应该如何设计,接下来的几步该怎么走。&/b&从棋阵来看,复盘是攻守结合的切磋,从心理战来看,能更好地对比双方的心理思维,最终总结出所谓的「套路」。当「套路」熟捻于心,就自然能达到高手的境界了。&/blockquote&&p&——柳传志《我的复盘方法论》&/p&&p&&br&&/p&&p&&br&&/p&&p&具体而言,可以分为这样几个步骤:&/p&&ul&&li&第一步,回顾目标并和结果对比:回顾一件重大的决策中,你做了哪些事?和开始的目标之间有什么不一样?&br&&/li&&li&第二步,评估所做的事情:评估每件事的价值,到底哪一步是关键步骤?&br&&/li&&li&第三步,发掘规律,寻找共性:有哪些原则或者经验可以从中学到?有哪些其他的案例或者书籍对这样的决策有帮助?&/li&&li&第四步,总结反思:有哪些可以提升的地方?如果再面临这类问题,如何决策?&/li&&/ul&&p&&br&&/p&&p&&b&复盘最直接的,就是磨练我们的思维能力,并且最大限度地防止我们在同一个地方犯错误——这绝对是决策能力最大的体现。&/b&&/p&&p&&br&&/p&&p&如果你做一件事情失败了,一定不能只得到“我失败了”或者“我不适合这项任务”的结论,而是要知道,到底是哪一项具体的原因构成了失败:心理因素?信息不足?还是没有实战经验?如果每一个因素都有,也不能鱼龙混杂地分析,更要精确到具体的事项,了解究竟是哪一步出现了问题——就像围棋落子一样,确定地知道,是哪一步棋走得不够好,并且这样还不够,还要知道,要怎么走才好,这样反复去思考,清楚地了解到所有可能被遗漏的细节。&/p&&p&&br&&/p&&p&&b&除了提升决策能力之外,让我们更有效地分配我们的决策能力。&/b&&/p&&p&&br&&/p&&p&&br&&/p&&p&很多人可能没有意识到的是,我们往往在做一些重大决定(如买房,结婚,择业)的时候,并没有给予和这件事重要性匹配的关注。&/p&&p&&br&&/p&&p&就拿结婚来说,我曾经做过婚礼司仪,和新郎新娘聊天时发现,有一些人在准备婚礼各项事宜(重要事项)花费了两个月,但是相亲到确定对方是另一半(极端重要事项),只见了五次面;&/p&&p&&br&&/p&&p&很多人在升学选择学校(极端重要事项)的时候,决定因素仅仅是一份不知道哪里来的学校排名,但决定晚饭去哪一家餐厅(中低等重要事项)的时候,却翻遍了某app里所有评论;&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-4cefcfe81d237ba31a800dfc_b.png& data-caption=&& data-rawwidth=&596& data-rawheight=&321& class=&origin_image zh-lightbox-thumb& width=&596& data-original=&https://pic4.zhimg.com/v2-4cefcfe81d237ba31a800dfc_r.png&&&/figure&&p&我们对待不同事情所花费的决策精力大致就像上面这张图所示。&/p&&p&对于中等重要的事情,往往我们会大幅提高我们的精力去处理,比如一个策划案,比如一顿重要的晚宴。&/p&&p&其原因是在做这些决策时,我们明显可以看到&b&即时收益,强大的即时反馈让我们知道,花更多的精力来做这个决策是有价值的。&/b&&/p&&p&&br&&/p&&p&&br&&/p&&p&我们很擅长做这样的决定:如果明天就要考试,那么现在熬夜通宵是值得的;&/p&&p&也很擅长做这样的决定:今天这封邮件不发给老板可能会被骂,虽然现在去发邮件让我很不爽,但是相比于被骂,现在发邮件还是值得的。&/p&&p&&br&&/p&&p&&br&&/p&&p&&b&但是遗憾的是,很多重要的决定并非是即时的。&/b&&/p&&p&&br&&/p&&p&我们看不到,这一刻深思熟虑地交一个挚友可以带给我们什么样的帮助;&/p&&p&我们也不知道,多思考一下“这份职业适不适合我”是不是就可以提升薪水;&/p&&p&我们更无法量化,如果多反思10分钟“最近一个月的工作有什么不足和可以改进之处”可以带来什么收益。&/p&&p&&br&&/p&&p&我们绝大部分人都天生不擅长这种长逻辑链的思考,只有简单的因果(我做了A决定→得到了B收益)才会激发我们的决策欲望。&/p&&p&&br&&/p&&p&所以,有时候&b&不是决策能力有问题,而是根本没有用上足够多的时间和精力去做决定。&/b&&/p&&p&&br&&/p&&p&&b&而造成这样的原因是:我们无法把一件复杂的决策拆分下来,清楚了解到我们每一步行为的价值。&/b&&/p&&p&&br&&/p&&p&&b&复盘在这个时候也就相当重要。&/b&在做完一件事,尤其是一眼望不透的事的时候,重新回顾,重新肢解每一步的行为,确定他们的价值,并总结经验。通过许多次这样的复盘之后,能逐渐建立起一些关系链条很复杂的事情之间的联系,从而优化自己的决策能力这项资源的配置。&/p&&p&&br&&/p&&p&&b&决策能力提升+决策能力的利用效率提升,这绝对是很实在的方法。&/b&&/p&
我推荐一个方法,很简单但很好用,就是不断地复盘。 「复盘」这个词最早来源于棋类术语,也称「复局」,指对局完毕后,复演该盘棋的记录,以检查对局中对弈者的优劣与得失关键。每天「打谱」,按照棋谱排演,有效地加深对这盘对弈的印象,也可以找出双方攻…
&figure&&img src=&https://pic4.zhimg.com/v2-94cb0b8cd4e0eda52d02d2_b.jpg& data-rawwidth=&647& data-rawheight=&362& class=&origin_image zh-lightbox-thumb& width=&647& data-original=&https://pic4.zhimg.com/v2-94cb0b8cd4e0eda52d02d2_r.jpg&&&/figure&&p&&b&单数据库架构&/b&&/p&&p&一个项目在初期的时候,为了尽可能快地验证市场,其对业务系统的最大要求是快速实现。在这个阶段,代码开发人员为了能快速实现业务系统,一般都是将所有层级(MVC)的业务代码都写在同一个项目中,所有的业务数据都存放在同一个数据库中。此时,项目的整体架构图如下所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-8bfa25fce74c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&621& data-rawheight=&531& class=&origin_image zh-lightbox-thumb& width=&621& data-original=&https://pic4.zhimg.com/v2-8bfa25fce74c_r.jpg&&&/figure&&p&&br&&/p&&p&从上图可以看到,我们在一个项目中集中了注册、登陆、购物三个模块的业务代码,并且这三个业务模块都读取同一个业务数据库。&/p&&p&但随着项目的不断推进,用户量不断增长,单台应用服务器已经无法承受如此巨大的流量了。此时常见的做法是把项目进行分布式部署,分散单台服务器的流量,从而可以暂时缓解用户增长带来的应用服务器压力。此时的项目架构图如下所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-a163a2e5ca1a4761fc52_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&621& data-rawheight=&861& class=&origin_image zh-lightbox-thumb& width=&621& data-original=&https://pic2.zhimg.com/v2-a163a2e5ca1a4761fc52_r.jpg&&&/figure&&p&&br&&/p&&p&但随着我们部署的应用服务器越来越多,后端的单台数据库服务器已经无法承受如此巨大的流量了。为了尽快缓解用户访问压力,我们一般是在应用服务器与数据库服务器中间加多一个缓存层,通过缓存可以抵消掉一部分的数据库查询操作。此时的项目架构图如下所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-4eeb05a482e12e005d73a51c01bc1371_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&621& data-rawheight=&981& class=&origin_image zh-lightbox-thumb& width=&621& data-original=&https://pic1.zhimg.com/v2-4eeb05a482e12e005d73a51c01bc1371_r.jpg&&&/figure&&p&&br&&/p&&p&但是增加数据库缓存层只能缓解数据库访问压力,拦截部分数据库访问请求。随着用户访问量的进一步增长,数据库访问的瓶颈还是会进一步凸显。这个时候,我们不得不对数据层的架构进行改造。&/p&&p&&b&主从数据库架构&/b&&/p&&p&这个时候常用的解决方案就是将原本单台数据库服务器变成主从模式的数据库服务器,即一台数据库作为主库支持写入数据,一台数据库作为读库支持查询数据。此时项目的架构图如下所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-47db344a238999dcdf4ff78a6004df55_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&763& data-rawheight=&881& class=&origin_image zh-lightbox-thumb& width=&763& data-original=&https://pic4.zhimg.com/v2-47db344a238999dcdf4ff78a6004df55_r.jpg&&&/figure&&p&&br&&/p&&p&我们通过数据库主从同步实现了读写分离,将所有读操作都引导到从库进行,将所有写操作都引导到主库进行。&/p&&p&因为我们对数据库层进行了改造,规定所有读数据库操作要访问从库,所有写数据库操作要访问主库,那么我们就必须对原来的代码进行改造。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public User selectUser(){
dataTemplate.selectById(...);
public User insertUser(){
dataTemplate.insert(user);
&/code&&/pre&&/div&&p&上面是改造前的代码,无论是读操作还是写操作,我们都使用同一个数据源进行操作。但为了适应新的数据库架构,我们必须在代码中手动判断应该请求哪个数据源。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public User selectUser(){
readTemplate.selectById(...);
public User insertUser(){
writeTemplate.insert(user);
&/code&&/pre&&/div&&p&经过修改后的代码,开发根据自身经验判断应该选择哪个数据源进行操作。当是读操作的时候,我们选择 readTemplate。当是写操作的时候,我们选择 writeTemplate。&/p&&p&但作为一个程序员,我们隐隐约约觉得识别应该用哪个数据源这个判断不应该人工判断,而应该自动让代码去判断。毕竟这个判断的模式很简单 —— 如果是 select 那么就用读的数据源,如果是其他那么就用写的数据源。&/p&&p&&b&其实这个就是 MyCat 的用途之一,即作为一个数据库中间件去解决数据源判断问题。&/b&如果我们使用 MyCat 作为数据库中间件,那么我们不需要关心我应该使用哪个数据源。MyCat 帮我们屏蔽了不同数据源的差异,对于我们来说就只有一个数据源,这个数据源能处理写操作,也能处理读操作。上面查询和插入的代码就可以变成下面这样:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public User selectUser(){
dataTemplate.selectById(...);
public User insertUser(){
dataTemplate.insert(user);
&/code&&/pre&&/div&&p&实现了主从数据库架构,再使用 MyCat,你发现我们并不需要去修改太多的代码,只需要将数据源改为 MyCat 地址即可。MyCat 自动把我们所有的语句发送给后端的 MySQL 服务器。&/p&&p&当我们使用了主从数据库架构之后,我们会发现我们能支撑更多的用户访问和请求了。但随着业务的进一步发展,其实可以发现会存在一些问题:&/p&&ul&&li&当我们修改了注册模块的时候,我们需要整个项目都发布一次,这样会影响到登录、购物模块的正常使用。&/li&&li&即使每次改动的代码即使很小,我们还是需要发布整个项目包,这使得每次发布的代码包非常巨大。&/li&&li&随着业务量的不断增长,我们会发现即使实现了主从的读写分离,数据库的压力也是非常大,似乎快要承受不了了。&/li&&/ul&&p&上面说的这些问题只是实战中遇到的一部分问题,事实上遇到的问题只会更多不会更少,而且随着业务的不断发展会愈加凸显。&/p&&p&&b&垂直切分数据库架构&/b&&/p&&p&此时为了各个业务模块不互相影响,我们把应用层进行垂直拆分,即把注册模块、登陆模块、购物模块都单独作为一个应用系统,分别读写独立的数据库服务器。此时,我们的系统架构图如下图所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-da8ee797f23c4c5b3e2b613638dbdc1b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&921& data-rawheight=&601& class=&origin_image zh-lightbox-thumb& width=&921& data-original=&https://pic1.zhimg.com/v2-da8ee797f23c4c5b3e2b613638dbdc1b_r.jpg&&&/figure&&p&&br&&/p&&p&实现了垂直拆分之后,我们可以成功解决上面说到的三个问题:业务模块相互影响问题、单数据库压力问题。&/p&&p&但是随着业务的进一步扩大,我们又增加了许多业务模块:客服模块、钱包模块、个人中心模块、收藏夹模块、订单模块等。按照我们之前所设计的数据库架构,我们会存在许多个数据源,这些数据源分散在各个项目中:&/p&&ul&&li&用户数据库 192.168.0.1&/li&&li&商品数据库 192.168.0.2&/li&&li&短信数据库 192.168.0.3&/li&&li&客服数据库 192.168.0.4&/li&&li&钱包数据库 192.168.0.5&/li&&li&……&/li&&/ul&&p&对于一个项目管理者来说,这么多的数据源分散在不同项目中,怎么统一管理是一个问题。很多时候我们都很难记住这个项目连接的是哪个数据库,那个项目连接的是哪个数据库。&/p&&p&但如果你使用了 MyCat 作为数据库中间件的话,MyCat 就可以帮你解决这个问题。&b&对于所有项目来说,它们只需要统一连接 MyCat 对外提供的一个地址,而 MyCat 则帮这些项目联系所有后端的 MySQL 数据库。&/b&对于前端的项目俩说,它们只知道 MyCat 这个数据库中间件,而不需要去理会我到底连接哪个数据库,MyCat 通过自身配置可以完成这个任务。&/p&&p&&b&水平切分数据库架构&/b&&/p&&p&当数据库架构经历了主从架构、垂直拆分架构之后,应对一般的业务读写是没有什么问题了。但对于一些核心的业务数据,可能还是会有瓶颈问题,例如用户模块。&/p&&p&对于一些用户量高达一个亿的用户系统来说,即使经过主从架构、垂直拆分架构的优化,但其用户数据库的单个表里需要存储的数据还是高达一个亿的大小。如果我们把所有的数据都存放在一个表里,无论是注册时的插入数据,或者是登陆时的查询数据,势必会变得很慢。&/p&&p&这时候,我们就不得不对这些高数据量的核心业务表进行水平拆分,即将海量的数据记录拆分到多张表中保存。例如我们一开始可能只有一张 User 表,我们将 User 表按照用户 ID 对 1000 取余进行拆分,那么我们就会有 1000 张表,分别是 User_000 至 User_999。此时,项目的架构图如下所示:&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-d5aa7b13cf3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&881& data-rawheight=&751& class=&origin_image zh-lightbox-thumb& width=&881& data-original=&https://pic1.zhimg.com/v2-d5aa7b13cf3_r.jpg&&&/figure&&p&&br&&/p&&p&当我们在代码中查询用户数据时,我们先根据用户 ID 取余判断其应该操作的表,之后再查询对应的表。例如 UserId 为
的用户就应该查询 User_38 表,UserId 为
的用户就应该查询 User_83 表。&/p&&p&通过水平拆分,我们成功解决了海量数据核心业务表的读写瓶颈问题。但此时在代码层面上有一个问题出现了,那就是我们需要在查询数据库之前,根据 UserId 去判断应该查询哪个表,这个操作对于所有业务模块来说都是高度一致的,应该抽离成一个公用的项目。&/p&&p&与判断应该使用读数据源还是写数据源一致,我们都觉得这样机械的任务不应该丢给程序员做,应该让机器去做。这其实就是 MyCat 可以帮我们做的事情:&b&MyCat 通过配置一系列的分库分表规则,让 MyCat 帮我们自动判断应该查询哪一个分表。&/b&通过使用 MyCat 数据库中间件,我们可以省去在代码层判断查询哪个表的冗余代码,从而让开发人员更专注于业务逻辑的开发。&/p&&p&&b&总结&/b&&/p&&p&从单一的数据库架构,到主从读写分离的数据库架构,再到垂直拆分、水平拆分的数据库架构。我们可以看到 MyCat 帮我们解决了读写数据源判断、繁杂数据源地址、分表判断这三个机械的重复性的问题。&/p&&p&上面说到的三个功能就是 MyCat 诞生初期的最基本功能。但 MyCat 发展至今,其功能已经远远超过上面说的这三个。例如 MyCat 支持主从切换功能,当数据库主库发生网络问题或其他故障时,MyCat 可以自动切换到从库,从而保证正常读写功能的进行。&/p&&p&总的来说,MyCat 的定位是一个数据库中间件。但凡所有处于应用层和数据层之间的事情,MyCat 都可以做。&/p&&p&&br&&/p&&p&作者: 陈树义 &/p&&p&链接:&a href=&https://link.zhihu.com/?target=http%3A//www.imooc.com/article/23057& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://www.&/span&&span class=&visible&&imooc.com/article/23057&/span&&span class=&invisible&&&/span&&/a&&/p&&p&来源:慕课网&/p&&p&本文原创发布于慕课网 ,转载请注明出处,谢谢合作&/p&
单数据库架构一个项目在初期的时候,为了尽可能快地验证市场,其对业务系统的最大要求是快速实现。在这个阶段,代码开发人员为了能快速实现业务系统,一般都是将所有层级(MVC)的业务代码都写在同一个项目中,所有的业务数据都存放在同一个数据库中。此时…
&figure&&img src=&https://pic4.zhimg.com/v2-bf0cb538e8ed8a_b.jpg& data-rawwidth=&1100& data-rawheight=&733& class=&origin_image zh-lightbox-thumb& width=&1100& data-original=&https://pic4.zhimg.com/v2-bf0cb538e8ed8a_r.jpg&&&/figure&&h2&本文你将学到什么?&/h2&&p&本文将以原理+实战的方式,首先对“微服务”相关的概念进行知识点扫盲,然后开始手把手教你搭建这一整套的微服务系统。&/p&&h2&项目完整源码下载&/h2&&a href=&http://link.zhihu.com/?target=https%3A//github.com/bz51/SpringBoot-Dubbo-Docker-Jenkins& data-draft-node=&block& data-draft-type=&link-card& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&github.com/bz51/SpringB&/span&&span class=&invisible&&oot-Dubbo-Docker-Jenkins&/span&&span class=&ellipsis&&&/span&&/a&&h2&这套微服务框架能干啥?&/h2&&p&这套系统搭建完之后,那可就厉害了:&/p&&ul&&li&微服务架构&br&你的整个应用程序将会被拆分成一个个功能独立的子系统,独立运行,系统与系统之间通过RPC接口通信。这样这些系统之间的耦合度大大降低,你的系统将非常容易扩展,团队协作效率提升了N个档次。这种架构通过眼下流行的SpringBoot和阿里巴巴吊炸天的Dubbo框架来实现。&/li&&li&容器化部署&br&你的各个微服务将采用目前处于浪潮之巅的Docker来实现容器化部署,避免一切因环境引起的各种问题,让你们团队的全部精力集中在业务开发上。&/li&&li&自动化构建&br&项目被微服务化后,各个服务之间的关系错中复杂,打包构建的工作量相当可怕。不过没关系,本文将借助Jenkins,帮助你一键自动化部署,从此你便告别了加班。&/li&&/ul&&hr&&h2&知识点扫盲篇&/h2&&p&咳咳,敲黑板啦!笔记赶紧记起来,课后我要检查的!检查不合格的同学放学后留下来!&/p&&h2&知识点1:微服务&/h2&&p&微服务一次近几年相当火,成为程序猿饭前便后装逼热门词汇,你不对它有所了解如何在程序猿装逼圈子里混?下面我用最为通俗易懂的语言介绍它。&/p&&p&要讲清楚微服务,我先要从一个系统架构的演进过程讲起。&/p&&h2&单机结构&/h2&&p&我想大家最最最熟悉的就是单机结构,一个系统业务量很小的时候所有的代码都放在一个项目中就好了,然后这个项目部署在一台服务器上就好了。整个项目所有的服务都由这台服务器提供。这就是单机结构。 那么,单机结构有啥缺点呢?我想缺点是显而易见的,单机的处理能力毕竟是有限的,当你的业务增长到一定程度的时候,单机的硬件资源将无法满足你的业务需求。此时便出现了集群模式,往下接着看。&/p&&h2&集群结构&/h2&&p&集群模式在程序猿界由各种装逼解释,有的让你根本无法理解,其实就是一个很简单的玩意儿,且听我一一道来。&/p&&p&单机处理到达瓶颈的时候,你就把单机复制几份,这样就构成了一个“集群”。集群中每台服务器就叫做这个集群的一个“节点”,所有节点构成了一个集群。每个节点都提供相同的服务,那么这样系统的处理能力就相当于提升了好几倍(有几个节点就相当于提升了这么多倍)。&/p&&p&但问题是用户的请求究竟由哪个节点来处理呢?最好能够让此时此刻负载较小的节点来处理,这样使得每个节点的压力都比较平均。要实现这个功能,就需要在所有节点之前增加一个“调度者”的角色,用户的所有请求都先交给它,然后它根据当前所有节点的负载情况,决定将这个请求交给哪个节点处理。这个“调度者”有个牛逼了名字——负载均衡服务器。&/p&&p&集群结构的好处就是系统扩展非常容易。如果随着你们系统业务的发展,当前的系统又支撑不住了,那么给这个集群再增加节点就行了。但是,当你的业务发展到一定程度的时候,你会发现一个问题——无论怎么增加节点,貌似整个集群性能的提升效果并不明显了。这时候,你就需要使用微服务结构了。&/p&&h2&微服务结构&/h2&&p&先来对前面的知识点做个总结。 从单机结构到集群结构,你的代码基本无需要作任何修改,你要做的仅仅是多部署几台服务器,没太服务器上运行相同的代码就行了。但是,当你要从集群结构演进到微服务结构的时候,之前的那套代码就需要发生较大的改动了。所以对于新系统我们建议,系统设计之初就采用微服务架构,这样后期运维的成本更低。但如果一套老系统需要升级成微服务结构的话,那就得对代码大动干戈了。所以,对于老系统而言,究竟是继续保持集群模式,还是升级成微服务架构,这需要你们的架构师深思熟虑、权衡投入产出比。&/p&&p&OK,下面开始介绍所谓的微服务。 微服务就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在微服务结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。&/p&&p&举个例子,假设需要开发一个在线商城。按照微服务的思想,我们需要按照功能模块拆分成多个独立的服务,如:用户服务、产品服务、订单服务、后台管理服务、数据分析服务等等。这一个个服务都是一个个独立的项目,可以独立运行。如果服务之间有依赖关系,那么通过RPC方式调用。&/p&&p&这样的好处有很多:&/p&&ol&&li&系统之间的耦合度大大降低,可以独立开发、独立部署、独立测试,系统与系统之间的边界非常明确,排错也变得相当容易,开发效率大大提升。&/li&&li&系统之间的耦合度降低,从而系统更易于扩展。我们可以针对性地扩展某些服务。假设这个商城要搞一次大促,下单量可能会大大提升,因此我们可以针对性地提升订单系统、产品系统的节点数量,而对于后台管理系统、数据分析系统而言,节点数量维持原有水平即可。&/li&&li&服务的复用性更高。比如,当我们将用户系统作为单独的服务后,该公司所有的产品都可以使用该系统作为用户系统,无需重复开发。&/li&&/ol&&p&那么问题来了,当采用微服务结构后,一个完整的系统可能有很多独立的子系统组成,当业务量渐渐发展起来之后,而这些子系统之间的关系将错综复杂,而且为了能够针对性地增加某些服务的处理能力,某些服务的背后可能是一个集群模式,由多个节点构成,这无疑大大增加了运维的难度。微服务的想法好是好,但开发、运维的复杂度实在是太高。为了解决这些问题,阿里巴巴的Dubbo就横空出世了。&/p&&h2&知识点2:Dubbo&/h2&&p&Dubbo是一套微服务系统的协调者,在它这套体系中,一共有三种角色,分别是:服务提供者(下面简称提供者)、服务消费者(下面简称消费者)、注册中心。&/p&&p&你在使用的时候需要将Dubbo的jar包引入到你的项目中,也就是每个服务都要引入Dubbo的jar包。然后当这些服务初始化的时候,Dubbo就会将当前系统需要发布的服务、以及当前系统的IP和端口号发送给注册中心,注册中心便会将其记录下来。这就是服务发布的过程。与此同时,也是在系统初始化的时候,Dubbo还会扫描一下当前系统所需要引用的服务,然后向注册中心请求这些服务所在的IP和端口号。接下来系统就可以正常运行了。当系统A需要调用系统B的服务的时候,A就会与B建立起一条RPC信道,然后再调用B系统上相应的服务。&/p&&p&这,就是Dubbo的作用。&/p&&h2&知识点3:容器化部署&/h2&&p&当我们使用了微服务架构后,我们将一个原本完整的系统,按照业务逻辑拆分成一个个可独立运行的子系统。为了降低系统间的耦合度,我们希望这些子系统能够运行在独立的环境中,这些环境之间能够相互隔离。&/p&&p&在Docker出现之前,若使用虚拟机来实现运行环境的相互隔离的话成本较高,虚拟机会消耗较多的计算机硬件/软件资源。Docker不仅能够实现运行环境的隔离,而且能极大程度的节约计算机资源,它成为一种轻量级的“虚拟机”。&/p&&h2&知识点4:自动化构建&/h2&&p&当我们使用微服务架构后,随着业务的逐渐发展,系统之间的依赖关系会日益复杂,而且各个模块的构建顺序都有所讲究。对于一个小型系统来说,也许只有几个模块,那么你每次采用人肉构建的方式也许并不感觉麻烦。但随着系统业务的发展,你的系统之间的依赖关系日益复杂,子系统也逐渐增多,每次构建一下你都要非常小心谨慎,稍有不慎整个服务都无法正常启动。而且这些构建的工作很low,但却需要消耗大量的精力,这无疑降低了开发的效率。不过没关系,Jenkins就是来帮助你解决这个问题的。&/p&&p&我们只需在Jenkins中配置好代码仓库、各个模块的构建顺序和构建命令,在以后的构建中,只需要点击“立即构建”按钮,Jenkins就会自动到你的代码仓库中拉取最新的代码,然后根据你事先配置的构建命令进行构建,最后发布到指定的容器中运行。你也可以让Jenkins定时检查代码仓库版本的变化,一旦发现变动就自动地开始构建过程,并且让Jenkins在构建成功后给你发一封邮件。这样你连“立即构建”的按钮也不需要按,就能全自动地完成这一切构建过程。&/p&&hr&&h2&实战动手篇&/h2&&h2&1. 学习目标&/h2&&p&接下来我会带着大家,以一个在线商城为例,搭建一套能够自动化部署的微服务框架。这个框架能做如下几件事情:&/p&&ol&&li&基于SpringBoot快速开发 我们将选择目前热度很高的SpringBoot,最大限度地降低配置复杂度,把大量的精力投入到我们的业务开发中来。&/li&&li&基于Dubbo的微服务化 我们会使用阿里巴巴的开源框架Dubbo,将我们的系统拆分成多个独立的微服务,然后用Dubbo来管理所有服务的发布和引用。有了Dubbo之后,调用远程服务就像调用一个本地函数一样简单,Dubbo会帮我们完成远程调用背后所需要的一切。&/li&&li&基于Docker的容器化部署 由于使用了微服务架构后,我们的系统将会由很多子系统构成。为了达到多个系统之间环境隔离的目的,我们可以将它们部署在多台服务器上,可这样的成本会比较高,而且每台服务器的性能可能都没有充分利用起来。所以我们很自然地想到了虚拟机,在同一台服务器上运行多个虚拟机,从而实现环境的隔离,每个虚拟机上运行独立的服务。然而虚拟机的隔离成本依旧很高,因为它需要占用服务器较多的硬件资源和软件资源。所以,在微服务结构下,要实现服务环境的隔离,Docker是最佳选择。它比虚拟机更加轻量级,占用资源较少,而且能够实现快速部署。&/li&&li&基于Jenkins的自动化构建 当我们采用了微服务架构后,我们会发现这样一个问题。整个系统由许许多多的服务构成,这些服务都需要运行在单独的容器中,那么每次发布的复杂度将非常高。首先你要搞清楚这些服务之间的依赖关系、启动的先后顺序,然后再将多个子系统挨个编译、打包、发布。这些操作技术难度低,却又容易出错。那么有什么工具能够帮助我们解决这些问题呢?答案就是——Jenkins。 它是一款自动化构建的工具,简单的来说,就是我们只需要在它的界面上按一个按钮,就可以实现上述一系列复杂的过程。&/li&&/ol&&h2&2. 项目背景介绍&/h2&&p&本文我以一个大家都非常熟悉的在线商城作为例子,一步步教大家如何搭建微服务框架,它有如下功能:&/p&&ul&&li&产品管理&br&产品的增删改查。&/li&&li&订单管理&br&订单的增删改查、购物车功能。&/li&&li&用户管理&br&用户的登录、注册、权限管理、收货地址等等。&/li&&li&数据分析&br&提供对本系统数据分析的功能。&/li&&/ul&&blockquote&注意:本文的IDE使用的是intelliJ IDEA,推荐大家也用这个,用了都说好,用了你就会爱上它。&/blockquote&&h2&3. 创建项目的组织结构&/h2&&p&在动手之前,我先来说一说这一步的目标:&/p&&ul&&li&创建一个Maven Project,命名为“Gaoxi”&br&这个Project由多个Module构成,每个Module对应着“微服务”的一个子系统,可独立运行,是一个独立的项目。 这也是目前主流的项目组织形式,即多模块项目。&/li&&li&在Gaoxi这个项目下创建各个子模块,每个自模块都是一个独立的SpringBoot项目:&/li&&ul&&li&Gaoxi-User 用户服务&/li&&li&Gaoxi-Order 订单服务&/li&&li&Gaoxi-Product 产品服务&/li&&li&Gaoxi-Analysis 数据分析服务&/li&&li&Gaoxi-Controller 本系统的控制层,和以往三层结构中的Controller层的作用一样,都是用作请求调度,只不过在微服务架构中,我们将它抽象成一个单独的系统,可以独立运行。&/li&&li&Gaoxi-Common-Service-Facade 它处于本系统的最底层,被所有模块依赖,一些公用的类库都放在这里。&/li&&li&Gaoxi-Redis 我们将Redis封装成一个单独的服务,运行在独立的容器中,当哪一个模块需要使用Redis的时候,仅需要引入该服务即可,就免去了各种繁琐的、重复的配置。而这些配置均在Gaoxi-Redis系统中完成了。&/li&&/ul&&/ul&&figure&&img src=&https://pic3.zhimg.com/v2-4f8c0e95dda_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&312& data-rawheight=&151& class=&content_image& width=&312&&&/figure&&p&下面开始动手。&/p&&h2&3.1 创建Project&/h2&&ul&&li&New一个Project&/li&&/ul&&figure&&img src=&https://pic3.zhimg.com/v2-ac60c76dbb78ee2fb17658e_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&615& data-rawheight=&541& class=&origin_image zh-lightbox-thumb& width=&615& data-original=&https://pic3.zhimg.com/v2-ac60c76dbb78ee2fb17658e_r.jpg&&&/figure&&ul&&li&选择Spring Initializr&/li&&/ul&&figure&&img src=&https://pic2.zhimg.com/v2-cf363d1cde67a5de86b41d9d_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&844& data-rawheight=&573& class=&origin_image zh-lightbox-thumb& width=&844& data-original=&https://pic2.zhimg.com/v2-cf363d1cde67a5de86b41d9d_r.jpg&&&/figure&&ul&&li&设置groupId、artifactId、version&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi&/artifactId&
&version&0.0.1-SNAPSHOT&/version&
&/code&&/pre&&/div&&ul&&li&Project创建完毕!接下来在Project下面创建Module&/li&&/ul&&h2&3.2 创建Module&/h2&&ul&&li&在Project上New Module&/li&&/ul&&figure&&img src=&https://pic3.zhimg.com/v2-73a1cd1a41a_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&683& data-rawheight=&240& class=&origin_image zh-lightbox-thumb& width=&683& data-original=&https://pic3.zhimg.com/v2-73a1cd1a41a_r.jpg&&&/figure&&ul&&li&和刚才一样,选择Spring Initializr,设置groupId、artifactId、version&/li&&li&依次创建好所有的Module,如下图所示: &/li&&/ul&&figure&&img src=&https://pic1.zhimg.com/v2-11abe1e66abdb04_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&313& data-rawheight=&336& class=&content_image& width=&313&&&/figure&&p&&br&&/p&&h2&3.3 构建模块的依赖关系&/h2&&p&目前为止,模块之间没有任何联系,下面我们要通过pom文件来指定它们之间的依赖关系,依赖关系如下图所示: &/p&&figure&&img src=&https://pic1.zhimg.com/v2-0eb55dc2fd4d5ee7e384bcba9b6e5e80_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&512& data-rawheight=&230& class=&origin_image zh-lightbox-thumb& width=&512& data-original=&https://pic1.zhimg.com/v2-0eb55dc2fd4d5ee7e384bcba9b6e5e80_r.jpg&&&/figure&&p&Gaoxi-User、Gaoxi-Analysis、Gaoxi-Product、Gaoxi-Order这四个系统相当于以往三层结构的Service层,提供系统的业务逻辑,只不过在微服务结构中,Service层的各个模块都被抽象成一个个单独的子系统,它们提供RPC接口供上面的Gaoxi-Controller调用。它们之间的调用由Dubbo来完成,所以它们的pom文件中并不需要作任何配置。而这些模块和Gaoxi-Common-Service-Facade之间是本地调用,因此需要将Gaoxi-Common-Service-Facade打成jar包,并让这些模块依赖这个jar,因此就需要在所有模块的pom中配置和Gaoxi-Common-Service-Facade的依赖关系。&/p&&p&此外,为了简化各个模块的配置,我们将所有模块的通用依赖放在Project的pom文件中,然后让所有模块作为Project的子模块。这样子模块就可以从父模块中继承所有的依赖,而不需要自己再配置了。&/p&&p&下面开始动手:&/p&&ul&&li&首先将Common-Service-Facade的打包方式设成jar&br&当打包这个模块的时候,Maven会将它打包成jar,并安装在本地仓库中。这样其他模块打包的时候就可以引用这个jar。&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi-common-service-facade&/artifactId&
&version&0.0.1&/version&
&packaging&jar&/packaging&
&/code&&/pre&&/div&&ul&&li&将其他模块的打包方式设为war&br&除了Gaoxi-Common-Service-Facade外,其他模块都是一个个可独立运行的子系统,需要在web容器中运行,所以我们需要将这些模块的打包方式设成war&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi-user&/artifactId&
&version&0.0.1-SNAPSHOT&/version&
&packaging&war&/packaging&
&/code&&/pre&&/div&&ul&&li&在总pom中指定子模块&br&modules标签指定了当前模块的子模块是谁,但是仅在父模块的pom文件中指定子模块还不够,还需要在子模块的pom文件中指定父模块是谁。&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&modules&
&module&Gaoxi-Analysis&/module&
&module&Gaoxi-Order&/module&
&module&Gaoxi-Product&/module&
&module&Gaoxi-User&/module&
&module&Gaoxi-Redis&/module&
&module&Gaoxi-Controller&/module&
&module&Gaoxi-Common-Service-Facade&/module&
&/modules&
&/code&&/pre&&/div&&ul&&li&在子模块中指定父模块&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&parent&
&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi&/artifactId&
&version&0.0.1-SNAPSHOT&/version&
&relativePath&../pom.xml&/relativePath&
&/code&&/pre&&/div&&blockquote&到此为止,模块的依赖关系配置完毕!但要注意模块打包的顺序。由于所有模块都依赖于Gaoxi-Common-Servie-Facade模块,因此在构建模块时,首先需要编译、打包、安装Gaoxi-Common-Servie-Facade,将它打包进本地仓库中,这样上层模块才能引用到。当该模块安装完毕后,再构建上层模块。否则在构建上层模块的时候会出现找不到Gaoxi-Common-Servie-Facade中类库的问题。&/blockquote&&h2&3.4 在父模块的pom中添加所有子模块公用的依赖&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&dependencies&
&!-- Spring Boot --&
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter&/artifactId&
&/dependency&
&!-- Spring MVC --&
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-web&/artifactId&
&/dependency&
&!-- Spring Boot Test --&
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-test&/artifactId&
&scope&test&/scope&
&/dependency&
&!-- MyBatis --&
&dependency&
&groupId&org.mybatis.spring.boot&/groupId&
&artifactId&mybatis-spring-boot-starter&/artifactId&
&version&1.3.1&/version&
&/dependency&
&!-- Mysql --&
&dependency&
&groupId&mysql&/groupId&
&artifactId&mysql-connector-java&/artifactId&
&scope&runtime&/scope&
&/dependency&
&!-- Dubbo --&
&dependency&
&groupId&io.dubbo.springboot&/groupId&
&artifactId&spring-boot-starter-dubbo&/artifactId&
&version&1.0.0&/version&
&/dependency&
&!-- gaoxi-common-service-facade --&
&dependency&
&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi-common-service-facade&/artifactId&
&version&0.0.1&/version&
&/dependency&
&!-- AOP --&
&dependency&
&groupId&org.springframework.boot&/groupId&
&artifactId&spring-boot-starter-aop&/artifactId&
&/dependency&
&!-- guava --&
&dependency&
&groupId&com.google.guava&/groupId&
&artifactId&guava&/artifactId&
&version&23.3-jre&/version&
&/dependency&
&/dependencies&
&/code&&/pre&&/div&&p&当父模块的pom中配置了公用依赖后,子模块的pom文件将非常简洁,如下所示:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi-user&/artifactId&
&version&0.0.1-SNAPSHOT&/version&
&packaging&war&/packaging&
&name&gaoxi-user&/name&
&groupId&com.gaoxi&/groupId&
&artifactId&gaoxi&/artifactId&
&version&0.0.1-SNAPSHOT&/version&
&relativePath&../pom.xml&/relativePath&
&/code&&/pre&&/div&&p&当项目的结构搭建完成之后,接下来你需要配置Docker环境,并将这些项目打包进容器中,验证下是否能正常启动。&/p&&h2&4. 创建Docker容器&/h2&&h2&4.1 安装Docker&/h2&&p&在使用Docker之前,你当然先要安装Docker,安装过程较为简单,基本上就是傻瓜式操作,这里就不作过多介绍了,你可以在Docker的官网下载相应系统的安装包。 &a href=&http://link.zhihu.com/?target=https%3A//www.docker.com/& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&docker.com/&/span&&span class=&invisible&&&/span&&/a&&/p&&h2&4.2 获取Tomcat镜像&/h2&&p&在微服务架构中,一个完整的系统被拆分成了多个被称为“微服务”的子系统,这些子系统可以独立运行在Web容器中。所以我们需要为这些系统提供运行的Web容器,这里我们选择大家较为熟悉的Tomcat。&/p&&p&我们知道,Tomcat依赖于Java环境,安装Tomcat之前要进行一系列环境的配置:安装Java、配置环境变量、安装Tomcat等等。这些操作还是有些繁琐的。不过没关系,当使用了Docker之后,这些过程都可以轻而易举地完成。&/p&&p&我们只需从Docker Hub上找到Tomcat的镜像资源,然后从上面拉取下来就可以使用。你可以使用Tomcat官方的镜像,也可以使用我发布在Docker Hub上的Tomcat镜像。&/p&&blockquote&注意点:推荐使用我的Tomcat镜像资源chaimm/tomcat,因为这个镜像中除了配置Tomcat的安装环境以外,还有一些本项目中要用到的Jenkins相关的配置。&/blockquote&&p&采用如下命令从Docker Hub上拉取镜像:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&docker pull chaimm/tomcat:1.1
&/code&&/pre&&/div&&p&简单解释下,docker pull是从从Docker Hub上拉取镜像的命令,后面的chaimm/tomcat是镜像的名称,:1.1是镜像的版本号。目前这个镜像的最新版本号是1.1,推荐大家拉取这个。&/p&&h2&4.3 创建Tomcat容器&/h2&&p&这里再简单介绍下“镜像”和“容器”的关系。 “镜像”就好比是面向对象中的“类”,“容器”就好比“类”创建的“对象”。在面向对象中,“类”定义了各种属性,“类”可以实例化出多个“对象”;而在Docker中,“镜像”定义了各种配置信息,它可以实例化出多个“容器”。“容器”就是一台可以运行的“虚拟机”。&/p&&p&接下来我们需要为所有的微服务创建各自的容器:&/p&&ul&&li&gaoxi-user&/li&&li&gaoxi-product&/li&&li&gaoxi-order&/li&&li&gaoxi-analysis&/li&&li&gaoxi-controller&/li&&li&gaoxi-redis&/li&&/ul&&p&以创建gaoxi-user容器为例,采用如下命令创建容器:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&docker run --name gaoxi-user-1 -p
-v /usr/web/gaoxi-log:/opt/tomcat/gaoxi-log chaimm/tomcat:1.1
&/code&&/pre&&/div&&ul&&li&--name:指定容器的名字&/li&&li&-p:指定容器的端口映射 -p
表示将容器的8080端口映射到宿主机的8082端口上&/li&&li&-v:指定容器数据卷的映射 xxx:yyy 表示将容器yyy目录映射到宿主机的xxx目录上,从而访问宿主机的xxx目录就相当于访问容器的yyy目录。&/li&&li&chaimm/tomcat:1.1:表示容器所对应的镜像。&/li&&/ul&&p&这条命令执行成功后,你就可以通过&code&你的IP:8082&/code& 访问到gaoxi-user-1容器的tomcat了。如果你看到了那只眼熟了猫,那就说明容器启动成功了! &/p&&figure&&img src=&https://pic1.zhimg.com/v2-7ae15cd5abaa46dc9ea819c20d11a25c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1024& data-rawheight=&288& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&https://pic1.zhimg.com/v2-7ae15cd5abaa46dc9ea819c20d11a25c_r.jpg&&&/figure&&p&&br&&/p&&p&接下来,你需要按照上面的方法,给剩下几个系统创建好Tomcat容器。&/p&&blockquote&注意点:这里要注意的是,你需要给这些Tomcat容器指定不同的端口号,防止端口号冲突。当然,在实际开发中,你并不需要将容器的8080端口映射到宿主机上,这里仅仅是为了验证容器是否启动成功才这么做的。&/blockquote&&h2&5. 整合Dubbo&/h2&&h2&5.1 创建zookeeper容器&/h2&&p&Dubbo一共定义了三种角色,分别是:服务提供者、服务消费者、注册中心。注册中心是服务提供者和服务消费者的桥梁,服务消费者会在初始化的时候将自己的IP和端口号发送给注册中心,而服务消费者通过注册中心知道服务提供者的IP和端口号。&/p&&p&在Dubbo中,注册中心有多种选择,Dubbo最为推荐的即为ZooKeeper,本文采用ZooKeepeer作为Dubbo的注册中心。&/p&&p&创建ZooKeeper容器也较为简单,大家可以直接使用我创建的ZooKeeper镜像,通过如下命令即可下载镜像:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&docker pull chaimm/zookeeper-dubbo:1.0
&/code&&/pre&&/div&&p&该镜像中不仅运行了一个zookeeper,还运行了一个拥有dubbo-admin项目的tomcat。dubbo-admin是Dubbo的一个可视化管理工具,可以查看服务的发布和引用的情况。&/p&&p&使用如下命令启动容器:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&docker run --name zookeeper-debug -p
chaimm/zookeeper-dubbo:1.0
&/code&&/pre&&/div&&ul&&li&-p :将容器的2181端口映射到宿主机的2182端口上,该端口是ZooKeeper的端口号。&/li&&li&-p :将容器的8080端口映射到宿主机的10000端口上,该端口是Dubbo-Admin所在Tomcat的端口号。&/li&&/ul&&p&启动成功后,你就可以通过&code&你的IP:10000/dubbo-admin-2.8.4/&/code&访问到Dubbo-Admin,如下图所示: &/p&&figure&&img src=&https://pic2.zhimg.com/v2-a78bdf24ad9_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&531& data-rawheight=&214& class=&origin_image zh-lightbox-thumb& width=&531& data-original=&https://pic2.zhimg.com/v2-a78bdf24ad9_r.jpg&&&/figure&&h2&5.2 父pom文件中引入dubbo依赖&/h2&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&&!-- Spring Boot Dubbo 依赖 --&
&dependency&
&groupId&io.dubbo.springboot&/groupId&
&artifactId&spring-boot-starter-dubbo&/artifactId&
&version&1.0.0&/version&
&/dependency&
&/code&&/pre&&/div&&h2&5.3 发布服务&/h2&&blockquote&假设,我们需要将Gaoxi-User项目中的UserService发布成一项RPC服务,供其他系统远程调用,那么我们究竟该如何借助Dubbo来实现这一功能呢?&/blockquote&&ul&&li&在Gaoxi-Common-Service-Facade中定义UserService的接口&br&由于服务的发布和引用都依赖于接口,但服务的发布方和引用方在微服务架构中往往不在同一个系统中,所以需要将需要发布和引用的接口放在公共类库中,从而双方都能够引用。接口如下所示:&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&public interface UserService {
public UserEntity login(LoginReq loginReq);
&/code&&/pre&&/div&&ul&&li&在Gaoxi-User中定义接口的实现&br&在实现类上需要加上Dubbo的@Service注解,从而Dubbo会在项目启动的时候扫描到该注解,将它发布成一项RPC服务。&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&@Service(version = &1.0.0&)
public class UserServiceImpl implements UserService {
public UserEntity login(LoginReq loginReq) {
// 具体的实现代码
&/code&&/pre&&/div&&ul&&li&在Gaoxi-User的application.properties中配置服务提供者的信息&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&spring.dubbo.application.name=user-provider # 本服务的

我要回帖

更多关于 https www.778ddcom 的文章

 

随机推荐