-
- Letsencrypt sent out deprecation notices for ACMEv1. Starting June 1, only ACMEv2 standards will be accepted as sufficient certs. I’ll have to upgrade the
jrcs/letsencrypt-nginx-proxy-companion
(running certbot) before then.
- Smoked the 15lb dry-brined prime brisket. Garlic, mustard, paprika, pepper. Post oak and cherry. Honey.
- Ran out of 18″ aluminum foil. For a big cut like brisket, it definitely leaks with 12″. Ordered more.
- Plaid connects apps like venmo, robinhood to accounts like citi, boa. Visa just bought plaid for 5.3b.
- I get python weekly and founder weekly, but I’m subscribed to nosql and never get that newsletter?
- Airtable makes a kinda cool product. It’s a database/spreadsheet combined. Standard backend but offers a full frontend gui like google sheets. This exists in many stacks, but it’s usually 2 products.
- Kadane’s algorithm for max some of contiguous subarray.
- Basically at index i, consider all the subarrays up to index i, starting from every index before it. Get the max sum of those. Go to the next index. It’s just the previous answer plus the number at the new index, or the previous answer itself.
- local_maximum[i]= max(local_maximum[i-1], array[i] + local_maximum[i-1])
- Simple recursion problem.
- Rewrote some graph traversal algorithms. Raw BFS/DFS easy. For pre-order and post-order traversal (types of DFS), use recursion. Just add the node to `visited` before or after the recursive call. For level-order (BFS), use iteration.
- For python remember the distinction between the subprocess and multiprocessing modules. Subprocess is for calling other programs, running something else from the shell, etc. Multiproc is for adding concurrency to your python program.
- Boston is ~200 miles northeast of Manhattan.
- If you’re alive, you can breathe. If you can break, you can speak 🙂
- Threading is better for IO-bound tasks. Multiprocessing better for CPU-bound tasks.
- Read quite a bit about py3’s async capability. https://realpython.com/async-io-python/.
- Slightly different than the parallelism/concurrency of threading/multiprocessing. Its async features (like asyncio.sleep()) are self-aware of when they’re idling, efficiently giving the event loop to another coroutine during that time.
- Think of a standard web service, able to handle multiple requests in parallel. Asyncio is that capability, but for your program. It’s very different than multiprocessing, which has a given workload to do and wants to split it among many workers to make it complete faster.
- async def foo(): tells python to create a coroutine. Within that function, say await bar(), instruct the event loop to go work on something else until bar() returns.
- Websockets.
- These build on that exact same async infrastructure. Before py3’s asyncio, there was eventlet and gevent. Very similar principles.
- You basically have a route that’s decorated slightly different than a REST route, and it keeps a websocket connected to the client. Every time a new message appears, it will perform the logic in that route. Example: flask-socketio. Just @socketio instead of @app.route.
- You can also go low-level yourself and define an explicit `async def my_coroutine` with `await websocket.recv()`. The websockets module comes with a very basic server that can persist the connection. https://websockets.readthedocs.io/en/stable/intro.html.
- No matter what, this manifests itself eventually as a data structure in python. Think of it like a list, in memory, that an async service is continually appending to under the hood. Do whatever you want with it, it’s just a regular old list to your python app.
- Capsaicin is spread by birds. You might think seeds from chili plants don’t get spread around by animal scat because they don’t want to eat them, and you’d be right; with the exception of birds, who don’t have teeth and just swallow the seeds.
- Watched Shimmer Lake. Dwight!
- Worked again with javier, jack, and tara for the next rounds.
- Scheduled google for friday.
- More general prep. Checked linked profiles of Monday’s Amazon interviews. Watched about 10 system design videos, each ~30min.
- Lots from this channel for system design: https://www.youtube.com/channel/UCn1XnDWhsLS5URXTi5wtFTA.
- Locks.
- Even if the transaction isn’t a single db statement (like a deposit) but has multiple steps (like a transfer), you can still lock. A transfer is a withdrawal + deposit + commission, for example. If ANY of those 3 steps fails, have it undo the whole chain.
- You can queue transactions such that if A has a lock while B tries, B will try again in a few seconds when the lock is freed. This is called retry logic. You can write it with TRY statements in SQL!
- The full queue of transactions to write is called a write-ahead log. Like a task manager built into the database.
- Most locks will only lock the scope that’s being changed (only that row). Some locks will disable write but allow read during the change. Some locks will disable both.
- Pessimistic lock = the standard one you’re thinking of. Lock a row, change some data, release the lock. The safest way. Better for joint sets of data, many conflicts.
- Optimistic lock = check the timestamp / version / hash at the start of the transaction, and then again when you’re ready to write back. Only write back if they’re the some. It’s less restrictive, and allows multiple people to read, but it basically favors fasters changes. Slow changes get clogged. Better for disjoint sets of data, few conflicts.
- Locks can be distributed, just like the databases themselves. You can have a cluster of redis nodes (direct duplicates for backup), each storing the mutexes for writes to the primary cluster. microservicenodes -> lockmanager -> caches, just like client -> loadbalancer -> microservicenodes.
- Locks have timeouts to ensure some dead node doesn’t halt the system.
- Put timeouts on everything! Responses, db locks, everything.
- A single char usually takes up 1 byte, so a string of len 4 is the same as an int for a 32bit system. A full sentence, maybe 100bytes. A paragraph, maybe ~1KB. A large doc, maybe 1MB. Compression helps too.
- CAP = consistency availability and partition tolerance.
- P is how the system reacts when nodes can’t talk to each other. Examples: two shards drop a connection, master fails the replication to the slave….
- The whole point is that in the presence of partitions (distributed systems), you can only choose one of (consistency, availability).
- Master-slave is AP. You might have inconsistency, where a write replication might take longer than the next read.
- Many equal nodes is CP. They might handle different tables (vertical partitioning), but they back each other up. This is a distributed datastore. Banking. REST. Locks on everything.
- Cassandra has something called “replication factor” which is how many other nodes to split the backup of a node on.
- Distributed transactions.
- Have the microservice itself (or a separate orchestrator/coordinator) keep a record of all planned queries/writes in the chain of the request. It needs to regard all of them as a single transaction. If any of the individual reads/writes to various other dbs fails, it needs to rollback the entire thing. You might hear this called “3-phase-commit” (can commit, precommit, do commit).
- Hash tables under the hood. You might think the keys are just assigned to registers, 0-2^32 or something. Then you hash the input and simply lookup by key. This would work, but if anything changed (like the # of total memory locations), you’d have to remap your table to the new modulo.
- Instead, just make the keys random numbers. Then during lookup, pick the first key that’s greater than your hash output. If you reach the end, just take the first element. Then, since you’re finding the closest neighbor instead of the exact key, it’s robust to remapping.
- While 50k requests/sec to a website is very large, to be considered “very large” in the world of queries/sec you must go even higher. Large apps are over 1 million queries/sec.
- Caches.
- A global cache can be as big as terabytes for large websites.
- Cache latency should be <10ms.
- LRU is a very common cache eviction policy.
- Under the hood, a cache is just a message queue with an event loop that has a threadpool at its disposal (and access to ram).
- Fault tolerance in a cache is usually just regular snapshots to disk.
- Since caches are typically event-driven, you can also take the logs and just replay all the actions.