Blog / September 2015
-
23 September 2015Database maintenance
The website was unavailable for ~15 mins today. I realized it's been a while since run the optimize functions on the database. It seems to have helped... though not by much.
The cache of the shared stories list is a good improvement, however it only saves one relatively expensive query. There is another similar query for the "Recent Stories" that is not cached yet, and I suspect this one also causes a lot of slow down.
I'm going to investigate the design of the database. I've never studied MySQL thoroughly since my main interest in web development is the front end side (Javascript, Css, etc). However I need to catch up on optimization techniques because the stories table is nearly one gigabyte and it keeps growing. Something is not quite right with the way I've designed the table, or the indexes.
-
21 September 2015Just how effective is the Shared Stories cache?
Today I implemented a simple log for the cache and a corresponding report in the "administration" panel for the website. As you can see the Study page caching, which was meant to improve the page loading time, hasn't been very effective so far:
That's because the cache only lasted an hour, and with visits spread across thousands of kanji pages, the cache typically wouldn't last long enough for another visitor to benefit from it.
I've now set the cache of the shared stories list to 12 hours, and the effectiveness is closer to 30% as of writing. Now I have real numbers, and hopefully we will see at least every second request to the Study page to benefit from the cache.It's a good thing I finally looked into this because the queries for the Shared Stories list have become rather slow. I've seen response times as high as three seconds and typically from one to two seconds... which is actually really bad. I'm not at all an expert in database design... my hunch is that because the stories take several hundred megabytes.. the queries now have to span across a lot of storage and have become slower and slower over time.
The cache will buy me some time to think about better solutions. At some point I'm going to have to think about what to do with all those private stories. One solution to trim the database that I have considered, is to move private stories for very old and unused accounts to a second database. Since the "backup" database will be essentially dormant it should have no impact on performance. Then, if a user tries to sign in an "expired" account, they could export their data from the second database, and/or the account could be restored transparently without the user knowing anything. -
18 September 2015Small fixes following yesterday's update
The timezone setting for the server was set incorrectly, so that due cards and "reviewed today" count would not update at the usual time. This is now fixed. Remember to restore your timezone setting in the Account page if you tweaked it yesterday. Thanks for faneca and Daniel for the report!
Update : three minor fixes:
- Fixed broken /sightreading URL
- Fixed broken article link in Manage page to the RTK Supplement news update
- Fixed error when clearing the learned kanji list ("Clear" in Study sidebar)
-
17 September 2015Today's update : Optimizing the Study page
The website has been updated today with changes that should improve the loading times of the Study pages.
The Shared Stories list on the study pages is now cached. I have set the "lifetime" of cached stories initially as low as one hour. So eg. if you share a new story, or upvote someone else's story, it may take up to an hour to be reflected in the page. Update: it may take several hours, up to a day to notice a difference because the cache is very conservative atm (probably too much) .
This is obviously a usability problem. How do you signal to users that the content is not immediately updated, but will be eventually? It's not ideal, but I think the tradeoff is worth it. It's not critical for votes, reports, and shared stories to be reflected in real time on the website, and this saves a lot of unnecessary queries on the database.
I will keep an eye on just how many pages are cached, based on the user activity, and then increase gradually the effect of the cache until it provides a significant speed improvement. In theory, updating the Shared Stories list even just once a day should provide more significant gains. But I wanted to think about how that is going to work usability wise so I will finetune it over time.
Since the website has been entirely upgraded to a more complete framework, there may be a few bugs that slipped through my tests. These should be very easy to fix. If you find an issue please let me know and I will fix it asap.
-
15 September 2015Kanji Ryokucha : an Android client for the Kanji Koohii SRS
Last month I worked with member porukkusu on a simple API that lets a third party application connect with a Kanji Koohii user's account. The Android application, called Kanji Ryokusha is now available on slideme.org!
The app lets you complete SRS reviews on your mobile device. The key feature of the app is that you can write the kanji on your touch enabled device, before flipping the flashcard and comparing your answer with the correct one.
If you use the Kanji Koohii reviewing system and own an Android device, give it a go, and be sure to give some feedback to porrukusu in this thread!
A few points I need to mention:
I struggled implementing OAuth last month, partly because I was just so tired and I couldn't find any straightforward solution in the form of a library that handles OAuth completely from the server side. For this reason although there is a simple API working on the website for the SRS reviews, it is not made public yet. However if you have an interest in it, just get in touch as more developers can help me design it better.
Without OAuth we decided to go ahead with a simple sign in through the website's own sign in page. In programming terms I believe this is "good enough" for the time being. Hopefully in the future I can improve the API authentication, and at that point I will make it public. The downside to this is that the app needs your username and password to login.
In terms of privacy: the API currently only gives access to your flashcards (read/write) and custom keywords (read only). Your email is not shared with the app. If you decide to stop using the app you can always update your password if you'd like to be 100% sure it is no longer accessible through the third party app. -
13 September 2015Improving the responsiveness of the site
Wow.. I am done refactoring the website to the symfony framework! I'm actually surprised how easy it has been and wish I had done it sooner. I started September 3rd, and I have now converted all the pages, the build scripts, the deployment script. Everything seems to work fine. It took ~11 days and a little under 30 hours total, which is pretty impressive.
So this is an interesting experience. Years ago when I wanted to make my own "lightweight" MVC to learn more about php and web development... I knew refactoring was a big pain. And so I made a fortuitous decision to use a well designed API as a guide instead of trying to make my own from scratch. It was a great learning experience. I basically implemented all the basic MVC components from symfony such as Request, Response, Context, and so on. I left out everything I didn't need or I didn't understand. I also included classes from symfony as is where that made sense, for example the routing system, which didn't make sense for me to try to simplify. I was basically taking a grand tour through an MVC, and through symfony's code I was learning about all kinds of php functions and programming tricks.
Since I followed a well designed framework's conventions, the "actions" and "views" where much of the magic happens required practically no changes. I use a Zend_Db like API for the database, and a bunch of other custom classes so I had to create a bridge between my classes and those of symfony, but for the most part it's pretty clean and makes sense to me. Though the website is not entirely written in the symfony "style", there is no overhead. Either my classes, or symfony's classes are used depending on the type of functionality. For example I have a simpler version of the "sfView" class which I use for rendering many widgets such as the ajax tables.
So this is great. I now I have access to a much more complete framework, and in particular powerful caching capabilities. In the coming week I am going to explore those caching features and try to speed up the Study pages as much as I can.
-
7 September 2015Plans, plans... what plans?
One thing that often puts me off writing updates is that I'll just stare at the screen and draw a blank. Come to think of it, it is closely related with the absence of planning and clarity as to what I'm working on.
First, I planned some changes to the SRS described earlier. Then came surgery for my deviated septum (difficulty breathing through the nose) and lost track of my goal as my sleep quality has only slightly improved since. I now breathe more consistently but the air flow is only 50% of what I consider comfortable so I'm still breathing through the mouth and I never really know how I'll feel when I wake up. Heck I just had two days of decent sleep in a row which is almost a blessing. I'm told it can take months for this surgery to show its final results.
Someone got in touch about creating an Android app that connects to the site. Since I put off making an API for so long, I thought I'd finally get down to it. We have a very simple API working, and you may hear soon about an Android app that allows to do SRS reviews synced with your Kanji Koohii account. Unfortunately since I was struggling with my sleep and overall energy... I just couldn't wrap my mind around all the abstraction in OAuth and the API doesn't have a proper authentication for the consumer (the app, not the user). I couldn't come up with a simple alternative myself either. Currently the app takes your Kanji Koohii login credentials. It's not ideal since in theory the app author can store those credentials and mess with your account. But then again there is always some level of trust required when using an app that handles your data. Many apps do this (take your login and password), and all things considered.. nothing too nefarious will happen with a Kanji Koohii account. When you login, your email is not shared by the API. The API currently only deals with the SRS status and flashcards. So private stories aren't a concern either. However if I want to make the API available for general consumption, and expand it I will have to implement OAuth or something similar.
While working on this I also realized the website's MVC (Model-View-Controller) framework is really out of date. Incredibly.. the site has been running on a very trimmed down version of symfony 1.2 for the past ten years. Symfony is actually a great framework, but I have been using a hacked version of my own rather than the full framework. It was a great experience for learning php: I used the symfony API as a tutorial, sort of, and implemented all the core MVC components by copying much of the code, leaving out a lot of complexity. Thus, I was learning both php and MVC from the inside out. The reasoning was that at some later date, if I wanted to I could refactor the site with the full framework since the API is relatively similar. So now I am finally doing this.
This is the kind of updates that frustrating to work on because I have nothing to show. However I think it will be well worth it because I've noticed at certain times of day the website can become slow, and this change will finally bring some much needed caching. I think the Study section is the most expensive on the server side. It includes a handful of queries per page. Caching of course is complicated on a site like this since a lot of the presentation is dynamic content, meaning every user sees different things. I think the shared stories list is a great candidate for caching, since that list is more or less static for each kanji, and it's not critical for the the votes/reports to be updated in realtime. So I am excited to see how this will improve the responsiveness of the site.
Upgrading the framework also could help me with the API. I may be able to plug in OAuth support from an already made library for symfony.
Finally, I will have a proper internationalization and localization support with I18N. I have no idea what that thing is, but hey.. it means the likelyhood of translating the site to other languages will be much more feasible. It's just one of those things that I never added to my "trimmed down" version of the MVC framework.
By Month
- Oct 2024 (1)
- Sep 2024 (1)
- Jun 2024 (2)
- May 2024 (4)
- Apr 2024 (3)
- Mar 2024 (1)
- Feb 2024 (1)
- Dec 2023 (1)
- Nov 2023 (2)
- Oct 2023 (2)
- Apr 2023 (2)
- Mar 2023 (2)
- Feb 2023 (1)
- Jan 2023 (2)
- Dec 2022 (1)
- Nov 2022 (2)
- Oct 2022 (3)
- Sep 2022 (1)
- May 2022 (4)
- Apr 2022 (1)
- Feb 2022 (2)
- Jan 2022 (2)
- Dec 2021 (4)
- Nov 2021 (2)
- Oct 2021 (2)
- Sep 2021 (2)
- Aug 2021 (1)
- Apr 2021 (2)
- Feb 2021 (3)
- Jan 2021 (3)
- Dec 2020 (1)
- Nov 2020 (1)
- May 2020 (1)
- Apr 2020 (1)
- Jan 2020 (1)
- Oct 2019 (1)
- Sep 2019 (1)
- Aug 2019 (4)
- Jul 2019 (3)
- Jun 2019 (1)
- May 2019 (1)
- Mar 2019 (2)
- Jan 2019 (1)
- Nov 2018 (3)
- Oct 2018 (8)
- Sep 2018 (4)
- Aug 2018 (3)
- Jul 2018 (1)
- Jun 2018 (4)
- May 2018 (1)
- Apr 2018 (1)
- Mar 2018 (1)
- Jan 2018 (1)
- Dec 2017 (6)
- Nov 2017 (4)
- Oct 2017 (4)
- Sep 2017 (5)
- Aug 2017 (5)
- Jun 2017 (3)
- May 2017 (2)
- Apr 2017 (3)
- Mar 2017 (7)
- Feb 2017 (10)
- Jan 2017 (11)
- Dec 2016 (6)
- Nov 2016 (5)
- Oct 2016 (6)
- Sep 2016 (7)
- Aug 2016 (3)
- May 2016 (1)
- Mar 2016 (2)
- Jan 2016 (1)
- Dec 2015 (3)
- Nov 2015 (1)
- Oct 2015 (1)
- Sep 2015 (7)
- Jul 2015 (2)
- Jun 2015 (1)
- May 2015 (5)
- Apr 2015 (4)
- Mar 2015 (5)
- Feb 2015 (4)
- Jan 2015 (5)
- Dec 2014 (4)
- Nov 2014 (3)
- Oct 2014 (2)
- Jun 2014 (1)
- Apr 2014 (2)
- Mar 2014 (4)
- Feb 2014 (3)
- Jan 2014 (4)
- Dec 2013 (2)
- Oct 2013 (1)
- Sep 2013 (1)
- Jun 2013 (4)
- May 2013 (1)
- Mar 2013 (1)
- Jan 2013 (2)
- Oct 2012 (2)
- Aug 2012 (1)
- Jul 2012 (2)
- Jun 2012 (2)
- May 2012 (1)
- Mar 2012 (2)
- May 2011 (1)
- Apr 2011 (4)
- Mar 2011 (3)
- Feb 2011 (2)
- Jan 2011 (2)
- Dec 2010 (8)
- Nov 2010 (8)
- Oct 2010 (3)
- Sep 2010 (3)
- Aug 2010 (1)
- Jul 2010 (2)
- Jun 2010 (5)
- May 2010 (1)
- Apr 2010 (3)
- Mar 2010 (4)
- Feb 2010 (2)
- Jan 2010 (1)
- Dec 2009 (5)
- Nov 2009 (5)
- Oct 2009 (1)
- Aug 2009 (1)
- May 2009 (5)
- Apr 2009 (2)
- Mar 2009 (1)
- Feb 2009 (2)
- Jan 2009 (2)
- Nov 2008 (1)
- Oct 2008 (1)
- Sep 2008 (1)
- May 2008 (2)
- Apr 2008 (1)
- Feb 2008 (6)
- Jan 2008 (5)
- Dec 2007 (6)
- Oct 2007 (1)
- Sep 2007 (2)
- Aug 2007 (3)
- Jun 2007 (1)
- May 2007 (5)
- Apr 2007 (1)
- Mar 2007 (2)
- Feb 2007 (1)
- Jan 2007 (4)
- Dec 2006 (3)
- Aug 2006 (1)
- Jun 2006 (3)
- Apr 2006 (6)
- Mar 2006 (8)
- Feb 2006 (1)
- Jan 2006 (4)
- Nov 2005 (1)
- Oct 2005 (4)
- Sep 2005 (1)
- Aug 2005 (11)