我在sql数据库备份方法的文件是 123.sql.7z 我直接删除.7z变成 sql文件可以吗?还是要做转换

&p&作者:团子s1&/p&&p&链接:&a href=&https://link.zhihu.com/?target=https%3A//www.nowcoder.com/discuss/94656& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&nowcoder.com/discuss/94&/span&&span class=&invisible&&656&/span&&span class=&ellipsis&&&/span&&/a&&/p&&p&来源:牛客网&/p&&p&&br&&/p&&p&看了牛客网上那么多面筋,回馈一波儿&/p&&p&1面(48分钟):基础+项目&/p&&p&自我介绍,项目介绍,遇到的最大困难是什么?怎么解决的?你觉得你能怎么优化这个项目?&/p&&p&1)讲一下JVM&/p&&p&2)讲一下JVM的分代回收以及具体算法&/p&&p&3)将一下JVM的垃圾收集器,G1和CMS有啥区别?&/p&&p&4)讲一下一个变量从产生到结束所经历的过程,讲一下字符串常量的过程?&/p&&p&5)将一下线程安全问题产生的原因?&/p&&p&6)讲一下乐观锁和悲观锁&/p&&p&7)乐观锁是怎么保证一致性的&/p&&p&8)Integer和int有啥区别,integer中有哪些特殊的函数?&/p&&p&9)讲一下数据库的隔离等级&/p&&p&10)说一下MVCC&/p&&p&11)说一聚簇索引和非聚簇索引的有什么不同&/p&&p&2面(1h):主要聊项目,基础问得不多&/p&&p&主要怼项目,你做过哪些项目,用过哪些技术?你为什么读研?了解哪些框架?你觉得对你技术提升最高的是哪一件事情,提升了你哪一方面的技术?&/p&&p&1)讲一下Spring AOP和IOC的底层实现&/p&&p&2)说一下hashcode的作用?HashMap的底层实现?HashMap和HashTable的区别&/p&&p&3)说一下concurrentHashMap和hashTable在性能上的区别?以及这种差异形成的原因&/p&&p&4)讲一下堆以及堆排序&/p&&p&5)说一下B+tree和二叉搜索树的区别?说一下二叉搜索树和AVL树、红黑树之间的差别&/p&&p&6)给你两个文件(字符串形式的)如何找出他们之间的不同地方?&/p&&p&7)你刚刚说的能怎么优化?&/p&&p&8)知道倒排索引嘛&/p&&p&3面(35分钟):总共四个问题(其实是两个)&/p&&p&1. 给你50亿行字符串,机器4G内存(只能一台机器),找出重复次数最多的那行字符串?(以行为单位,每行不超过10个字符)&/p&&p&2. 一个圆上三个点形成钝角的概率是多少?&/p&&p&3. 假如两个点和圆心形成的圆心角已经是直角,那么第三个和这两个点形成钝角的概率是多少?(接上一题)&/p&&p&4. 快速排序的平均复杂多少?最坏情况是什么?(这个题估计就是缓和一下尴尬的气氛)&/p&&p&吐槽一下三面:本来说好的是机试,但是下午临时打电话过来直接就面了,就这么四个题,面试官普通话也说不标准,很难懂他说的是啥!哎。。。无语&/p&&p&HR面(40分钟):&/p&&p&1)对数据技术与产品部有什么了解?&/p&&p&2)你更愿意从事算法还是开发方面的工作?&/p&&p&3)聊了聊论文&/p&&p&4)聊了聊读研的事儿?&/p&&p&5)讲一讲你遇到过的最大困哪&/p&&p&6)有女朋友嘛?(&b&我老实说了有,然后hr就和我说阿里招聘的时候,一方可能会受另一方影响比较大,哎感觉凉凉&/b&)&/p&&p&HR面带给我的恐惧感是最强的,虽然hr态度很好,但是阿里巴巴HR面刷人是最多的,所以也没抱太大期望,已经走到了这一步,已经没有什么遗憾了,也认清了自己和大佬们的差距。&/p&&p&PS:HR没有给口头offer,也没有问期望薪资,八成是凉得不能再凉了。&/p&&p&记录下阿里的招聘之路与诸位牛油共勉!&/p&&p&&br&&/p&&p&&br&&/p&&p&&b&与作者交流:&a href=&https://link.zhihu.com/?target=https%3A//www.nowcoder.com/discuss%3Ftype%3D2%26order%3D0& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&nowcoder.com/discuss?&/span&&span class=&invisible&&type=2&order=0&/span&&span class=&ellipsis&&&/span&&/a&&/b&&/p&&p&&b&更多笔经面经:&a href=&https://link.zhihu.com/?target=https%3A//www.nowcoder.com/discuss/94656& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://www.&/span&&span class=&visible&&nowcoder.com/discuss/94&/span&&span class=&invisible&&656&/span&&span class=&ellipsis&&&/span&&/a&&/b&&/p&
作者:团子s1链接:来源:牛客网 看了牛客网上那么多面筋,回馈一波儿1面(48分钟):基础+项目自我介绍,项目介绍,遇到的最大困难是什么?怎么解决的?你觉得你能怎么优化这个项目?1)讲一下JVM2)讲一下JVM的分代回收以及具体算法3…
&p&如果我们假设CMU15-721可以代表学术界, 又假设学术界定义了名词概念的话,&/p&&p&那么最常有的混乱是由于OCC不仅指乐观并发控制思想, 还指特定的算法引起的.&/p&&p&&br&&/p&&p&悲观并发控制思想 v.s. 乐观并发控制思想(OCC)&/p&&p&悲观控制唯一的实现是2PL&/p&&p&乐观控制唯一的实现是Timestamps&/p&&p&2PL和Timestamps是唯二解决事务并发的模型.&/p&&p&&br&&/p&&p&Timestamps的实现又分为&/p&&p&Basic T/O, 遵循Thomas Write Rule, 每个transaction不用到commit阶段就立马写进数据结构, 依靠read timestamps和write timestamps检查保证操作序列化.&/p&&p&OCC算法(对, 没错这也叫OCC, 但这叫OCC算法), 所有的操作都在本地完成. 比如, 我Get A, 这不阻塞, A就复制到了本地, 之后所有对于A的操作都是在&private memory space&内, 直到commit的时候, 开始检查冲突, 有正向验证(validation), 也有反向验证, 在一定的时间区间(epoch)内.&/p&&p&题外话: epoch思想还用于epoch GC, 例子BW-Tree. 在一个区间内标记为垃圾的资源, 在这个区间以及之前区间的所有线程都退出后, 就可以释放掉, 不需要引用计数.&/p&&p&MVCC, 百家争鸣. 在不同的isolation level也有不同的表现形式, 共享的思想是通过保存多个版本来解决冲突. 很多人认为这能解决读写冲突和写读冲突, 但这是在Snapshopt Isolation(SI)下的情况. SI会导致Write Skew Anomaly. 现有50个男生, 50个女生. 事务1: 如果男生数量跟女生相同, 赶走所有女生, 换成男生. 事务2: 如果男生数量和女生相同, 赶走所有男生, 换成女生. SI等级下, 结果是毛线都没发生. 但如果我们严格遵守序列化操作, 最后要么只有100个男生, 要么只有100个女生.&/p&&p&所以MVCC是乐观并发控制思想的一种体现, 但不是具体严格的算法. MVCC在数据库系统中必须根据不同的isolation level搭配一些别的CC算法, 比如MySQL InnoDB的MVCC+2PL. 据我不严格判断, MyRocks的默认实现也是这样的.&/p&&p&&br&&/p&&p&还有lock和latch也是经常被误会的. lock保护的是transaction, latch保护的是数据结构. Timestamps是lock-free的, 但实现这个目标的数据结构不一定是latch-free的. 2PL不是lock-free的, 但RocksDB的memtable是latch-free的(吗?).&/p&
如果我们假设CMU15-721可以代表学术界, 又假设学术界定义了名词概念的话,那么最常有的混乱是由于OCC不仅指乐观并发控制思想, 还指特定的算法引起的. 悲观并发控制思想 v.s. 乐观并发控制思想(OCC)悲观控制唯一的实现是2PL乐观控制唯一的实现是Timestamps2PL…
&p&*最简单的并发控制算法是2PL(2 Phase Locking),分为两阶段:&/p&&p&1)获得锁阶段;&/p&&p&2)释放锁阶段。&/p&&p&一般2PL被称为是悲观并发控制。&/p&&p&&br&&/p&&p&与之相对的是乐观并发控制OCC( Optimistic Concurrency Control)。OCC假设事务会成功,开始事务时该读读,该写写,不加锁。只有到提交时做一下验证,验证这个事务是不是能够成功提交。 OCC分为三阶段:&/p&&p&1)Read Phase, 对于读,放到Read Set,对于写,把写记到临时副本,放到Write Set。因为写是写到临时区的,属于未提交结果,其它事务读不到(这点是和MVCC的重要区别);&/p&&p&2)Validation Phase,重扫Read Set,Write Set,检验数据是否满足Isolation Level,如果满足则Commit,否则Abort;&/p&&p&3)WritePhase,或者叫做Commit Phase,把临时副本区的数据更新到数据库中,完成事务提交。&/p&&p&&br&&/p&&p&MVCC(Multiversion Concurrency Control)是另一种并发控制算法。MVCC为每条记录维护多个快照(Snapshot),通过起止两个时间戳(Begin Timestamp / End Timestamp)维护副本的可见性。读写进行的不同操作如下:&/p&&p&Update,创建一个新的版本(Version);&/p&&p&Delete,更新End Timestamp。&/p&&p&Read,通过起止时间戳判定记录是否对当前事务可见(OCC读不到未提交的记录,所以不需要做这个判断)。&/p&&p&这样,通过Snapshot,实现了读写互不阻塞。但为了实现Serializable,对读写规则还是要进行一定的限制。MVCC通过不同的方法实现。有基于锁定的,MV-2PL,如MySQL。有基于时间排序(Time Ordering)的,叫MV-TO,如PostgreSQL。其实准确来说,PG的实现叫SSI(Serializable Snapshot Isolation),不算MV-TO。也有像OCC那样基于乐观算法的,MV-OCC,即读写时不做验证,延迟到提交时验证。&/p&&p&&br&&/p&&p&效率上,2PL读写阻塞,在维护锁开销较小时较好;OCC不维护锁,一些比较新的OCC算法吞吐可以做得很高,不过相应回滚也会比较高,冲突比较小和验证开销小时比较好;MVCC对不同类型的workload都有很好的适应性,读写互不阻塞,回滚率也比OCC好,很多RDBMS也都用MVCC,如Oracle,PostgreSQL,MySQL。还有一个效率问题,随着现在CPU核心数越来越多,考虑并发控制算法往往需要考虑它的多核扩展性好不好。由于多数MVCC,OCC算法都需要时间戳分配,时间戳通常对全局变量进行CAS(Compare And Swap)操作来计算,当核心数变大时,CAS的争用也变大了。&/p&&p&&br&&/p&&p&另外,现在的许多并发控制方法经常混合了多种算法。先有人提出了A,后有人提出了B,再后来就有人提出了A+B,那么A+B应该是叫A呢还是叫B呢?就像上面提到的MV-2PL,MV-TO,MV-OCC。&/p&&p&-------------------------------------&/p&&p&关于并发控制算法怎么分类,有不同的意见。&/p&&p&&br&&/p&&p&《Transactional Information Systems》对并发控制算法的分类。把多版本相对于单版本,作为另一个维度看。多版本可以应用在任一算法上,形成MV-SGT,MV-TO,MV-2PL,MV-OCC等。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-d75fa09daa9e3b64fbc65b1_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&690& data-rawheight=&890& class=&origin_image zh-lightbox-thumb& width=&690& data-original=&https://pic3.zhimg.com/50/v2-d75fa09daa9e3b64fbc65b1_r.jpg&&&/figure&&p&&br&&/p&&p&而&a href=&//link.zhihu.com/?target=http%3A//15721.courses.cs.cmu.edu/spring2017/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&CMU 15-72&/a&2课程里,把并发控制分为两类,2PL和TO,OCC和MVCC都归为TO。&/p&&figure&&img src=&https://pic3.zhimg.com/50/v2-45f296b0b48c63cf5bcd0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&2022& data-rawheight=&1010& class=&origin_image zh-lightbox-thumb& width=&2022& data-original=&https://pic3.zhimg.com/50/v2-45f296b0b48c63cf5bcd0_r.jpg&&&/figure&&figure&&img src=&https://pic2.zhimg.com/50/v2-9d4ed57ba7_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1654& data-rawheight=&1086& class=&origin_image zh-lightbox-thumb& width=&1654& data-original=&https://pic2.zhimg.com/50/v2-9d4ed57ba7_r.jpg&&&/figure&&p&-------------------------------------&/p&&p&感谢 &a class=&member_mention& href=&//www.zhihu.com/people/c21a3538c6cfcf& data-hash=&c21a3538c6cfcf& data-hovercard=&p$b$c21a3538c6cfcf&&@Ed Huang&/a& 纠正关于2PL应用场景的错误&/p&
*最简单的并发控制算法是2PL(2 Phase Locking),分为两阶段:1)获得锁阶段;2)释放锁阶段。一般2PL被称为是悲观并发控制。 与之相对的是乐观并发控制OCC( Optimistic Concurrency Control)。OCC假设事务会成功,开始事务时该读读,该写写,不加锁。只…
数据库要保证运行时崩溃而数据不丢失, 无外乎两种方法, 一是让数据自省, 每次启动时检查完整性, 二是写日志. 99%(可能是100%)的数据库都选择写日志, 因为这样不仅能保证数据安全还比较容易实现事务(LevelDB有弱化版的对应, 叫batch). 接下来分析一下, LevelDB是怎么从日志中恢复数据的.&p&实现在DBImpl::Recover函数中, 先看&a href=&https://link.zhihu.com/?target=http%3A//db_impl.cc& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&db_impl.cc&/span&&span class=&invisible&&&/span&&/a& 275-286行,&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&n&&Status&/span& &span class=&n&&DBImpl&/span&&span class=&o&&::&/span&&span class=&n&&Recover&/span&&span class=&p&&(&/span&&span class=&n&&VersionEdit&/span&&span class=&o&&*&/span& &span class=&n&&edit&/span&&span class=&p&&,&/span& &span class=&kt&&bool&/span& &span class=&o&&*&/span&&span class=&n&&save_manifest&/span&&span class=&p&&)&/span& &span class=&p&&{&/span&
&span class=&n&&mutex_&/span&&span class=&p&&.&/span&&span class=&n&&AssertHeld&/span&&span class=&p&&();&/span&
&span class=&c1&&// Ignore error from CreateDir since the creation of the DB is&/span&
&span class=&c1&&// committed only when the descriptor is created, and this directory&/span&
&span class=&c1&&// may already exist from a previous failed creation attempt.&/span&
&span class=&n&&env_&/span&&span class=&o&&-&&/span&&span class=&n&&CreateDir&/span&&span class=&p&&(&/span&&span class=&n&&dbname_&/span&&span class=&p&&);&/span& &span class=&c1&&// 有可能是第一次打开数据库, 尝试创建目录&/span&
&span class=&n&&assert&/span&&span class=&p&&(&/span&&span class=&n&&db_lock_&/span& &span class=&o&&==&/span& &span class=&nb&&NULL&/span&&span class=&p&&);&/span&
&span class=&n&&Status&/span& &span class=&n&&s&/span& &span class=&o&&=&/span& &span class=&n&&env_&/span&&span class=&o&&-&&/span&&span class=&n&&LockFile&/span&&span class=&p&&(&/span&&span class=&n&&LockFileName&/span&&span class=&p&&(&/span&&span class=&n&&dbname_&/span&&span class=&p&&),&/span& &span class=&o&&&&/span&&span class=&n&&db_lock_&/span&&span class=&p&&);&/span& &span class=&c1&&// FileLock* db_lock_&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&s&/span&&span class=&p&&.&/span&&span class=&n&&ok&/span&&span class=&p&&())&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&s&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&LevelDB的数据库(文件)是一个文件夹, 如果有多个程序打开这个数据库肯定糟糕了. 那怎么确保一个实例能稳定霸占一个文件夹呢? 跟所有别的程序一样, 建立一个单独的文件, 以独占的方式打开作为LOCK. 每个实例都要尝试创建/拥有这个锁文件, 如果失败了, 说明有别的实例在使用这个数据库.&/p&&p&db_lock_看着很唬人, 其实就是一个简单的结构体, 保存了fd和文件名.&/p&&p&&a href=&https://link.zhihu.com/?target=http%3A//env_posix.cc& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&env_posix.cc&/span&&span class=&invisible&&&/span&&/a& 302-306行,&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&k&&class&/span& &span class=&nc&&PosixFileLock&/span& &span class=&o&&:&/span& &span class=&k&&public&/span& &span class=&n&&FileLock&/span& &span class=&p&&{&/span&
&span class=&k&&public&/span&&span class=&o&&:&/span&
&span class=&kt&&int&/span& &span class=&n&&fd_&/span&&span class=&p&&;&/span&
&span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&string&/span& &span class=&n&&name_&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&/code&&/pre&&/div&&p&&b&有点值得注意的是Google完全不在乎虚函数的开销!&/b& 知乎上对于虚函数性能的争论可以钦定一下了. FileLock是一个纯虚类, 什么方法都没定义! 仅仅禁止了复制构造! PosixFileLock就是一个简单结构体.&/p&&p&理论上来说, 完全没必要用虚函数. 结果, 虚函数不仅这里用, LevelDB到处都是虚函数, 一个接口对应一个实现也要用虚函数. 喜闻乐见的模板消除虚函数大法毫无用武之地.&/p&&blockquote&要虚函数, 不要模板和宏&br&&/blockquote&&p&网上还有文章指出不应该用虚函数作为库的接口, LevelDB再次违反规定, 整个对外暴露的db类, 全都是虚函数...&/p&&p&可见, 工程实践和理论分析是有差别的. 模板用了一堆, 性能没高多少, 可读性直线下降, 暴力模不可取. 不过, Google的代码也不是完美的, 很多虚函数就是纯属浪费时间, 比如我刚刚举例的结构体继承了一个只禁止复制的纯虚类? realllllly?&/p&&p&------&/p&&p&继续, &a href=&https://link.zhihu.com/?target=http%3A//db_impl.cc& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&db_impl.cc&/span&&span class=&invisible&&&/span&&/a& 288-297行,&/p&&br&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span& &span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&env_&/span&&span class=&o&&-&&/span&&span class=&n&&FileExists&/span&&span class=&p&&(&/span&&span class=&n&&CurrentFileName&/span&&span class=&p&&(&/span&&span class=&n&&dbname_&/span&&span class=&p&&)))&/span& &span class=&p&&{&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&options_&/span&&span class=&p&&.&/span&&span class=&n&&create_if_missing&/span&&span class=&p&&)&/span& &span class=&p&&{&/span& &span class=&c1&&// 没有CURRENT文件, 新建数据库&/span&
&span class=&n&&s&/span& &span class=&o&&=&/span& &span class=&n&&NewDB&/span&&span class=&p&&();&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&s&/span&&span class=&p&&.&/span&&span class=&n&&ok&/span&&span class=&p&&())&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&s&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span& &span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&Status&/span&&span class=&o&&::&/span&&span class=&n&&InvalidArgument&/span&&span class=&p&&(&/span&
&span class=&n&&dbname_&/span&&span class=&p&&,&/span& &span class=&s&&&does not exist (create_if_missing is false)&&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&跟入NewDB()代码, 178-208行,&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&n&&Status&/span& &span class=&n&&DBImpl&/span&&span class=&o&&::&/span&&span class=&n&&NewDB&/span&&span class=&p&&()&/span& &span class=&p&&{&/span&
&span class=&n&&VersionEdit&/span& &span class=&n&&new_db&/span&&span class=&p&&;&/span&
&span class=&n&&new_db&/span&&span class=&p&&.&/span&&span class=&n&&SetComparatorName&/span&&span class=&p&&(&/span&&span class=&n&&user_comparator&/span&&span class=&p&&()&/span&&span class=&o&&-&&/span&&span class=&n&&Name&/span&&span class=&p&&());&/span& &span class=&c1&&// 防止用不同comparator打开数据库&/span&
&span class=&n&&new_db&/span&&span class=&p&&.&/span&&span class=&n&&SetLogNumber&/span&&span class=&p&&(&/span&&span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&n&&new_db&/span&&span class=&p&&.&/span&&span class=&n&&SetNextFile&/span&&span class=&p&&(&/span&&span class=&mi&&2&/span&&span class=&p&&);&/span& &span class=&c1&&// 硬盘文件名后缀, manifest已经占用1了, 所以这里要是2&/span&
&span class=&n&&new_db&/span&&span class=&p&&.&/span&&span class=&n&&SetLastSequence&/span&&span class=&p&&(&/span&&span class=&mi&&0&/span&&span class=&p&&);&/span&
&span class=&k&&const&/span& &span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&string&/span& &span class=&n&&manifest&/span& &span class=&o&&=&/span& &span class=&n&&DescriptorFileName&/span&&span class=&p&&(&/span&&span class=&n&&dbname_&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&);&/span&
&span class=&n&&WritableFile&/span&&span class=&o&&*&/span& &span class=&n&&file&/span&&span class=&p&&;&/span&
&span class=&n&&Status&/span& &span class=&n&&s&/span& &span class=&o&&=&/span& &span class=&n&&env_&/span&&span class=&o&&-&&/span&&span class=&n&&NewWritableFile&/span&&span class=&p&&(&/span&&span class=&n&&manifest&/span&&span class=&p&&,&/span& &span class=&o&&&&/span&&span class=&n&&file&/span&&span class=&p&&);&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&o&&!&/span&&span class=&n&&s&/span&&span class=&p&&.&/span&&span class=&n&&ok&/span&&span class=&p&&())&/span& &span class=&p&&{&/span&
&span class=&k&&return&/span& &span class=&n&&s&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&p&&{&/span&
&span class=&n&&log&/span&&span class=&o&&::&/span&&span class=&n&&Writer&/span& &span class=&n&&log&/span&&span class=&p&&(&/span&&span class=&n&&file&/span&&span class=&p&&);&/span&
&span class=&n&&std&/span&&span class=&o&&::&/span&&span class=&n&&string&/span& &span class=&n&&record&/span&&span class=&p&&;&/span&
&span class=&n&&new_db&/span&&span class=&p&&.&/span&&span class=&n&&EncodeTo&/span&&span class=&p&&(&/span&&span class=&o&&&&/span&&span class=&n&&record&/span&&span class=&p&&);&/span& &span class=&c1&&// 将VersionEdit序列化&/span&
&span class=&n&&s&/span& &span class=&o&&=&/span& &span class=&n&&log&/span&&span class=&p&&.&/span&&span class=&n&&AddRecord&/span&&span class=&p&&(&/span&&span class=&n&&record&/span&&span class=&p&&);&/span& &span class=&c1&&// 写入硬盘&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&s&/span&&span class=&p&&.&/span&&span class=&n&&ok&/span&&span class=&p&&())&/span& &span class=&p&&{&/span&
&span class=&n&&s&/span& &span class=&o&&=&/span& &span class=&n&&file&/span&&span class=&o&&-&&/span&&span class=&n&&Close&/span&&span class=&p&&();&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&k&&delete&/span& &span class=&n&&file&/span&&span class=&p&&;&/span&
&span class=&k&&if&/span& &span class=&p&&(&/span&&span class=&n&&s&/span&&span class=&p&&.&/span&&span class=&n&&ok&/span&&span class=&p&&())&/span& &span class=&p&&{&/span&
&span class=&c1&&// Make &CURRENT& file that points to the new manifest file.&/span&
&span class=&n&&s&/span& &span class=&o&&=&/span& &span class=&n&&SetCurrentFile&/span&&span class=&p&&(&/span&&span class=&n&&env_&/span&&span class=&p&&,&/span& &span class=&n&&dbname_&/span&&span class=&p&&,&/span& &span class=&mi&&1&/span&&span class=&p&&);&/span& &span class=&c1&&// CURRENT文件承担了一个引导的作用&/span&
&span class=&p&&}&/span& &span class=&k&&else&/span& &span class=&p&&{&/span&
&span class=&n&&env_&/span&&span class=&o&&-&&/span&&span class=&n&&DeleteFile&/span&&span class=&p&&(&/span&&span class=&n&&manifest&/span&&span class=&p&&);&/span&
&span class=&p&&}&/span&
&span class=&k&&return&/span& &span class=&n&&s&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&p&如果说这里让你学到了什么数据库以外的东西, 那就是把问题扔给操作系统吧. 锁/引导都用文件系统的原子性和健壮性解决.&/p&&p&------&/p&&p&VersionEdit在LevelDB是什么个概念?&/p&&p&由于LSM Tree没有任何主索引体系, 只要Log+SSTable正确, 就一定能得出正确的结果. 所以不同version之间的差别就是SSTable的差别, A版本到B版本, 可能就是删除名叫e, d, f的SSTable, 再加上o, p, q的SSTable. 这就天然具有了超强的健壮性! &/p&&p&VersionEdit_t0 + VersionEdit_t1 = Data_t1&/p&&br&&p&管理如此众多SSTable的任务可以直接甩锅给文件系统, 也就不难理解LevelDB的超强性能了.&/p&
数据库要保证运行时崩溃而数据不丢失, 无外乎两种方法, 一是让数据自省, 每次启动时检查完整性, 二是写日志. 99%(可能是100%)的数据库都选择写日志, 因为这样不仅能保证数据安全还比较容易实现事务(LevelDB有弱化版的对应, 叫batch). 接下来分析一下, Level…
&p&&/p&&hr&&h2&我们的程序是如何被运行的?&/h2&&p&学习过操作系统的人,应该对进程和线程的模型都是有所了解的。按照我的理解:「进程」是操作系统资源分配的基本单位,它给程序提供了一个良好的运行环境。「线程」则是一个轻量级的进程,一个「进程」中可以有很多线程,但是最终在一个 CPU 的核上只能有一个「进程」的其中一个「线程」被执行。所以,我们的一个程序的执行过程可以粗略的理解为:&/p&&ol&&li&程序的可执行文件被 Load 到内存中&/li&&li&创建进程&创建主线程&/li&&li&主线程被 OS 调度到合适的 CPU 执行&/li&&/ol&&h2&goroutine 是什么?&/h2&&p&看了很多文章对于 goroutine 的描述,其中出现最多的一句话就是「The goroutine is a lightweight thread.」。在结合了对操作系统的线程模型的理解之后,我觉得 goroutine 就是一个在用户空间(usernamespace)下实现的「线程」,它由 golang 的 runtime 进行管理。goroutine 和 go runtime 的关系可以直接的类比于线程和操作系统内核的关系。至于它是不是轻量级,这需要和操作系统的线程进行对比之后才能够知道。在此我们先避免「人云亦云」。&/p&&h2&goroutine 和 thread 有什么不同?&/h2&&p&目前看起来 goroutine 和 thread 在实现的思路上是比较相似的。但是为什么说 goroutine 比 thread 要轻量呢?从字面的意思上来理解,「轻量」肯定意味着消耗的系统资源变少了。&/p&&h2&内存消耗&/h2&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-7437764edc60fdf86dbd08_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&960& data-rawheight=&540& class=&origin_image zh-lightbox-thumb& width=&960& data-original=&https://pic1.zhimg.com/v2-7437764edc60fdf86dbd08_r.jpg&&&/figure&&p&&br&&/p&&h2&OS&/h2&&p&从 OS 的层面来说,内存大致可以分为三个部分:一部分为栈(Stack)另外一部分为堆(Heap),最后一部分为程序代码的存储空间(Programe Text)。既然在逻辑上 OS 已经对内存的布局做了划分,如果栈和堆之前如果没有遵守「分界线」而发生了 overwrite,那么结果将是灾难性的。为了防止发生这种情况,OS 在 Stack 和 Heap 之间设置了一段不可被 overwrite 的区域:Guard Page&/p&&h2&thread&/h2&&p&通过对 OS 中线程模型的了解,我们可以知道:同一个进程的多个线程共享进程的地址空间。所以,每一个 thread 都会有自己的 Stack 空间以及一份 Guard Page用于线程间的隔离。在程序运行的过程中,线程越多,消耗的内存也就越多。当一个线程被创建的时候,通常会消耗大概1MB的空间(预分配的 Stack 空间+ Guard Page)。&/p&&h2&goroutine&/h2&&p&对于一个 goroutine 来说,当它被创建的时候,有一个初始的内存使用量。这个使用量在 Go 1.2~1.4 版本的时候发生过几次改变,最终确定为2KB。当一个 goroutine 在运行的过程中如果需要使用更多的内存,那么它将会在 Heap 上申请。&/p&&p&对于 Guard Page 的问题,goroutine 采取了一种「用前检查」的方式来解决:每当一个函数调用的时候,go runtime 都会去检查当前 goroutine 的 stack 空间是否够用,如果不够就在 Heap 上分配一块新的空间,该块空间使用完还会被回收。&/p&&p&这种「用前检查」的动态分配内存的方式使得 goroutine 在内存的消耗上相较于 thread 来说具有明显的优势。所以在写 golang 程序的时候,我们几乎可以对收到的每一个 Request 都开一个 goroutine 处理。但是如果使用 thread这么做的话,你就等着 OOM 吧:)。上面的描述并不代表对于 goroutine 你就可以随意分配使用而不及时回收,如果 goroutine 数量太多它一样会 OOM,只不过 goroutine 相较于 thread 的内存增长率要低很多罢了。在同等的量级下,thread 会引起程序 OOM 但是 goroutine 不会。&/p&&h2&创建和销毁的性能&/h2&&h2&thread&/h2&&p&线程的创建和销毁都需要通过系统调用来实现,也就是说,这些动作都必须要和 OS 的内核进行交互。&/p&&h2&goroutine&/h2&&p&goroutine 的创建和销毁操作都是由 go runtime 来完成的,在用户空间下直接进行处理。&/p&&p&对于创建和销毁的性能问题,这里不做过多介绍。本质上来说,goroutine 和 thread 就相当于「用户级线程」和「内核级线程」。感兴趣的可以去找下相关资料深入了解下两者的区别。否则,可以简单的理解为「goroutine 的创建和销毁是程序自己做的,但是 thread 得麻烦 OS 的内核,两者的性能当然不一样」&/p&&h2&上下文切换的消耗&/h2&&h2&thread&/h2&&p&当不同的线程发生切换的时候,如上面提到的创建和销毁操作一样,都需要和 OS 的内核进行交互。调度器将会保存/恢复当时所有寄存器当中的内容:PC (Program Counter), SP (Stack Pointer) 等等一系列的上下文数据。这些操作都是非常「昂贵」的&/p&&h2&goroutine&/h2&&p&多个 goroutine 在发生切换的时候,由于是在同一个 thread 下面,只会保存/恢复三个寄存器当中的内容:Program Counter, Stack Pointer and DX。另外,如果你对 golang scheduler 的调度模型比较熟悉的话,那么你应该知道,同一时刻同一个 thread 只会执行一个 goroutine,未被执行但是已经准备好的 goroutine 都是放在一个 queue 中的,他们是被串行处理的。所以,即使一个程序创建了成千上万的 goroutine 也不会对上下文的切换造成什么影响。最重要的是,golang scheduler 在切换不同 goroutine 的操作上基本上达到了 O(1) 的时间复杂度。这就使得上下文切换的时间已经和 goroutine 的规模完全不相关了。&/p&&h2&goroutine 是如何工作的?&/h2&&p&通常来讲,一个 goroutine 运行起来通常需要三个「组件」参与:&/p&&ol&&li&golang runtime&/li&&li&runable goroutine&/li&&li&thread&/li&&/ol&&p&golang runtime将会创建一些 thread 以便提供 goroutine 的运行环境。一个可运行的 goroutine 将会被调度到 thread 上执行。当该 goroutine 被 block 住(没有 block 住对应的 thread,如系统中断等)的时候,会从「runable goroutines」中获取一个 goroutine 进行上下文切换以至于这个新的 goroutine 能够被执行&/p&&h2&golang 的 scheduler 是如何工作的?&/h2&&h2&golang 的调度模型&/h2&&p&对于 thread 和 os 内核来说,如果他们彼此的数量关系是1:1,在机器是多核的情况下,其并行计算能力将会被发挥到极致。但是,线程上下文切换的消耗将会对整个 OS 的性能有所影响。如果他们彼此的数量关系是 N:1,
虽然上下文切换的消耗降低了,但是 CPU 的利用率却会下降。&/p&&p&在 golang 的调度模型中,对于 goroutine 和 thread 的数量关系,采取了 M:N 的形式:它可以调度任意数量的 goroutine 到任意数量的 thread 上。在尽可能提高 CPU 利用率的同时,也保证了 goroutine 的上下文切换操作是较为「便宜」的(都是在 usernamespace 下进行,不需要 OS 内核参与)。 golang 对于 goroutine 的调度,设计了三个基本的对象:&/p&&ol&&li&machine(M)&/li&&li&goroutine(G)&/li&&li&processor(P)&/li&&/ol&&p&其中 M 代表的是一个可供使用的 thread,它被 OS 内核管理。G 则代表一个 goroutine,它是轻量级的 thread。P 代表一种「资源」,只有它和 M 一起配合才能够运行一段 golang 的代码,所以姑且可以把 P 理解为 goroutine 执行过程中的上下文环境。P 是一个桥梁,他把1:1和1:N 这两种模型结合了起来,最终产出了 M:N 的调度模型。&/p&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-44c5dfdcdfa386e92bfedbf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&391& class=&content_image& width=&400&&&/figure&&p&&br&&/p&&p&根据上面的模型图可以看出, golang 程序的并发能力除了受到 M(thread)的限制之外,还受到了 P(processor)数量的限制。 Thread 可以通过系统调用进行创建,那么 P 的数量可以通过什么来进行设置呢?在名为 &code&runtime&/code&的 package 中有一个&code&GOMAXPROCS&/code& 方法,我们可以通过它设置最大可使用的 P 的数量。 &/p&&p&&code&runtime. GOMAXPROCS&/code&这个函数本质上是用来设置最大可用的 CPU 核心数量:&/p&&blockquote& GOMAXPROCS sets the maximum number of CPUs that can be executing simultaneously and returns the previous setting. If n & 1, it does not change the current setting. The number of logical CPUs on the local machine can be queried with NumCPU. This call will go away when the scheduler improves.
&br&&/blockquote&&p&由于 CPU 核心数和 P 是1:1的关系(M 的数量可以多于 P),我们认为设置最大可用的 CPU 核心数就是设置最大可用的 P 的数量(对于一个 go 程序来说)&/p&&h2&调度过程&/h2&&p&我们将分四种情况来了解 golang scheduler 调度 goroutine 的过程。假设现在有两个 M,两个 P,若干个 G&/p&&h2&steady&/h2&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-44c5dfdcdfa386e92bfedbf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&391& class=&content_image& width=&400&&&/figure&&p&&br&&/p&&p&图中灰色的 G 表示了可被执行但是还未被调度的 goroutine。P 每次从「可被执行的 goroutine 队列」中选取一个 goroutine 调度到 M 执行。当前的 goroutine 被执行完成之后,将从队列中弹出。P 会不断的重复上述的过程处理 goroutine。&/p&&p&值得注意的是,在 golang 1.2之前的版本当中,「可被执行的 goroutine 队列」和 P 并不是 1:1 的关系。整个 go runtime 中只有一个全局的「可被执行的 goroutine 队列」。它通过一个全局的锁来防止并发读写时的「竞争」问题。这种设计无疑是低效的,尤其是在 CPU 核心数较多的机器上。&/p&&p&理论上来说,只要 P 所控制的「可被执行的 goroutine 队列」不为空,那么这个调度过程就是稳定的。&/p&&h2&busy&/h2&&p&&br&&/p&&figure&&img src=&https://pic4.zhimg.com/v2-44c5dfdcdfa386e92bfedbf_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&400& data-rawheight=&391& class=&content_image& width=&400&&&/figure&&p&&br&&/p&&p&Busy 的情况就是指所有的 M 上都有正在运行的 G,没有空闲的 P,也没有空闲的 M。此时整个调度过程如上面 steady 情况所描述的一样。&/p&&h2&idle&/h2&&p&通过对上面两种情况下调度过程的了解,我们再次回顾一下,一个「最小的调度单位」都包括哪些元素:&/p&&ol&&li&Gs(runable goroutine queue)&/li&&li&M&/li&&li&P&/li&&/ol&&p&Idle 状态即是:部分 P 中挂载的 runable goroutine queue已经没有剩余的 goroutine 可供调度。如下图所示,两个「最小调度单位」中,已经有一个的 runable goroutine queue 为空了。此时,为了能够让所有的 M 的利用率达到最大,golang runtime 会采取以下两种机制来处理 idle 状态:&/p&&ol&&li&从 global runable goroutine queue 中选取 goroutine&/li&&li&若 global runable goroutine queue 中也没有 goroutine,随机选取选取一个 P,从其挂载的 runable goroutine queue 中 steal 走一半的 goroutine&/li&&/ol&&p&&br&&/p&&p&&br&&/p&&p&一个更加通用的调度过程的描述如下:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&runtime.schedule() {
// only 1/61 of the time, check the global runnable queue for a G.
// if not found, check the local queue.
// if not found,
try to steal from other Ps.
if not, check the global runnable queue.
&/code&&/pre&&/div&&p&在描述 steady 状态的调度过程的时候,我们提到过老版本的 Go 中没有和 P 绑定的 runable goroutine queue, 而只有一个全局的 gloabl runable goroutine queue。虽然在之后的版本中不再使用锁+全局队列的机制来实现调度器,但它仍然被保存了下来,并且在查找可被调度的 goroutine 时还会被访问到。至于原因,我们会在后面说到。&/p&&h2&syscall&/h2&&p&当我们的 goroutine 逻辑中有使用「系统调用」的代码时,其对应的 M 会被阻塞。此时 P 中挂载的 runable goroutine queue 中的 goroutine 在短时间内将不会被这个 M 调度执行。现在看起来这些「剩余」的 goroutine 进入了一个比较尴尬的状态,它们似乎只能等待其对应的 M 从阻塞状态中释放出来才能够被重新调度执行。&/p&&p&在了解 go scheduler 如何处理这种情况之前,我们可以根据之前的了解先自己思考一下:&/p&&ol&&li&将剩余的 goroutine 全部放入 global runable goroutine queue 中等待被调度执行&/li&&li&进行 context switch 操作,将 P 连同剩下的 runable goroutine queue 切换到一个较为 idle 的 M 上等待被调度执行&/li&&/ol&&p&第一种办法最简单暴力,但是缺点也很明显,全局队列是需要有锁参与的,效率肯定不高。第二种办法的思路来源于对 idle 状态的讨论。既然不同的 P 之前都可以 steal 彼此的 goroutine,那么为什么不能直接一次性把 P 和整个 runable goroutine queue 都拿过来呢?&/p&&p&&br&&/p&&figure&&img src=&https://pic1.zhimg.com/v2-9fca444cdae53ac939d0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&550& data-rawheight=&400& class=&origin_image zh-lightbox-thumb& width=&550& data-original=&https://pic1.zhimg.com/v2-9fca444cdae53ac939d0_r.jpg&&&/figure&&p&&br&&/p&&p&实际上,golang scheduler 的做法和我们想的第二种比较相似。不同的 P 之间会进行上下文切换。将已经被 block 住的 M 上挂载的 P 连同 runable goroutine queue 全部切换到到一个空闲的 M 上等待被调度执行。而之前那个被 block 住的 M 将会带着一个 G 等待被 unblock。 Unblock 之后,对于一个「最小调度单位」而言,旧的 M 和 G 显然是缺少了一个 P 的。所以它按照「之前别人对付它的方式」看是否有机会能够从其他的 M 上 steal 到一个 P 和其挂载的 runable goroutine queue。如果这个 steal 的行为失败,那么它将会把带着的 G 丢到 global runable queue 中。至于这个 M 如何被进一步处理,那又是一个新的问题了,我们在剩余的篇幅中将会提到。&/p&&p&至此,对于 golang scheduler 调度 goroutine 的执行过程我们就大致的讲完了。对于在讨论 idle 情况的时候,我们留下的那个「为什么 global runable queue 会被保留」的问题,相信在讨论 syscall 情况的时候已经给出了答案。&/p&&h2&为什么会有空闲的 thread 在等待被使用呢?(Spinning Thread)&/h2&&p&在讨论调度过程中关于 syscall 情况的时候,你会发现,有以下几个比较奇怪的地方:&/p&&ol&&li&Golang scheduler 不是会最大限度的提高 thread 的利用率么?为什么还有一个空闲的 M 在那呢?&/li&&li&那个空闲的 M 为什么没有 P 呢?&/li&&/ol&&p&理论上来说,一个thread 如果完成了它所要做的事情就应该被 OS 销毁,接下来其他进程中的 thread 就可能被 CPU 调度执行。这也就是我们常说的操作系统中线程的「抢占式调度」。考虑上面 syscall 中的情况,如果一个程序现在有两个 M,其中一个因为事情做完而被销毁,另外一个因为 syscall 的原因被 block。此时,被block 的 M 上挂载的 runable goroutines 就必须要等到下一次这个 M 被 OS 调度执行的时候才会机会继续被处理。频繁的线程间的抢占操作不但会使得 OS 的负载升高,对一些对性能要求较高的程序来讲几乎是不可接受的。&/p&&p&golang scheduler 的设计者在考虑了「 OS 的资源利用率」以及「频繁的 thread 抢占给 OS 带来的负载」之后,最终提出了「Spinning Thread」的概念。自旋线程在没有找到可供其调度执行的 goroutine 之后,并不会销毁,而是采取「自旋」的操作保存了下来。虽然看起来这是浪费了一些资源,但是考虑一下 syscall 的情景就可以知道,比起「自旋」,线程间频繁的抢占以及频繁的创建和销毁操作可能带来的危害会更大。&/p&&p&对于一个 go 的程序来说,可存在的「Spining Thread」的数量是可以通过&code&runtime. GOMAXPROCS&/code&函数设置的。&code&runtime. GOMAXPROCS&/code&函数本意是设置最大可用的 CPU 核心数,但是仔细想想就可以明白「Spining Thread」出现的目的就是在其他 M 出现问题的时候,可以直接接管 P 继续处理 G。而 P 的概念在 golang 的调度模型中又相当于是 CPU 的一个核。所以 「Spining Thread」的数量最合适的就是和最大可用的 CPU 核心数保持一致。&/p&&p&举例来说,在具有1个 M和1个 P的一个程序中,如果正在执行的 M 已经被 syscall block 住,那么仍然需要和 P 数量相同的「Spining Thread」才能够让等待的 runable goroutine 继续执行。所以,在此期间, M 的数量是要多余 P 的数量的(一个 Spinning Thread+一个被 block 住的 thread)。这也就是为什么,当&code&runtime. GOMAXPROCS&/code&函数设置的值为1的时候,程序仍然是处于多线程运行的状态的。&/p&&p&根据上面的描述,「Spining Thread」是一个特殊的 M,当一个 M 具有以下几个特点中的一个的时候,它就可以被称作是一个「Spining Thread」:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&1. An M with a P assignment is looking for a runnable goroutine.
2. An M without a P assignment is looking for available Ps.
3. Scheduler also unparks an additional thread and spins it when it is readying a goroutine if there is an idle P and there are no other spinning threads.
&/code&&/pre&&/div&&p&针对一开始我们谈到的两个问题现在也不难给出答案:&/p&&ol&&li&充分提高 thread 利用率是在 runable goroutine 数量足够多的情况下,尽可能的将它们调度到 M 执行。但是当 runable goroutine 数量不会让所有的 M 都处于工作状态的时候,golang scheduler 也并不会直接把它们销毁,而是至多留出&code&runtime. GOMAXPROCS&/code&个处于 Spinning 状态的 M,等待被阻塞的 M 下挂载的 runable goroutine。这是为了避免线程间频繁的抢占操作给 OS 带来的压力,同时也尽可能的保证了 runable goroutine 能够快速的被处理&/li&&li&空闲的 M 但是没有挂载 P 也是「Spining Thread」 中的一类&/li&&/ol&
我们的程序是如何被运行的?学习过操作系统的人,应该对进程和线程的模型都是有所了解的。按照我的理解:「进程」是操作系统资源分配的基本单位,它给程序提供了一个良好的运行环境。「线程」则是一个轻量级的进程,一个「进程」中可以有很多线程,但是最终…
&figure&&img src=&https://pic2.zhimg.com/v2-7cdbb5ddbb_b.jpg& data-rawwidth=&1986& data-rawheight=&1117& class=&origin_image zh-lightbox-thumb& width=&1986& data-original=&https://pic2.zhimg.com/v2-7cdbb5ddbb_r.jpg&&&/figure&&ul&&li&概述:UEFI 引导下的 Win10 与 Ubuntu 双系统安装记录。&/li&&li&前置:在 Windows 系统上通过压缩卷给 Ubuntu 划分空间安装之。&/li&&li&简介:使用双系统的方式对系统进行安装。内容上包括:系统的安装、配置、美化和一些软件的安装介绍。&/li&&li&地址:本文章&a href=&https://link.zhihu.com/?target=https%3A//github.com/inkss/markdown/blob/master/Linux/Ubuntu/Ubuntu-18.04-%25E5%25AE%%25A3%%25AE%25B0%25E5%25BD%2595.md& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&原文件&/a&存放在 GitHub 的 &a href=&https://link.zhihu.com/?target=https%3A//github.com/inkss/markdown& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&markdown&/a& 仓库中(&a href=&https://link.zhihu.com/?target=https%3A//github.com/inkss/markdown/raw/master/Linux/Ubuntu/Ubuntu-18.04-%25E5%25AE%%25A3%%25AE%25B0%25E5%25BD%2595.pdf& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&PDF 版本下载&/a&)。&/li&&/ul&&hr&&h2&&b&目录&/b&&/h2&&ul&&li&&a href=&https://zhuanlan.zhihu.com/p/#%E4%B8%80-%E5%AE%89%E8%A3%85%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F& class=&internal&&一 安装操作系统&/a&&/li&&ul&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E5%BC%95%E5%AF%BC%E7%9B%98& class=&internal&&1 引导盘&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E5%88%86%E5%8C%BA& class=&internal&&2 分区&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E5%AE%89%E8%A3%85%E7%B3%BB%E7%BB%9F& class=&internal&&3 安装系统&/a&&/li&&/ul&&li&&a href=&https://zhuanlan.zhihu.com/p/#%E4%BA%8C-%E5%88%9D%E6%AD%A5%E7%B3%BB%E7%BB%9F%E9%85%8D%E7%BD%AE& class=&internal&&二 初步系统配置&/a&&/li&&ul&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E4%B8%8D%E5%8F%AF%E6%88%96%E7%BC%BA%E7%9A%84%E6%9B%B4%E6%96%B0& class=&internal&&1 不可或缺的更新&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E5%8F%8C%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%97%B6%E5%8C%BA%E9%97%AE%E9%A2%98& class=&internal&&2 双系统的时区问题&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E6%9B%B4%E6%8D%A2%E7%BB%88%E7%AB%AF%E7%B1%BB%E5%9E%8B& class=&internal&&3 更换终端类型&/a&&/li&&/ul&&li&&a href=&https://zhuanlan.zhihu.com/p/#%E4%B8%89-%E9%85%8D%E7%BD%AE%E4%B8%8E%E7%BE%8E%E5%8C%96%E7%B3%BB%E7%BB%9F& class=&internal&&三 配置与美化系统&/a&&/li&&ul&&li&&a href=&https://zhuanlan.zhihu.com/p/-gnome-tweak-tool& class=&internal&&1 Gnome-tweak-tool&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E4%B8%BB%E9%A2%98-%E5%9B%BE%E6%A0%87-%E5%AD%97%E4%BD%93& class=&internal&&2 主题 图标 字体&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-grub-%E5%90%AF%E5%8A%A8%E9%A1%B9%E7%BE%8E%E5%8C%96& class=&internal&&3 Grub 启动项美化&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E6%90%9C%E7%8B%97%E8%BE%93%E5%85%A5%E6%B3%95& class=&internal&&4 搜狗输入法&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E5%BA%95%E6%A0%8F-docky& class=&internal&&5 底栏 Docky&/a&&/li&&/ul&&li&&a href=&https://zhuanlan.zhihu.com/p/#%E5%9B%9B-%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85%E4%B8%8E%E8%AE%B0%E5%BD%95& class=&internal&&四 软件安装与记录&/a&&/li&&ul&&li&&a href=&https://zhuanlan.zhihu.com/p/-deepinwine-%E7%8E%AF%E5%A2%83& class=&internal&&1 Deepin-Wine 环境(QQ、百度网盘、微信等)&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E7%BD%91%E6%98%93%E4%BA%91%E9%9F%B3%E4%B9%90& class=&internal&&2 网易云音乐(解决无法打开软件的问题)&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E4%B8%80%E8%88%AC%E6%80%A7%E8%BD%AF%E4%BB%B6%E5%AE%89%E8%A3%85& class=&internal&&3 一般性软件安装(Chrome、Typora 等)&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-gnome-%E6%89%A9%E5%B1%95& class=&internal&&4 Ubuntu 18.04 Gnome 扩展推荐&/a&&/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E4%BD%BF%E7%94%A8-snap-%E5%8C%85%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6& class=&internal&&5 使用 Snap 包安装软件&/a& &/li&&li&&a href=&https://zhuanlan.zhihu.com/p/-%E6%96%87%E4%BB%B6%E5%A4%87%E4%BB%BD%E5%90%8C%E6%AD%A5& class=&internal&&6 文件备份同步传输(本地 & 云端 & 局域网)&/a&&/li&&/ul&&/ul&&hr&&h2&一 安装操作系统&/h2&&h2&1 引导盘&/h2&&p&鉴于现在都 18 年了,是时候抛弃 Legacy 引导,完全采用 UEFI 引导了。&/p&&p&而这里有两种选择(所有操作均在 Windows 下进行):&/p&&ul&&li&刻录到光盘:&/li&&/ul&&p&使用 &i&&a href=&https://link.zhihu.com/?target=https%3A//www.ultraiso.com/download.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&UltraISO&/a&&/i& 进行刻录,在完成之后,电脑可以对光盘识别到 Legacy 和 UEFI 两种方式的引导项。而如果 BIOS 中设置为仅 UEFI ,就只需直接选择进行安装即可。&/p&&ul&&li& 刻录到 U 盘:&/li&&ul&&li&解压镜像文件:准备一个干净的 FAT32 的 U 盘( &i&NTFS 不行&/i& ),使用压缩工具( &i&WinRAR,7z 等&/i& )对 Ubuntu 的镜像文件进行解压,解压目录为 U 盘根目录。&/li&&li&使用刻录工具:Ubuntu 官网中推荐的 U 盘刻录工具为 &i&&a href=&https://link.zhihu.com/?target=https%3A//www.pendrivelinux.com/universal-usb-installer-easy-as-1-2-3/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Universal-USB-Installer&/a&&/i& ,但是需要注意的是这个工具刻录后的 U 盘只有 Legacy 引导 ,所以只能抛弃该软件。然后在网上简单的搜索后找到了另一款 U 盘刻录工具:&i&&a href=&https://link.zhihu.com/?target=https%3A//rufus.akeo.ie/%3Flocale%3Dzh_CN& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Rufus&/a&&/i&,提到了其具有 &b&免安装、绿色版、支持 UEFI 引导 &/b&的特点,那么就选用它了。&/li&&/ul&&/ul&&blockquote&刻录到 U 盘的方式二选一,过程不多赘述,使用 Rufus 刻录时分区类型选择 &code&GPT&/code&。&/blockquote&&h2&2 分区&/h2&&p&本次目标是做一个双系统出来,所以保留原 Windows 系统,压缩出一个分区给 Ubuntu 使用。&/p&&p&打开 Windows 的文件管理器(快捷键 Win + E),展开顶部选择 &b&计算机&/b&→&b&管理 &/b&。&/p&&p&然后选择 &b&磁盘管理工具 &/b&,对相应分区进行压缩。&/p&&blockquote&具体的压缩教程可搜索查询,需要注意一下对压缩后的新分区 &b&不要新建简单卷或格式化 &/b&。&/blockquote&&h2&3 安装系统&/h2&&p&正常的安装过程,诸如对 BIOS 进行设置之类,网上教程很多,这里不多赘述。&/p&&p&在到 &i&安装类型&/i& 这一步时,如果你在上一步压缩完分区后,没有新建简单卷,那么就会多出一个 &b&安装 Ubuntu,与 Windows boot manager 共存 &/b&这一选项,那么就只需默认无脑下一步即可。&/p&&p&而如果需要自主划分分区,就选择 &i&其他选项 。&/i&分区只推荐划分出根 &code&/&/code& 和家目录 &code&/home&/code&。&/p&&blockquote&注意1:为了系统的稳定,安装过程中请连上网络,勾选 &b&安装 Ubuntu 时下载更新 &/b&。&br&注意2:安装时选择 &b&最小安装 &/b&,除非你对雷鸟、LibreOffice
之类的软件感兴趣。&/blockquote&&hr&&h2&二 初步系统配置&/h2&&h2&1 不可或缺的更新&/h2&&p&如果在上一步中勾选了安装 Ubuntu 时下载更新,那么大部分的系统更新已经下载完毕。&/p&&p&不过为了确保,先移步到 &b&设置&/b&→&b&详细信息 &/b&,点击右下角的 &b&检查更新 &/b&,如果存在更新,那么完成相应的更新操作。&/p&&p&接着移步到 &b&设置&/b&→&b&区域和语言&/b&→&b&管理已安装的语言 &/b&,在此处完成一个更新下载。&/p&&p&最后,为了确保系统和软件都更新完毕,打开终端使用命令安装更新:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt update
sudo apt upgrade
&/code&&/pre&&/div&&p&也可以不使用命令行,使用 &i&软件更新器&/i& 对系统和软件进行更新。&/p&&h2&2 双系统的时区问题&/h2&&p&双系统下 Windows 与 Ubuntu 的时间将会不相同,原因不多阐述,解决方案如下:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&timedatectl set-local-rtc 1
&/code&&/pre&&/div&&h2&3 更换终端类型&/h2&&p&这里推荐使用 &b&oh-my-zsh&/b& ,因为其具有十分方便的 &i&Tab&/i& 补全能力:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt-get install git
sudo apt-get install zsh
wget https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh -O - &span class=&p&&|&/span& sh
chsh -s /usr/bin/zsh
&/code&&/pre&&/div&&blockquote&重启系统以生效。&/blockquote&&hr&&h2&三 配置与美化系统&/h2&&figure&&img src=&https://pic2.zhimg.com/v2-0bcf6b2f59a8fee8d609be7e537341de_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic2.zhimg.com/v2-0bcf6b2f59a8fee8d609be7e537341de_r.jpg&&&/figure&&h2&1 Gnome-tweak-tool&/h2&&p&Ubuntu 18.04 与 16.04 最大的变动就是抛弃了 Unity 桌面,使用 Gnome ,所以先安装以下工具:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt install gnome-tweak-tool
&/code&&/pre&&/div&&p&然后移步到 &b&Ubuntu 软件&/b&→&b&附加组件&/b&,在此处安装相应的 Shell 组件。&/p&&p&为了自定义 Shell 主题,需要安装、启用插件:&i&User Themes(如此才可以修改 shell 样式,也就是顶栏)&/i&&/p&&p&附录:一个下载主题的网站:&a href=&https://link.zhihu.com/?target=https%3A//www.gnome-look.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Gnome-look&/a& &/p&&figure&&img src=&https://pic3.zhimg.com/v2-a4e96fee00a19fe6f9c0f5_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&918& data-rawheight=&664& class=&origin_image zh-lightbox-thumb& width=&918& data-original=&https://pic3.zhimg.com/v2-a4e96fee00a19fe6f9c0f5_r.jpg&&&/figure&&blockquote&上图中主题和图标的的下载地址:&a href=&https://link.zhihu.com/?target=https%3A//www.opendesktop.org/c/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Sierra-light&/a&、&a href=&https://link.zhihu.com/?target=https%3A//www.gnome-look.org/p/1102582/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&MacOS Icon&/a&&/blockquote&&h2&2 主题 图标 字体&/h2&&p&下载的主题如果是 deb 包的形式,安装方式见下文。而如果是压缩包的形式,那么就只能解压它放到对应的目录中了,这个目录有两种,区别上类似于 Windows 环境变量里的个人和系统。&/p&&ul&&li&主题存放目录:&code&/usr/share/themes&/code& 或 &code&~/.themes&/code&&/li&&li&图标存放目录:&code&/usr/share/icons&/code& 或 &code&~/.icons&/code&&/li&&li&字体存放目录:&code&/usr/share/fonts&/code& 或 &code&~/.fonts&/code&&/li&&/ul&&p&&i&/usr/share&/i& 目录需要 root 权限才能修改,秉着有图形界面就不用终端的心态:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 终端下打开一个具有管理员权限的文件管理器&/span&
&span class=&c1&&# 打开后终端最小化,不要关闭&/span&
sudo nautilus
&span class=&c1&&# 或者放到本地目录中&/span&
&/code&&/pre&&/div&&p&附录一个在 Linux 下特别好用的字体:&i&文泉驿系列字体&/i&&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt install fonts-wqy-microhei fonts-wqy-zenhei
&/code&&/pre&&/div&&h2&3 Grub 启动项美化&/h2&&p&主题包地址:&a href=&https://link.zhihu.com/?target=https%3A//www.gnome-look.org/browse/cat/109/order/latest& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Gnome Look - GRUB Themes&/a& (自行挑选喜欢的)&/p&&p&这里使用的主题包为:&a href=&https://link.zhihu.com/?target=https%3A//www.gnome-look.org/p/1230882/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Fallout &/a&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-a4f222d444b03ef294ac9_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1280& data-rawheight=&720& data-thumbnail=&https://pic2.zhimg.com/v2-a4f222d444b03ef294ac9_b.jpg& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&https://pic2.zhimg.com/v2-a4f222d444b03ef294ac9_r.jpg&&&/figure&&p&接下来介绍安装步骤:&/p&&p&首先下载主题包,为 zip 压缩包。解压出文件,使用 &code&sudo nautilus&/code& 打开带权限的文件管理器。&/p&&p&定位到目录:&code&/boot/grub&/code&,在该目录下新建文件夹:&code&themes&/code&,把解压出的文件拷贝到文件夹中。&/p&&p&接着终端下调用 gedit 修改 &i&grub&/i& 文件:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo gedit /etc/default/grub
&/code&&/pre&&/div&&p&在该文件末尾添加:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# GRUB_THEME=&/boot/grub/themes/主题包文件夹名称/theme.txt&&/span&
&span class=&nv&&GRUB_THEME&/span&&span class=&o&&=&/span&&span class=&s2&&&/boot/grub/themes/fallout-grub-theme-master/theme.txt&&/span&
&/code&&/pre&&/div&&p&最后更新配置文件:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo update-grub
&/code&&/pre&&/div&&blockquote&重启系统以见证效果。另外谈到 grub 就不得不谈到 &code&/boot/grub/grub.cfg&/code& ,这个文件才是事实上的配置文件,操纵此文件一个不慎就整个系统凉凉。所谓更新配置文件就是重新生成 &i&grub.cfg&/i& 的过程。&/blockquote&&h2&4 搜狗输入法&/h2&&p&Ubuntu 18.04 没有提供 Fcitx 输入框架,所以先安装该框架:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt install fcitx
&/code&&/pre&&/div&&p&接着到&a href=&https://link.zhihu.com/?target=https%3A//pinyin.sogou.com/linux/%3Fr%3Dpinyin& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&搜狗输入法官网&/a&下载输入法安装包,将会下载到一个 deb 格式的安装包,安装它:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 首先移步到文件管理器的下载目录,终端下输入以下命令进行安装&/span&
sudo dpkg -i sogoupinyin_2.2.0.0108_amd64.deb
&span class=&c1&&# 一般情况下会提示安装失败,缺失依赖,所以先解决依赖问题&/span&
sudo apt install -f
&span class=&c1&&# 接着重复第一步安装搜狗输入法的命令&/span&
&span class=&c1&&# 一般 deb 包都是如此安装的,如果失败就去解决依赖问题&/span&
&/code&&/pre&&/div&&p&然后移步到 &b&设置&/b&→&b&区域和语言 &/b&,删除一部分输入源,只保留 &i&汉语&/i&
。接着选择 &b&管理已安装的语言 &/b&,修改 &i&键盘输入法系统&/i& 为 &b&fcitx&/b& 。关闭窗口,打开所有程序,选择软件
&b&Fctix 配置&/b&,选择加号添加搜狗输入法(见下图):&/p&&figure&&img src=&https://pic3.zhimg.com/v2-644a8a065c53d65be92c_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&643& data-rawheight=&460& class=&origin_image zh-lightbox-thumb& width=&643& data-original=&https://pic3.zhimg.com/v2-644a8a065c53d65be92c_r.jpg&&&/figure&&blockquote&如果没有找到搜狗,就重启系统,再次重复以上步骤即可。&br&推荐一个搜狗输入法皮肤:&a href=&https://link.zhihu.com/?target=https%3A//pinyin.sogou.com/skins/detail/view/info/Frf%3Dsubject_jjzq%26tf%3Dp& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&简约-信&/a& &/blockquote&&figure&&img src=&https://pic3.zhimg.com/v2-fefba5abc6fe36eaacac076c22acd2e3_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&746& data-rawheight=&582& class=&origin_image zh-lightbox-thumb& width=&746& data-original=&https://pic3.zhimg.com/v2-fefba5abc6fe36eaacac076c22acd2e3_r.jpg&&&/figure&&h2&5 底栏 Docky&/h2&&p&这是一个能做到和 MAC 类似效果的 Dock 软件,颜值上比 Ubuntu 自带的好了很多。&/p&&p&首先把 Ubuntu 自带的 Dock 设置为 &i&自动隐藏&/i& :&b&设置&/b&→&b&Dock&/b&→&b&自动隐藏 Dock&/b& ,然后安装软件:&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&sudo apt install docky
&/code&&/pre&&/div&&p&【可选】如何 &i&&a href=&https://link.zhihu.com/?target=https%3A//my.oschina.net/ic4907/blog/158747& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&去掉 Docky 第一个图标&/a&&/i&&/p&&p&在 &b&Ubuntu SoftWare&/b& 中搜索 &i&Configuration Editor&/i& ,安装后打开软件,定位到:&/p&&p&&b&&code&/apps/docky-2/Docky/Items/DockyItem&/code&&/b&&/p&&p&取消 &i&ShowDockyItem&/i& 的勾选状态(决定是否显示 第一个 Docky)&/p&&hr&&h2&四 软件安装与记录&/h2&&h2&1 DeepinWine 环境&/h2&&p&曾经试用过一次 CrossOver ,用其安装了 TIM ,心想如果没太大毛病就购买这个软件了,只是蛮遗憾的一堆小问题,虽然不影响使用,但是影响体验呀。所以真的很感叹 Deepin 封装的 TIM/QQ 的稳定性,所以这里也是 &b&借用 Deepin 的贡献 &/b&达到使用 QQ 的目的。&/p&&p&首先需要在本机下载 Deepin-Wine 环境:&b&&a href=&https://link.zhihu.com/?target=https%3A//github.com/wszqkzqk/deepin-wine-ubuntu& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&deepin-wine-ubuntu&/a&&/b&&/p&&p&克隆或者下载压缩包到本机,解压后在终端下执行命令:&code&./install.sh&/code& 安装环境即可。&/p&&p&容器下载地址:&a href=&https://link.zhihu.com/?target=http%3A//mirrors.aliyun.com/deepin/pool/non-free/d/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Index of /deepin/pool/non-free/d/&/a& ,使用方法见仓库中的 ReadMe 文件。&/p&&blockquote&&b&关于托盘&/b&:安装 &i&TopIconPlus&/i& 的 gnome-shell 扩展。&br&然后在所有软件中找到&b&优化 (Gnome-tweak-tool) &/b&,在扩展中打开 &i&Topicons plus&/i& 。&br&参考资料地址:&a href=&https://link.zhihu.com/?target=https%3A//www.lulinux.com/archives/1319& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&多发行版通过!目前 Linux 上真正完美稳定的 wine QQ 方案&/a&&/blockquote&&figure&&img src=&https://pic4.zhimg.com/v2-f1d0a4f83250bd7afd2f95e6c32128e0_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&https://pic4.zhimg.com/v2-f1d0a4f83250bd7afd2f95e6c32128e0_r.jpg&&&/figure&&h2&2 网易云音乐&/h2&&p&在写这篇文章时,操作系统版本为:&code&Ubuntu 18.04.1 LTS x86_64&/code& ;网易云音乐版本为:&code&1.1.0&/code&&/p&&p&首先去网易云音乐官网&a href=&https://link.zhihu.com/?target=https%3A//music.163.com/%23/download& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&下载安装包&/a&(Ubuntu 16.04 64 位),然后就是正常的 deb 包安装过程。&/p&&p&安装完毕后,会发现在应用列表中点击应用图标无法启动软件(&b&当前版本如此&/b&),解决方案:&/p&&p&先获取操作系统的用户名:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 终端下输入下列命令&/span&
&/code&&/pre&&/div&&p&记录输出的内容,如我的用户名为:&code&inkss&/code&,然后终端下修改 sudoers :&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo gedit /etc/sudoers
&span class=&c1&&# 在打开的文本编辑器中,添加一行(inkss 为我的用户名):&/span&
inkss &span class=&nv&&ALL&/span& &span class=&o&&=&/span& NOPASSWD: /usr/bin/netease-cloud-music
&/code&&/pre&&/div&&p&接着修改网易云音乐的启动图标:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo gedit /usr/share/applications/netease-cloud-music.desktop
&span class=&c1&&# 修改 Exec 这一行内容:&/span&
&span class=&nv&&Exec&/span&&span class=&o&&=&/span&sudo netease-cloud-music %U
&/code&&/pre&&/div&&blockquote&原因,在终端下可以通过 &code&sudo netease-cloud-music&/code& 打开软件,只是无疑这个方法很是繁琐,所以不如将这个 sudo 放到 desktop 中,这样当点击应用图标后就是已管理员权限启动的,而且不需要密码。&br&参考资料地址:&a href=&https://link.zhihu.com/?target=https%3A//blog.csdn.net/Handoking/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&(已解决)ubuntu下网易云音乐无法打开&/a&&/blockquote&&figure&&img src=&https://pic3.zhimg.com/v2-3bb1081755fbaeb3b6f9b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1195& data-rawheight=&814& class=&origin_image zh-lightbox-thumb& width=&1195& data-original=&https://pic3.zhimg.com/v2-3bb1081755fbaeb3b6f9b_r.jpg&&&/figure&&h2&3 一般性软件安装&/h2&&p&相对麻烦的软件安装记录完毕,下文记录一些其他软件的安装:&/p&&h2&3.1 Chrome&/h2&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/sources.list.d/
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub &span class=&p&&|&/span& sudo apt-key add -
sudo apt update
sudo apt install google-chrome-stable
&/code&&/pre&&/div&&h2&3.3 Neofetch&/h2&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt install neofetch
&/code&&/pre&&/div&&p&终端下查询系统配置信息。&/p&&figure&&img src=&https://pic1.zhimg.com/v2-1697884aaf709cd4bdaf05034a13afac_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1207& data-rawheight=&695& class=&origin_image zh-lightbox-thumb& width=&1207& data-original=&https://pic1.zhimg.com/v2-1697884aaf709cd4bdaf05034a13afac_r.jpg&&&/figure&&h2&3.4 Typora&/h2&&p&颜值很高的实时 MD 编辑、阅读软件。&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# optional, but recommended&/span&
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys BA300B7755AFCFAE
&span class=&c1&&# add Typora's repository&/span&
sudo add-apt-repository &span class=&s1&&'deb https://typora.io/linux ./'&/span&
sudo apt update
&span class=&c1&&# install typora&/span&
sudo apt install typora
&/code&&/pre&&/div&&figure&&img src=&https://pic1.zhimg.com/v2-2776bafefcb72defbdef4b_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1593& data-rawheight=&865& class=&origin_image zh-lightbox-thumb& width=&1593& data-original=&https://pic1.zhimg.com/v2-2776bafefcb72defbdef4b_r.jpg&&&/figure&&h2&3.5 Albert&/h2&&p&这是一款非常好用的 &i&软件启动器&/i& ,我在安装的时候按照添加 &i&PPA&/i& 的方法安装失败了,如此便去其官网(&a href=&https://link.zhihu.com/?target=https%3A//albertlauncher.github.io/docs/installing/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&GitHub-Albert&/a&)查找了一下,步骤上略显繁琐,这里记录一下:&/p&&p&先这样:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&wget -nv -O Release.key &span class=&se&&\ &/span&https://build.opensuse.org/projects/home:manuelschneid3r/public_key
sudo apt-key add - & Release.key
sudo apt update
&/code&&/pre&&/div&&p&然后这样:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo sh -c &span class=&s2&&&echo 'deb http://download.opensuse.org/repositories/home:/manuelschneid3r/xUbuntu_18.04/ /' & /etc/apt/sources.list.d/home:manuelschneid3r.list&&/span&
sudo apt update
sudo apt install albert
&/code&&/pre&&/div&&figure&&img src=&https://pic3.zhimg.com/v2-dda0b8b42a08e3ff3b46d2_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&680& data-rawheight=&353& class=&origin_image zh-lightbox-thumb& width=&680& data-original=&https://pic3.zhimg.com/v2-dda0b8b42a08e3ff3b46d2_r.jpg&&&/figure&&h2&3.6 popup-dict&/h2&&p&Linux 下的划词翻译工具,支持使用有道等多种翻译服务。&/p&&p&功能特点:&/p&&ul&&li&目前只支持英文-&中文翻译,支持单词和短语&/li&&li&主要针对 Gnome 桌面环境,不保证其它环境下的正常使用&/li&&li&鼠标划词翻译,弹窗显示&/li&&li&智能处理选中内容(去除两端非英文字符、压缩空白字符、删除换行符等)&/li&&li&弹窗显示一段时间后自动关闭。若鼠标在弹窗中,延迟关闭&/li&&li&点击弹窗中链接可打开有道词典网页版&/li&&/ul&&p&安装过程:&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 安装 pip3 ,如果已有请忽略此步骤&/span&
sudo apt install python3-pip
&span class=&c1&&# 安装 PyGObject 依赖&/span&
sudo apt install python-gi python-gi-cairo python3-gi python3-gi-cairo gir1.2-gtk-3.0
&span class=&c1&&# 安装 popup-dict&/span&
sudo pip3 install popupdict
&/code&&/pre&&/div&&p&运行软件:使用 Gnome 扩展
&code&&a href=&https://link.zhihu.com/?target=https%3A//extensions.gnome.org/extension/1349/popup-dict-switcher/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Popup dict Switcher&/a&&/code&&/p&&figure&&img src=&https://pic2.zhimg.com/v2-c418e7949ccc94de06aee50_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&862& data-rawheight=&583& class=&origin_image zh-lightbox-thumb& width=&862& data-original=&https://pic2.zhimg.com/v2-c418e7949ccc94de06aee50_r.jpg&&&/figure&&h2&4 Gnome 扩展&/h2&&p&Ubuntu 18.04 抛弃了 Unity 桌面转而使用 Gnome ,所以 Gnome 桌面下的一些 Shell 扩展在 Ubuntu 18.04 中就可以使用了。在 &a href=&https://zhuanlan.zhihu.com/p/-gnome-tweak-tool& class=&internal&&Gnome-tweak-tool&/a& 一节中就提到通过 Ubuntu 软件中心下载、安装和管理 Gnome 扩展(附加组件),下面介绍一种通过浏览器对 Gnome 插件的安装管理方式:&/p&&p&首先安装 Chrome Gnome Shell :&/p&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&sudo apt install chrome-gnome-shell
&/code&&/pre&&/div&&p&然后安装浏览器插件(&b&谷歌浏览器&/b&):&a href=&https://link.zhihu.com/?target=https%3A//chrome.google.com/webstore/detail/gnome-shell-integration/gphhapmejobijbbhgpjhcjognlahblep& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Chrome 网上应用商店&/a&&/p&&p&浏览器插件安装完成后点击 &i&插件图标&/i& 就能进入:&b&&a href=&https://link.zhihu.com/?target=https%3A//extensions.gnome.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Shell 扩展商店&/a&&/b&&/p&&p&Gnome 扩展推荐&/p&&figure&&img src=&https://pic4.zhimg.com/v2-44e66f69a6bcb_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&600& data-rawheight=&686& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic4.zhimg.com/v2-44e66f69a6bcb_r.jpg&&&/figure&&blockquote&以上表格提到的所有扩展都能在 Ubuntu 18.04 中使用,如果存在安装失败的情况,请检查是否满足依赖。&br&&i&知乎不支持表格的用法,这里只能截图了,可以去这儿查看:&a href=&https://link.zhihu.com/?target=https%3A//github.com/inkss/markdown/blob/master/Linux/Ubuntu/Ubuntu-18.04-%25E5%25AE%%25A3%%25AE%25B0%25E5%25BD%2595.md%234-gnome-%25E6%%25E5%25B1%2595& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&4-Gnome-扩展&/a&&/i&&/blockquote&&figure&&img src=&https://pic1.zhimg.com/v2-cde4edc7dddf8a15a45fbaa_b.jpg& data-caption=&& data-size=&normal& data-rawwidth=&1603& data-rawheight=&985& class=&origin_image zh-lightbox-thumb& width=&1603& data-original=&https://pic1.zhimg.com/v2-cde4edc7dddf8a15a45fbaa_r.jpg&&&/figure&&h2&5 使用 Snap 包安装软件&/h2&&h2&5.1 Snap 简介&/h2&&blockquote&&b&What is a snap?&/b&&br&A Snap :&/blockquote&&ul&&li&is a squashFS filesystem containing your app code and a &code&snap.yaml&/code& file containing specific metadata. It has a read-only file-system and, once installed, a writable area.&/li&&li&is self-contained. It bundles most of the libraries and runtimes it needs and can be updated and reverted without affecting the rest of the system.&/li&&li&is confined from the OS and other apps through security mechanisms, but can exchange content and functions with other snaps according to fine-grained policies controlled by the user and the OS defaults. &/li&&/ul&&p&在 Ubuntu 16.04 时,Ubuntu 系统就已经内置了 Snap ,Snap 打包的应用不同于 deb 安装包,其包含了各种依赖环境等等(另外一个和 Snap 类似的是 Flatpak ,Deepin 正在使用的就是这个)。&/p&&h2&5.2 Snap 命令&/h2&&ul&&li&登录 Snap Store&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 这个账户是你的 UBuntu One 账户(https://login.ubuntu.com/+login)&/span&
sudo snap login
&span class=&c1&&# 退出账户&/span&
snap &span class=&nb&&logout&/span&
&/code&&/pre&&/div&&p&Snap 通常从 Snap Store 安装。您可以在不登录的情况下与 Snap Store 进行交互,但登录可提供许多优势。这些优势包括能够访问您的私人快照和管理快照而无需设备上的 root 。概括来说:&b&可以不登录,但是大部分命令就需要使用 sudo ,登录账户后则无需使用&/b&。此外登录账户后才可以发布 snap 包。&/p&&ul&&li&查找 snap 包&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 默认情况下只会发现发布到stable发布渠道的快照&/span&
snap find &query&
&span class=&c1&&# 附加命令&/span&
--private:搜索私人 snap 包
&/code&&/pre&&/div&&ul&&li&安装 snap 包&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 在系统中安装名为 snap 的包&/span&
snap install &snap&
&span class=&c1&&# 附加命令&/span&
--devmode:将 snap 设置为开发模式并禁用安全限制。
--classic:将 snap 设置为经典模式并禁用安全限制。
&/code&&/pre&&/div&&ul&&li&删除 snap 包&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 删除名为 snap 的包(包括其数据和公共数据目录)&/span&
snap remove &snap&
&/code&&/pre&&/div&&ul&&li&更新 snap 包&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 默认情况下,snap 每天会在后台自动更新系统中的 snap 包&/span&
&span class=&c1&&# 当然也可以手动指定更新&/span&
snap refresh &snap&
&span class=&c1&&# 附加命令&/span&
--list:显示可用的快照以进行刷新
&/code&&/pre&&/div&&ul&&li&还原 snap 包&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 回复到初始安装状态&/span&
snap revert &snap&
&/code&&/pre&&/div&&ul&&li&禁用与启用&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 禁用快照。快照的二进制文件和服务将不再可用。但是所有数据仍然可用,并且可以轻松再次启用快照。&/span&
snap disable &snap&
&span class=&c1&&# 启用快照&/span&
snap &span class=&nb&&enable&/span& &snap&
&/code&&/pre&&/div&&ul&&li&列出所有 snap 包&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&&span class=&c1&&# 显示当前系统中安装的 snap 包的摘要&/span&
snap list &snap&
&/code&&/pre&&/div&&p&更多 snap 的命令用法可在终端下:&code&man snap&/code& 查看,或者浏览器访问:&a href=&https://link.zhihu.com/?target=https%3A//docs.snapcraft.io/reference/snap-command& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&snap: command reference&/a&&/p&&h2&5.3 使用 snap 安装软件&/h2&&ul&&li&Pycharm:&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&snap install pycharm-professional --classic
&/code&&/pre&&/div&&ul&&li&IDEA:&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&snap install intellij-idea-ultimate --classic
&/code&&/pre&&/div&&ul&&li&Android Studio:&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&&/span&snap install android-studio --classic
&/code&&/pre&&/div&&ul&&li&Sublime:&/li&&/ul&&div class=&highlight&&&pre&&code class=&language-bash&&&span&

我要回帖

更多关于 数据库备份方法 的文章

 

随机推荐